コード例 #1
0
ファイル: datawidgets.py プロジェクト: luelista/pre_workbench
class ByteBufferWidget(QWidget):
    on_data_selected = pyqtSignal(QObject)

    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        #toolbar = QToolBar()
        #self.splitIntoPacketsAction = toolbar.addAction("Split into packets")
        #self.splitIntoPacketsAction.triggered.connect(self.splitIntoPackets)

        layout = QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)
        self.setLayout(layout)

        self.tabWidget = QTabWidget()
        self.tabWidget.setContentsMargins(0, 0, 0, 0)
        self.tabWidget.setDocumentMode(True)
        layout.addWidget(self.tabWidget)
        self.textbox = HexView2()
        self.textbox.on_data_selected.connect(self.on_data_selected.emit)
        self.textbox.onNewSubflowCategory.connect(self.newSubflowCategory)
        self.textbox.formatInfoUpdated.connect(self.onFormatInfoUpdated)
        self.tabWidget.addTab(self.textbox, "Raw buffer")
        #layout.addWidget(toolbar)

    def setContents(self, bufObj):
        self.bufferObject = bufObj
        self.setWindowTitle(str(bufObj))
        self.textbox.setBuffer(bufObj)
        self.bufferObject.on_new_data.connect(self.onNewData)

    def onFormatInfoUpdated(self):
        self.tabWidget.clear()
        self.tabWidget.addTab(self.textbox, "Raw buffer")

    def newSubflowCategory(self, category, parse_context):
        for i in range(self.tabWidget.count()):
            if self.tabWidget.tabText(i) == category:
                break
        widget = PacketListWidget()
        widget.setContents(parse_context.subflow_categories[category])
        self.tabWidget.addTab(widget, category)
        widget.on_data_selected.connect(self.on_data_selected.emit)

    def onNewData(self):
        #self.textbox.showHex(bufObj.buffer)
        self.textbox.redraw()

    def splitIntoPackets(self):
        pass

    def run_ndis(self):
        pass
コード例 #2
0
 def _add_widgets(self):
     layout = QVBoxLayout()
     tabs = QTabWidget()
     tabs.setContentsMargins(0, 0, 0, 0)
     tabs.addTab(TabAbout(), "&About")
     tabs.addTab(TabSystem(), "&System")
     tabs.addTab(TabFiles(), "&Files")
     tabs.addTab(TabMeetings(), "&Meetings")
     tabs.addTab(TabLog(), "&Log")
     layout.addWidget(tabs)
     self.setLayout(layout)
コード例 #3
0
class SchoolManagement(QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # create widgets
        self.tabs = QTabWidget(self)
        self.students_tab = StudentsTab()
        self.classes_tab = ClassesTab()
        self.jobs_tab = JobsTab()
        self.assign_tab = AssignmentsTab()
        self.policy_tab = PolicyTab()
        self.expansions_tab = ExpansionsTab()
        self.clubs_tab = ClubsTab()
        self.accounting_tab = AccountingTab()
        self.stats_tab = StatsTab()
        self.exit_btn = QPushButton()

        # create layouts
        layout = QVBoxLayout(self)
        self.tabs.setContentsMargins(0, 0, 0, 0)
        # TODO: translate
        self.tabs.addTab(self.classes_tab, "Classes")
        self.tabs.addTab(self.students_tab, "Students")
        self.tabs.addTab(self.jobs_tab, "Jobs")
        self.tabs.addTab(self.assign_tab, "Teacher Assignments")
        self.tabs.addTab(self.policy_tab, "School Policy")
        self.tabs.addTab(self.expansions_tab, "Expansions")
        self.tabs.addTab(self.clubs_tab, "Clubs")
        self.tabs.addTab(self.accounting_tab, "Accounting")
        self.tabs.addTab(self.stats_tab, "Stats")
        layout.addWidget(self.tabs)
        layout.addWidget(self.exit_btn)

        fixedsize = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.exit_btn.setSizePolicy(fixedsize)

        # configure widgets
        self.tabs.setStyleSheet(
            "QTabWidget { background-color: rgb(25, 45, 52);}")

        # connect signals
        self.exit_btn.clicked.connect(self.parent().toggle_school_management)

        # TODO: check if top part of tab handle reacts to interaction

        self.retranslateUi()

    def retranslateUi(self):
        tra = QApplication.translate
        ctxt = "SchoolManagement"
        self.exit_btn.setText(tra(ctxt, "Exit"))
        for idx, name in enumerate(
            ("Classes", "Students", "Jobs", "Teacher Assignments",
             "School Policy", "Expansions", "Clubs", "Accounting", "Stats")):
            self.tabs.setTabText(idx, tra(ctxt, name))
コード例 #4
0
class MainWindows(QWidget):
    ## Main class 3 tabs : 12 cameras
    def __init__(self):
        super().__init__()

        self.left = 100
        self.top = 30
        self.width = 1200
        self.height = 300
        self.setGeometry(self.left, self.top, self.width, self.height)
        self.setWindowTitle('Lolita Alignment')
        self.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
        p = pathlib.Path(__file__)
        sepa = os.sep
        self.icon = str(p.parent) + sepa + 'icons' + sepa
        self.setWindowIcon(QIcon(self.icon + 'LOA.png'))

        self.setup()
        self.actionButton()

    def setup(self):

        self.layout = QVBoxLayout(self)
        self.layout.setContentsMargins(1, 1, 1, 1)
        self.setContentsMargins(1, 1, 1, 1)
        self.tabs = QTabWidget()
        self.tabs.setContentsMargins(1, 1, 1, 1)
        self.tab0 = MULTICAM(names=['cam0', 'cam1', 'cam2', 'cam3'])
        self.tab1 = MULTICAM(names=['cam6', 'cam7', 'cam4', 'cam5'])
        #        self.tab2=App4Cam()

        self.tabs.addTab(self.tab0, '   Lolita centers     ')
        self.tabs.addTab(self.tab1, '    P3 & misc.    ')
        #self.tabs.addTab(self.tab2,'    P3    ')

        self.layout.addWidget(self.tabs)
        self.setLayout(self.layout)

    def changeTab(self):
        #        print('tab change', 'tab is',self.tabs.currentIndex())
        self.tab = [self.tab0, self.tab1]
        self.tab0.stopRun()
        self.tab1.stopRun()
        #self.tab2.stopRun()

    def actionButton(self):
        self.tabs.currentChanged.connect(self.changeTab)

    def closeEvent(self, event):

        event.accept()
コード例 #5
0
class TabWindow(QMainWindow):
    def __init__(self, app, **kwargs):
        super().__init__(None, **kwargs)
        self.app = app
        self.pages = {}
        self.menubar = None
        self.menuList = set()
        self.last_index = -1
        self.previous_widget_actions = set()
        self._setupUi()
        self.app.willSavePrefs.connect(self.appWillSavePrefs)

    def _setupActions(self):
        # (name, shortcut, icon, desc, func)
        ACTIONS = [
            (
                "actionToggleTabs",
                "",
                "",
                tr("Show tab bar"),
                self.toggleTabBar,
            ),
        ]
        createActions(ACTIONS, self)
        self.actionToggleTabs.setCheckable(True)
        self.actionToggleTabs.setChecked(True)

    def _setupUi(self):
        self.setWindowTitle(self.app.NAME)
        self.resize(640, 480)
        self.tabWidget = QTabWidget()
        # self.tabWidget.setTabPosition(QTabWidget.South)
        self.tabWidget.setContentsMargins(0, 0, 0, 0)
        # self.tabWidget.setTabBarAutoHide(True)
        # This gets rid of the annoying margin around the TabWidget:
        self.tabWidget.setDocumentMode(True)

        self._setupActions()
        self._setupMenu()
        # This should be the same as self.centralWidget.setLayout(self.verticalLayout)
        self.verticalLayout = QVBoxLayout(self.tabWidget)
        # self.verticalLayout.addWidget(self.tabWidget)
        self.verticalLayout.setContentsMargins(0, 0, 0, 0)
        self.tabWidget.setTabsClosable(True)
        self.setCentralWidget(self.tabWidget)  # only for QMainWindow

        self.tabWidget.currentChanged.connect(self.updateMenuBar)
        self.tabWidget.tabCloseRequested.connect(self.onTabCloseRequested)
        self.updateMenuBar(self.tabWidget.currentIndex())
        self.restoreGeometry()

    def restoreGeometry(self):
        if self.app.prefs.mainWindowRect is not None:
            self.setGeometry(self.app.prefs.mainWindowRect)
        else:
            moveToScreenCenter(self)

    def _setupMenu(self):
        """Setup the menubar boiler plates which will be filled by the underlying
        tab's widgets whenever they are instantiated."""
        self.menubar = self.menuBar(
        )  # QMainWindow, similar to just QMenuBar() here
        # self.setMenuBar(self.menubar)  # already set if QMainWindow class
        self.menubar.setGeometry(QRect(0, 0, 100, 22))
        self.menuFile = QMenu(self.menubar)
        self.menuFile.setTitle(tr("File"))
        self.menuMark = QMenu(self.menubar)
        self.menuMark.setTitle(tr("Mark"))
        self.menuActions = QMenu(self.menubar)
        self.menuActions.setTitle(tr("Actions"))
        self.menuColumns = QMenu(self.menubar)
        self.menuColumns.setTitle(tr("Columns"))
        self.menuView = QMenu(self.menubar)
        self.menuView.setTitle(tr("View"))
        self.menuHelp = QMenu(self.menubar)
        self.menuHelp.setTitle(tr("Help"))

        self.menuView.addAction(self.actionToggleTabs)
        self.menuView.addSeparator()

        self.menuList.add(self.menuFile)
        self.menuList.add(self.menuMark)
        self.menuList.add(self.menuActions)
        self.menuList.add(self.menuColumns)
        self.menuList.add(self.menuView)
        self.menuList.add(self.menuHelp)

    @pyqtSlot(int)
    def updateMenuBar(self, page_index=None):
        if page_index < 0:
            return
        current_index = self.getCurrentIndex()
        active_widget = self.getWidgetAtIndex(current_index)
        if self.last_index < 0:
            self.last_index = current_index
            self.previous_widget_actions = active_widget.specific_actions
            return

        page_type = type(active_widget).__name__
        for menu in self.menuList:
            if menu is self.menuColumns or menu is self.menuActions or menu is self.menuMark:
                if not isinstance(active_widget, ResultWindow):
                    menu.setEnabled(False)
                    continue
                else:
                    menu.setEnabled(True)
            for action in menu.actions():
                if action not in active_widget.specific_actions:
                    if action in self.previous_widget_actions:
                        action.setEnabled(False)
                    continue
                action.setEnabled(True)

        self.app.directories_dialog.actionShowResultsWindow.setEnabled(
            False if page_type ==
            "ResultWindow" else self.app.resultWindow is not None)
        self.app.actionIgnoreList.setEnabled(
            True if self.app.ignoreListDialog is not None
            and not page_type == "IgnoreListDialog" else False)
        self.app.actionDirectoriesWindow.setEnabled(
            False if page_type == "DirectoriesDialog" else True)

        self.previous_widget_actions = active_widget.specific_actions
        self.last_index = current_index

    def createPage(self, cls, **kwargs):
        app = kwargs.get("app", self.app)
        page = None
        if cls == "DirectoriesDialog":
            page = DirectoriesDialog(app)
        elif cls == "ResultWindow":
            parent = kwargs.get("parent", self)
            page = ResultWindow(parent, app)
        elif cls == "IgnoreListDialog":
            parent = kwargs.get("parent", self)
            model = kwargs.get("model")
            page = IgnoreListDialog(parent, model)
        self.pages[cls] = page
        return page

    def addTab(self, page, title, switch=False):
        # Warning: this supposedly takes ownership of the page
        index = self.tabWidget.addTab(page, title)
        # index = self.tabWidget.insertTab(-1, page, title)
        if isinstance(page, DirectoriesDialog):
            self.tabWidget.tabBar().setTabButton(index, QTabBar.RightSide,
                                                 None)
        if switch:
            self.setCurrentIndex(index)
        return index

    def showTab(self, page):
        index = self.indexOfWidget(page)
        self.setTabVisible(index, True)
        self.setCurrentIndex(index)

    def indexOfWidget(self, widget):
        return self.tabWidget.indexOf(widget)

    def setCurrentIndex(self, index):
        return self.tabWidget.setCurrentIndex(index)

    def setTabVisible(self, index, value):
        return self.tabWidget.setTabVisible(index, value)

    def removeTab(self, index):
        return self.tabWidget.removeTab(index)

    def isTabVisible(self, index):
        return self.tabWidget.isTabVisible(index)

    def getCurrentIndex(self):
        return self.tabWidget.currentIndex()

    def getWidgetAtIndex(self, index):
        return self.tabWidget.widget(index)

    def getCount(self):
        return self.tabWidget.count()

    # --- Events
    def appWillSavePrefs(self):
        # Right now this is useless since the first spawn dialog inside the
        # QTabWidget will assign its geometry after restoring it
        prefs = self.app.prefs
        prefs.mainWindowIsMaximized = self.isMaximized()
        prefs.mainWindowRect = self.geometry()

    def closeEvent(self, close_event):
        # Force closing of our tabbed widgets in reverse order so that the
        # directories dialog (which usually is at index 0) will be called last
        for index in range(self.getCount() - 1, -1, -1):
            self.getWidgetAtIndex(index).closeEvent(close_event)
        self.appWillSavePrefs()

    @pyqtSlot(int)
    def onTabCloseRequested(self, index):
        current_widget = self.getWidgetAtIndex(index)
        if isinstance(current_widget, DirectoriesDialog):
            # if we close this one, the application quits. Force user to use the
            # menu or shortcut. But this is useless if we don't have a button
            # set up to make a close request anyway. This check could be removed.
            return
        current_widget.close()
        self.setTabVisible(index, False)
        # self.tabWidget.widget(index).hide()
        self.removeTab(index)

    @pyqtSlot()
    def onDialogAccepted(self):
        """Remove tabbed dialog when Accepted/Done."""
        widget = self.sender()
        index = self.indexOfWidget(widget)
        if index > -1:
            self.removeTab(index)

    @pyqtSlot()
    def toggleTabBar(self):
        value = self.sender().isChecked()
        self.actionToggleTabs.setChecked(value)
        self.tabWidget.tabBar().setVisible(value)
コード例 #6
0
class MainWindows(QWidget):
    ## Main class 4 tabs :  cameras
    def __init__(self):
        super().__init__()

        self.left = 100
        self.top = 30
        self.width = 1400
        self.height = 1700
        self.setGeometry(self.left, self.top, self.width, self.height)
        self.setWindowTitle('Lolita Cameras')
        self.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
        p = pathlib.Path(__file__)
        sepa = os.sep
        self.icon = str(p.parent) + sepa + 'icons' + sepa
        self.setWindowIcon(QIcon(self.icon + 'LOA.png'))

        self.setup()
        self.actionButton()

    def setup(self):

        self.layout = QVBoxLayout(self)
        self.layout.setContentsMargins(1, 1, 1, 1)
        self.setContentsMargins(1, 1, 1, 1)
        self.tabs = QTabWidget()
        self.tabs.setContentsMargins(1, 1, 1, 1)
        pathVisu = 'C:/Users/loa/Desktop/Python/camera/confCamera.ini'
        self.tab0 = CameraMotorLoop.CAMERAMOTOR(cam="cam2",
                                                fft='off',
                                                meas='on',
                                                affLight=False,
                                                aff='left',
                                                separate=False,
                                                multi=False,
                                                confpath=pathVisu,
                                                loop=True)
        self.tab1 = camera2.CAMERA(cam="cam3",
                                   fft='off',
                                   meas='on',
                                   affLight=False,
                                   aff='left',
                                   separate=False,
                                   multi=False,
                                   confpath=pathVisu)
        self.tab2 = camera2.CAMERA(cam="cam1",
                                   fft='off',
                                   meas='on',
                                   affLight=False,
                                   aff='left',
                                   separate=False,
                                   multi=False,
                                   confpath=pathVisu)
        self.tab3 = camera2.CAMERA(cam='cam4',
                                   fft='off',
                                   meas='on',
                                   affLight=False,
                                   aff='left',
                                   separate=False,
                                   multi=False,
                                   confpath=pathVisu)
        self.tab4 = CameraMotorLoop.CAMERAMOTOR(cam='cam5',
                                                fft='off',
                                                meas='on',
                                                affLight=False,
                                                aff='left',
                                                separate=False,
                                                multi=False,
                                                confpath=pathVisu,
                                                loop=True)
        #        self.tab2=App4Cam()

        self.tabs.addTab(self.tab0, self.tab0.ccdName)
        self.tabs.addTab(self.tab1, self.tab1.ccdName)
        self.tabs.addTab(self.tab2, self.tab2.ccdName)
        self.tabs.addTab(self.tab3, self.tab3.ccdName)
        self.tabs.addTab(self.tab4, self.tab4.ccdName)
        #self.tabs.addTab(self.tab2,'    P3    ')

        self.layout.addWidget(self.tabs)
        self.setLayout(self.layout)

    def changeTab(self):
        print('tab change', 'tab is', self.tabs.currentIndex())
        # self.tab=[self.tab0,self.tab1]
        # self.tab0.stopRun()
        # self.tab1.stopRun()
        #self.tab2.stopRun()

    def actionButton(self):
        self.tabs.currentChanged.connect(self.changeTab)

    def closeEvent(self, event):
        # exit
        event.accept()
コード例 #7
0
ファイル: main.py プロジェクト: lukoou3/MusicPlayer
class Main(QFrame):
    def __init__(self, parent=None):
        """"""
        super().__init__()

        self.setObjectName('Main')
        self.parent = parent

    def initUI(self):
        self.setWindowFlags(Qt.FramelessWindowHint)  # 隐藏边框

        self.mainLayout = QVBoxLayout(self)
        # self.mainLayout.setSpacing(0)

        self.header = Header(self)
        self.mainLayout.addWidget(self.header, 20)

        self.contentLayout = QHBoxLayout()
        self.contentLayout.setContentsMargins(0, 0, 0, 0)
        self.contentLayout.setSpacing(0)
        self.navigation = Navigation(self)
        self.contentLayout.addWidget(self.navigation)
        self.contents = QTabWidget()
        self.contents.setContentsMargins(0, 0, 0, 0)
        self.contents.tabBar().hide()
        self.recommendMusic = RecommendMusic(self)
        self.musicDetailNetEase = RecommendMusicDetailNetEase(self)
        self.musicDetailQQ = RecommendMusicDetailQQ(self)
        self.searchMusic = SearchMusic(self)
        self.contents.addTab(self.recommendMusic, "")
        self.contents.addTab(self.musicDetailNetEase, "")
        self.contents.addTab(self.musicDetailQQ, "")
        self.contents.addTab(self.searchMusic, "")
        self.content = self.recommendMusic
        self.contents.setCurrentWidget(self.content)
        self.contentLayout.addWidget(self.contents)
        self.mainLayout.addLayout(self.contentLayout, 400)

        self.player = Player(self)
        self.mainLayout.addWidget(self.player, 20)

        self.registerSignalConnect()

    def registerSignalConnect(self):
        # 注册最小化事件
        self.header.minButton.clicked.connect(self.showMinimized)
        # 注册最大化事件
        self.header.maxButton.clicked.connect(self.showMaxiOrRevert)
        #注册关闭事件
        self.header.closeButton.clicked.connect(self.close)
        # 注册导航栏事件
        self.navigation.recommendList.currentRowChanged.connect(
            self.navigationRecommendChanged)
        self.navigation.recommendList.itemPressed.connect(
            self.navigationRecommendItemClick)
        self.navigation.myMusicList.currentRowChanged.connect(
            self.navigationmyMusicChanged)

        self.header.searchLineEdit.searchSignal.connect(self.showSearchMusic)

    def showMaxiOrRevert(self):
        if self.isMaximized():
            self.showNormal()
        else:
            self.showMaximized()

    def navigationRecommendChanged(self, index):
        #print(index)
        self.navigation.myMusicList.setCurrentRow(-1)

        self.changeContentWidget(self.recommendMusic)

    def navigationRecommendItemClick(self, widgetItem):
        pass
        print(self.navigation.recommendList.currentRow())
        #print(widgetItem)

    def navigationmyMusicChanged(self, index):
        self.navigation.recommendList.setCurrentRow(-1)

    def changeContentWidget(self, content):
        #self.contentLayout.replaceWidget(self.content, content)
        #sip.delete(self.content)
        #del self.content
        self.content = content
        self.contents.setCurrentWidget(self.content)

    def showSearchMusic(self, text):
        text = text.strip()
        if text:
            self.changeContentWidget(self.searchMusic)
            self.searchMusic.search(text)
コード例 #8
0
class MainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.create_flags()
        self.create_backend()
        self.create_shortcuts()
        self.build_ui()
        self.window_setup()
        self.build_dialogs()
        self.load_folder()
        self.show_window()

    # main app creators
    def create_main_components(self):
        # main window
        self.window = QFrame()
        self.layout = QVBoxLayout()

        # external windows
        self.folderSwitch = None

    def create_context(self):
        self.context = Context()
        self.context.load()

    def create_shortcuts(self):
        self.shortcutSave = QShortcut(QKeySequence("Ctrl+S"), self)
        self.shortcutInfo = QShortcut(QKeySequence("F1"), self)
        self.shortcutMain = QShortcut(QKeySequence("F2"), self)
        self.shortcutSide = QShortcut(QKeySequence("F3"), self)
        self.shortcutTasks = QShortcut(QKeySequence("F4"), self)
        self.shortcutSwitch = QShortcut(QKeySequence("F5"), self)
        self.shortcutTheme = QShortcut(QKeySequence("F7"), self)
        self.shortcutMode = QShortcut(QKeySequence("F8"), self)
        self.shortcutSetup = QShortcut(QKeySequence("F9"), self)
        self.shortcutExit = QShortcut(QKeySequence("F10"), self)
        self.shortcutFullscreen = QShortcut(QKeySequence("F11"), self)
        self.shortcutHide = QShortcut(QKeySequence("Esc"), self)
        self.bind_shortcuts()

    def create_flags(self):
        # logic
        self.wasMaximized = False

    def create_backend(self):
        self.notes = Notes()  ## do remove
        self.version = VersionInfo()  ## to context
        self.stylist = Stylist()
        self.directory = Directory()
        self.timer = Timer(self)

    def create_side_components(self):
        self.sidenote = SideNotes(self)

    def create_notepad_components(self):
        self.notepad = Notepad(self)

    def create_todolist_components(self):
        self.todolist = ToDoList(self, Component.ToDoList)

    def create_status_bar(self):
        self.status_bar = StatusBar(self, Component.StatusBar)

    def build_ui(self):
        self.create_context()
        self.create_main_components()
        self.create_notepad_components()
        self.create_side_components()
        self.create_todolist_components()
        self.create_status_bar()

        desktop = QWidget()
        desktop_container = QHBoxLayout()

        self.side_tabs = QTabWidget()
        self.side_tabs.addTab(self.sidenote, "Notes")
        self.side_tabs.addTab(self.todolist, "Tasks")
        self.side_tabs.setFixedWidth(300)

        desktop_container.addWidget(self.notepad)  # separate class
        desktop_container.addWidget(self.side_tabs)
        desktop.setLayout(desktop_container)

        desktop.setContentsMargins(0, 0, 0, 0)
        self.side_tabs.setContentsMargins(0, 0, 0, 0)
        self.layout.setContentsMargins(0, 0, 0, 0)
        desktop_container.setContentsMargins(0, 0, 0, 0)
        desktop_container.setSpacing(0)

        self.layout.addWidget(desktop)
        self.layout.addWidget(self.status_bar)

        self.window.setLayout(self.layout)
        self.setCentralWidget(self.window)

    # shortcuts actions
    def bind_shortcuts(self):
        self.shortcutSave.activated.connect(self.action_save)
        self.shortcutFullscreen.activated.connect(
            self.action_toggle_fullscreen)
        self.shortcutExit.activated.connect(self.action_terminate)

        self.shortcutMain.activated.connect(self.action_focus_notepad)
        self.shortcutSide.activated.connect(self.action_focus_sidenote)
        self.shortcutTasks.activated.connect(self.action_focus_tasks)

        self.shortcutSwitch.activated.connect(self.action_toggle_folder_switch)
        self.shortcutInfo.activated.connect(self.action_toggle_info_window)
        self.shortcutSetup.activated.connect(
            self.action_toggle_settings_window)
        self.shortcutHide.activated.connect(self.action_hide_dialog)

        self.shortcutTheme.activated.connect(self.action_switch_editor_theme)
        self.shortcutMode.activated.connect(self.action_switch_editor_mode)

    def action_save(self):
        saved = False
        saved = saved or self.notepad.save(self.context.source_folder)
        saved = saved or self.sidenote.save(self.context.source_folder)
        saved = saved or self.todolist.save(self.context.source_folder)

        if saved:
            self.status_bar.publish("Saved!")
            self.timer.setup()

    def action_toggle_fullscreen(self):
        if self.isFullScreen():
            if self.wasMaximized:
                self.showNormal()
                self.showMaximized()
            else:
                self.showNormal()
        else:
            self.wasMaximized = self.isMaximized()
            self.showFullScreen()

    def action_terminate(self):
        self.save_window_position()
        self.action_save()
        self.close()

    def action_focus_notepad(self):
        self.notepad.focus()

    def action_focus_sidenote(self):
        self.side_tabs.setCurrentIndex(0)
        self.sidenote.focus()

    def action_focus_tasks(self):
        self.side_tabs.setCurrentIndex(1)
        self.todolist.focus()

    def action_toggle_folder_switch(self):
        if self.folderSwitch.isVisible():
            self.folderSwitch.hide()
        else:
            self.folderSwitch.show()

    def action_toggle_info_window(self):
        self.dialog.show_dialog(ActivePanel.Info)

    def action_toggle_settings_window(self):
        self.dialog.setup(self.context)
        self.dialog.show_dialog(ActivePanel.Options)

    def action_hide_dialog(self):
        self.dialog.hide_dialog()

    def action_switch_editor_theme(self):
        if self.context.color_theme == EditorTheme.Dark:
            self.context.color_theme = EditorTheme.Light
        else:
            self.context.color_theme = EditorTheme.Dark
        self.set_editor_theme()

    def action_switch_editor_mode(self):
        if self.context.editor_mode == EditorMode.Focus:
            self.context.editor_mode = EditorMode.Normal
        else:
            self.context.editor_mode = EditorMode.Focus
        self.set_editor_mode()

    # dialogs
    def build_dialogs(self):
        self.dialogWidget = QWidget(self)
        self.dialog = Dialog(self.dialogWidget)
        self.dialog.hide()

        self.build_folder_switch_dialog()

    def build_folder_switch_dialog(self):
        self.folderSwitch = QWidget(self)
        switch = FolderSwitch(self.folderSwitch)
        self.resizeEvent(None)

    # main window settings
    def window_setup(self):
        self.setMinimumSize(800, 600)
        self.setWindowTitle(self.version.app_name())

        self.set_icon()
        self.set_geometry()
        self.update_params()

    def update_params(self):
        self.set_editor_font()
        self.set_editor_theme()
        self.set_editor_mode()

    def set_editor_font(self):
        self.notepad.setup(self.context.text_size)
        self.sidenote.setup(self.context.text_size)

    def set_editor_theme(self):
        self.setStyleSheet(
            self.stylist.get_style_sheet(self.context.color_theme))

    def set_editor_mode(self):
        self.notepad.setup_mode(self.context)

    def set_icon(self):
        self.setWindowIcon(
            QtGui.QIcon(self.directory.get_resource_dir() + 'icon.png'))

    def set_geometry(self):
        if self.context.window_left < 0 or self.context.window_top < 0:

            screen = QDesktopWidget().screenGeometry(-1)
            self.context.window_width = int(screen.width() / 3) * 2
            self.context.window_height = int(screen.height() / 3) * 2
            if self.context.window_width < 800:
                self.context.window_width = 800
            if self.context.window_height < 600:
                self.context.window_height = 600
            self.setGeometry(0, 0, self.context.window_width,
                             self.context.window_height)
            self.center_window()
        else:
            if self.context.window_width < 800:
                self.context.window_width = 800
            if self.context.window_height < 600:
                self.context.window_height = 600
            self.setGeometry(self.context.window_left, self.context.window_top,
                             self.context.window_width,
                             self.context.window_height)
            self.move(self.context.window_left, self.context.window_top)

    def center_window(self):
        geometry = self.frameGeometry()
        screen = QApplication.desktop().screenNumber(
            QApplication.desktop().cursor().pos())
        centerPoint = QApplication.desktop().screenGeometry(screen).center()
        geometry.moveCenter(centerPoint)
        self.move(geometry.topLeft())

    def show_window(self):
        if self.context.window_maximized == 1:
            self.showMaximized()
        else:
            self.showNormal()

    #
    def load_folder(self, folder=0):
        if folder != 0:
            self.context.source_folder = folder

        if self.context.is_source_local:
            self.notepad.load(self.context.source_folder)
            self.sidenote.load(self.context.source_folder)
            self.todolist.load(self.context.source_folder)

    def clear_status(self):
        self.status_bar.clear()

    def save_window_params(self):
        if self.isMaximized():
            self.context.window_maximized = True
        else:
            self.context.window_maximized = False
            geometry = self.geometry()
            pos = self.pos()
            self.context.window_left = pos.x()
            self.context.window_top = pos.y()
            self.context.window_width = geometry.width()
            self.context.window_height = geometry.height()

    # events
    def resizeEvent(self, event):
        self.notepad.refresh()
        if not (self.folderSwitch is None):
            self.resize_folder_switch()

        self.dialog.resize()

    def closeEvent(self, event):
        self.save_window_params()
        self.context.store()
        self.action_save()
        event.accept()

    ## dragons below

    # switch folder {

    def resize_folder_switch(self):
        maxw = 700
        maxh = 500

        left_shift = int((self.width() - maxw) / 2)
        top_shift = int((self.height() - maxh) / 2)

        self.folderSwitch.setGeometry(left_shift, top_shift, maxw, maxh)
コード例 #9
0
ファイル: central_widget.py プロジェクト: adoregnu/scrapper
class CentralWidget(QWidget):
    crawledMovieInfo = None

    def __init__(self, config):
        super().__init__()

        self.globalConfig = config
        if not 'FolderView' in config.sections():
            config.add_section('y')

        self.scrapperConfig = self.globalConfig['Scrapper']
        mainLayout = QHBoxLayout()
        mainLayout.setContentsMargins(3, 3, 3, 3)

        self.fileView = FolderView(config)
        self.fileView.movieFound.connect(self.onFoundMovie)
        mainLayout.addWidget(self.fileView)

        self.movieTab = QTabWidget()
        self.movieTab.setContentsMargins(0, 0, 0, 0)
        self.listView = MovieListView(config, self.fileView.model, parent=self)
        self.listView.movieDoubleClicked.connect(self.onMovieClicked)
        self.movieTab.addTab(self.listView, 'List')

        self.infoView = MovieInfoView()
        self.movieTab.addTab(self.infoView, 'Detail')
        
        mainLayout.addWidget(self.movieTab)
        self.setLayout(mainLayout)

        self.initCrawlRunner()

    def initCrawlRunner(self):
        from scrapy.crawler import CrawlerRunner
        from scrapy.utils.log import configure_logging
        from scrapy.utils.project import get_project_settings
        configure_logging()
        self.runner = CrawlerRunner(get_project_settings())
        self.crawler = None
        self.site = None
        self.numCids = 0

    '''
    def onMovieDoubleClicked(self, index):
        self.movieTab.setCurrentWidget(self.infoView)
        self.fileView.setCurrentIndex(index)
    '''

    def onMovieClicked(self, index, doubleClicked):
        if doubleClicked:
            self.movieTab.setCurrentWidget(self.infoView)
        self.fileView.setCurrentIndex(index)

    def updateFromFile(self, files, index = None):
        self.infoView.clearMovieInfo(True, self.numCids > 1)
        if not files: return

        #print(files)
        nfo = next(filter(lambda x:x.endswith('.nfo'), files), False)
        if not nfo:
            return

        info = utils.nfo2dict(nfo)
        if index:
            info['path'] = self.fileView.getPath(index) 
        else:
            info['path'] = self.fileView.getPath() 

        for file in files:
            if file.endswith('.nfo'): continue
            if '-poster' in file:
                info['poster'] = utils.AvImage(file)
            elif '-fanart' in file:
                info['fanart'] = file
        #print('file set movie info')
        #print(info)
        self.infoView.setMovieInfo(info, self.numCids > 1)

    def checkCrop(self, info):
        donotcrop = []
        if 'VR' in info['id'] : return False
        if self.scrapperConfig.get('studios_skipping_crop'):
            donotcrop = self.scrapperConfig['studios_skipping_crop'].split(',')
            #print(donotcrop)
        if not info.get('studio'): return False
        if info['studio'] in donotcrop: return False

        if self.scrapperConfig.get('labels_skipping_crop'):
            donotcrop = self.scrapperConfig['labels_skipping_crop'].split(',')

        if not info.get('label'): return False
        if info['label'] in donotcrop: return False

        return True
 
    def updateFromScrapy(self, info):
        #self.infoView.clearMovieInfo(False, True)
        try :
            info['fanart'] = info['thumb']
            if self.checkCrop(info):
                info['poster'] = info['thumb'].cropLeft()
            else:
                info['poster'] = info['thumb']

            #print('scrapy set movie info')
            self.infoView.setMovieInfo(info, False)
        except:
            traceback.print_exc()

    def onFoundMovie(self, movieinfo):
        if isinstance(movieinfo, list):
            self.updateFromFile(movieinfo)
        elif isinstance(movieinfo, dict):
            self.updateFromScrapy(movieinfo)

    '''
    def onScrapDone(self, _):
        self.numCids = 0

    # don't do anything related to Qt UI in scrapy signal. it doesn't work.
    def onSpiderClosed(self, spider):
        #import pprint as pp
        #pp.pprint(spider.movieinfo)
        try:
            self.crawledMovieInfo = spider.movieinfo
        except:
            self.crawledMovieInfo = None
    '''
    def onSpiderClosed(self, spider):
        self.numCids = 0
        self.listView.refresh()

    def onItemScraped(self, item, response, spider):
        if not response.meta.get('id'): return
        cid = response.meta['id']
        #print(cid)
        minfo = dict(item)
        minfo['path'] = self.fileView.getPath(cid['idx'])
        if 'releasedate' in minfo:
            minfo['year'] = minfo['releasedate'].split('-')[0]
        if 'actor_thumb' in minfo:
            del minfo['actor_thumb']

        #print(response.request.headers)
        if self.numCids > 1:
            mfiles = self.fileView.getFiles(cid['idx'])
            self.updateFromFile(mfiles, cid['idx'])
            self.updateFromScrapy(minfo)
            self.infoView.saveMovieInfo()
        else:
            self.updateFromScrapy(minfo)
            #self.onFoundMovie(minfo)

    def runCrawler(self, **kw):
        from scrapy import signals
        site = self.scrapperConfig.get('site', 'r18')
        if not self.crawler or self.site != site:
            self.site = site
            self.crawler = self.runner.create_crawler(site)
            self.crawler.signals.connect(self.onItemScraped, signals.item_scraped)
            self.crawler.signals.connect(self.onSpiderClosed, signals.spider_closed)
        self.runner.crawl(self.crawler, **kw)
        #deferd = self.runner.crawl(self.crawler, **kw)
        #deferd.addBoth(self.onScrapDone)

    def scrap(self, **kw):
        if kw:
            kw['outdir'] = self.fileView.rootPath()
            self.runCrawler(**kw)
            return

        selected = self.fileView.getSelectedIndexes()
        if len(selected) < 1:
            print('select movie!')
            return

        cids = [{'cid':os.path.basename(self.fileView.getPath(idx)), 'idx':idx} for idx in selected]
        self.numCids = len(cids)
        #print('num cids:', self.numCids)
        #print(cids, self.fileView.rootPath())
        self.runCrawler(**{'cids':cids})
        '''
        for index in selected:
            path = self.fileView.getPath(index)
            cid = os.path.basename(path)
            self.runCrawler(**{'keyword':cid, 'outdir':path})
        '''

    def saveAll(self):
        self.infoView.saveMovieInfo()
        self.listView.refresh()

    def changeDir(self, path):
        self.fileView.folderList.changeDir(path)

    def upDir(self):
        self.fileView.folderList.upDir()

    def fileRenameTool(self):
        config = self.globalConfig['FolderView']
        from rename_tool import FileRenameDialog
        dlg = FileRenameDialog(config.get('currdir', ''), self)
        dlg.exec_()
コード例 #10
0
class WritePanel(QWidget):
    def __init__(self, parent):
        super().__init__()

        self.initUI()

    def initUI(self):
        self.centralFrame = QFrame(self)
        self.centralFrame.setFrameShape(QFrame.NoFrame)
        self.centralFrame.setFrameShadow(QFrame.Raised)
        self.centralFrame.setContentsMargins(0, 0, 0, 0)
        self.centralFrame.setStyleSheet("background: black;"
                                        "border: 1px solid gray;"
                                        "border-radius: 5px;")

        self.contentFrame = QFrame(self.centralFrame)
        self.contentFrame.setFrameShape(QFrame.NoFrame)
        self.contentFrame.setFrameShadow(QFrame.Raised)
        self.contentFrame.setContentsMargins(0, 0, 0, 0)
        self.contentFrame.setStyleSheet("border: none;")

        self.antPanelFrame = QFrame(self.contentFrame)
        self.antPanelFrame.setFrameShape(QFrame.NoFrame)
        self.antPanelFrame.setFrameShadow(QFrame.Raised)
        self.antPanelFrame.setContentsMargins(0, 0, 0, 0)
        self.antPanelFrame.setStyleSheet("border: none;")

        self.antPanel = ANTPanel(self.antPanelFrame,
                                 alignment=ANTPanel.ALIGN_GRID,
                                 devicesStyle=ANTPanel.LIST_BOX)

        self.devices = self.antPanel.devices
        self.profiles = self.antPanel.profiles
        self.dataPages = self.antPanel.dataPages
        self.pageMeasurements = self.antPanel.pageMeasurements

        self.antPanelLayout = QHBoxLayout(self.antPanelFrame)
        self.antPanelLayout.addWidget(self.antPanel)
        self.antPanelLayout.setContentsMargins(0, 0, 0, 0)

        self.writerFrame = QFrame(self.contentFrame)
        self.writerFrame.setFrameShape(QFrame.NoFrame)
        self.writerFrame.setFrameShadow(QFrame.Raised)
        self.writerFrame.setContentsMargins(10, 10, 10, 10)
        self.writerFrame.setStyleSheet("border: none;")

        self.writerPanelFrame = QFrame(self.writerFrame)
        self.writerPanelFrame.setFrameShape(QFrame.NoFrame)
        self.writerPanelFrame.setFrameShadow(QFrame.Raised)
        self.writerPanelFrame.setContentsMargins(0, 0, 0, 0)
        self.writerPanelFrame.setStyleSheet("border: none;")

        self.udpPanel = UdpPanel(self.writerFrame)
        self.csvPanel = CSVPanel(self.writerFrame)

        self.writerPanel = QTabWidget(self.writerFrame)
        self.writerPanel.addTab(self.udpPanel, 'UDP')
        self.writerPanel.addTab(self.csvPanel, 'CSV')
        self.writerPanel.setContentsMargins(10, 10, 10, 10)
        self.writerPanel.setStyleSheet("QTabBar::tab { "
                                          "height: 30px; "
                                          "width: 100px; "
                                          "background-color: rgb(39, 44, 54);"
                                          "font: 14px;"
                                          "border-radius: 1px;"
                                          "}"
                                          "QTabBar::tab:selected { "
                                          "border: 1px solid gray;"
                                          "}"
                                          "QTabBar::tab:hover{"
                                          "background-color: rgb(85, 170, 255);"
                                          "}"
                                          "QTabWidget::pane {"
                                          "border: 1px solid gray;"
                                          "}")

        self.writerPanelLayout = QHBoxLayout(self.writerPanelFrame)
        self.writerPanelLayout.addWidget(self.writerPanel)
        self.writerPanelLayout.setContentsMargins(0, 0, 0, 0)

        self.logPanelFrame = QFrame(self.writerFrame)
        self.logPanelFrame.setFrameShape(QFrame.NoFrame)
        self.logPanelFrame.setFrameShadow(QFrame.Raised)
        self.logPanelFrame.setContentsMargins(0, 0, 0, 0)
        self.logPanelFrame.setStyleSheet("background: rgb(15,15,15);"
                                         "border: 1px solid gray;"
                                         )

        self.logPanel = QTextEdit(self.logPanelFrame)
        self.logPanel.setStyleSheet("border: none;")
        self.logPanel.setReadOnly(True)

        self.logPanelLayout = QHBoxLayout(self.logPanelFrame)
        self.logPanelLayout.addWidget(self.logPanel)
        self.logPanelLayout.setContentsMargins(0, 0, 0, 0)

        self.writerLayout = QVBoxLayout(self.writerFrame)
        self.writerLayout.addWidget(self.writerPanelFrame)
        self.writerLayout.addWidget(self.logPanelFrame)
        self.writerLayout.setContentsMargins(0, 0, 0, 0)

        self.contentLayout = QHBoxLayout(self.contentFrame)
        self.contentLayout.addWidget(self.antPanelFrame, stretch=1)
        self.contentLayout.addWidget(self.writerFrame, stretch=1)
        self.contentLayout.setContentsMargins(0, 0, 0, 0)

        self.centralLayout = QHBoxLayout(self.centralFrame)
        self.centralLayout.addWidget(self.contentFrame)
        self.centralLayout.setContentsMargins(0, 0, 0, 0)

        self.uiLayout = QHBoxLayout(self)
        self.uiLayout.addWidget(self.centralFrame)
        self.uiLayout.setContentsMargins(0, 0, 0, 0)

        self.setLayout(self.uiLayout)
        self.setContentsMargins(0, 0, 0, 0)
コード例 #11
0
ファイル: RainyDM.py プロジェクト: razputin42/RainyDM
class DMTool(QMainWindow):
    SEARCH_BOX_WIDTH = 200

    def __init__(self, db_path, validate_views=False):
        super().__init__()
        self._database_path = db_path
        sys.excepthook = self.excepthook
        self.settings = dict({"query_srd": True})
        self.load_meta()
        self._setup_ui()
        self._setup_menu()
        self.bind_signals()
        self.load_session()
        self._display_ui()
        if validate_views:
            self.validate_views()

    def _setup_ui(self):
        """
        Layout is a windowLayout with a horizontal box on the left and a tab widget on the right
        :return:
        """
        self.setStyleSheet(
            open(os.path.join("assets", "styles", "default.css")).read())
        self.setWindowIcon(QIcon(os.path.join('assets', 'tear.png')))
        self.setWindowTitle("RainyDM")
        self.setGeometry(100, 100, 1280, 720)
        self.window_frame = QFrame()
        self.window_layout = QHBoxLayout()
        # Left side tab
        self.tab_widget = QTabWidget()

        # Viewers
        # - monster viewer
        monster_button_bar = QFrame()
        monster_button_bar_layout = QHBoxLayout()
        monster_button_bar.setLayout(monster_button_bar_layout)
        self.monster_viewer = MonsterViewer(monster_button_bar, self.system)
        monster_viewer_frame_layout = QVBoxLayout()
        self.monster_viewer_frame = QFrame()
        self.monster_viewer_frame.setLayout(monster_viewer_frame_layout)
        self.monster_viewer_frame.layout().setContentsMargins(0, 0, 0, 0)
        self.monster_viewer_frame.setFrameStyle(0)

        # - spell viewer
        self.spell_viewer = SpellViewer(self.system)

        # - item viewer
        self.item_viewer = ItemViewer(self.system)

        # Text box
        self.text_box = QTextEdit()
        self.text_box.setObjectName("OutputField")
        self.text_box.setReadOnly(True)
        self.text_box.setFontPointSize(10)

        ## Tables
        # Spell Table
        self.spell_table_widget = SpellTableWidget(self, self.spell_viewer)

        # Monster table
        self.monster_table_widget = MonsterTableWidget(self,
                                                       self.monster_viewer)

        # Item table
        self.item_table_widget = ItemTableWidget(self, self.item_viewer)
        self.item_table_widget.layout().addWidget(self.item_viewer)

        self.load_resources(self._database_path)

        # Loot Generator Widget
        self.lootViewer = ItemViewer(self.system)
        self.loot_widget = TreasureHoardTab(self, self.item_viewer,
                                            self.item_table_widget)

        # Initiative list
        self.encounterWidget = EncounterWidget(self.monster_viewer)

        # bookmark
        self.bookmark_widget = BookmarkWidget(self.monster_table_widget,
                                              self.monster_viewer,
                                              self.spell_table_widget,
                                              self.spell_viewer)

        encounter_frame = QFrame()
        encounter_layout = QVBoxLayout()
        encounter_layout.addWidget(self.encounterWidget)
        encounter_layout.addWidget(self.bookmark_widget)
        encounter_frame.setLayout(encounter_layout)

        # player tab
        player_table_frame = QFrame()
        player_table_layout = QVBoxLayout()
        encounter_button_layout = QHBoxLayout()
        self.add_player_button = QPushButton("Add Player")
        self.add_player_button.setSizePolicy(QSizePolicy.Minimum,
                                             QSizePolicy.Minimum)
        self.playerWidget = PlayerTable()
        encounter_button_layout.addWidget(self.add_player_button)
        encounter_button_layout.addStretch(0)
        player_table_layout.addWidget(self.playerWidget)
        player_table_layout.addLayout(encounter_button_layout)
        player_table_frame.setLayout(player_table_layout)

        self.monster_viewer_bar = QFrame()
        self.monster_viewer_bar.setContentsMargins(0, 0, 0, 0)

        monster_viewer_frame_layout.addWidget(self.monster_viewer)
        monster_viewer_frame_layout.addWidget(monster_button_bar)
        monster_viewer_frame_layout.addWidget(self.monster_viewer_bar)
        monster_viewer_frame_layout.setStretch(3, 1)
        monster_viewer_frame_layout.setStretch(0, 2)

        middle_frame_layout = QVBoxLayout()
        self.middle_frame = QTabWidget()
        self.middle_frame.setLayout(middle_frame_layout)
        self.middle_frame.setContentsMargins(0, 0, 0, 0)

        layout = QHBoxLayout()
        monster_plaintext_button = QPushButton("Copy plaintext to clipboard")
        monster_plaintext_button.clicked.connect(
            self.copy_plaintext_monster_to_clipboard)
        layout.addWidget(monster_plaintext_button)
        self.monster_viewer_bar.setLayout(layout)

        # middle_frame_layout.addWidget(self.spell_viewer)
        middle_frame_layout.setStretch(0, 2)
        middle_frame_layout.setContentsMargins(0, 0, 0, 0)

        # Leftmost tab
        self.tab_widget.addTab(encounter_frame, "Encounter")
        self.tab_widget.addTab(player_table_frame, "Players")
        self.tab_widget.addTab(self.loot_widget, "Loot")

        # Center tab
        self.middle_frame.addTab(self.monster_table_widget, "Monster")
        self.middle_frame.addTab(self.spell_table_widget, "Spell")
        self.middle_frame.addTab(self.item_table_widget, "Item")
        self.middle_frame.addTab(self.text_box, "Text Box")

        # Right frame
        self.right_tab = QTabWidget()
        self.right_tab.addTab(self.monster_viewer_frame, "Monster")
        self.right_tab.addTab(self.spell_viewer, "Spell")
        self.right_tab.addTab(self.item_viewer, "Item")

        self.window_layout.addWidget(self.tab_widget)
        self.window_layout.addWidget(self.middle_frame)
        self.window_layout.addWidget(self.right_tab)
        self._set_widget_stretch(GlobalParameters.MAIN_TOOL_POSITION,
                                 GlobalParameters.MAIN_TOOL_STRETCH)
        self._set_widget_stretch(GlobalParameters.MIDDLE_FRAME_POSITION, 0)
        self._set_widget_stretch(GlobalParameters.RIGHT_FRAME_POSITION,
                                 GlobalParameters.RIGHT_FRAME_STRETCH)

        self.monster_viewer_bar.setHidden(True)

        self.window_frame.setLayout(self.window_layout)

    def _setup_menu(self):
        ### Menubar
        menu = self.menuBar()
        version = menu.addMenu("Version")
        # button_3_5 = QAction("3.5 Edition", self)
        # button_3_5.setStatusTip("3.5 Edition")
        # version.addAction(button_3_5)
        button_5 = QAction("5th Edition", self)
        button_5.setStatusTip("5th Edition")
        version.addAction(button_5)
        button_5.triggered.connect(lambda: self.change_version(System.DnD5e))
        button_sw5e = QAction("SW 5th Edition", self)
        button_sw5e.setStatusTip("SW 5th Edition")
        version.addAction(button_sw5e)
        button_sw5e.triggered.connect(lambda: self.change_version(System.SW5e))
        # button_3_5.triggered.connect(lambda: self.change_version("3.5"))

        experimental = menu.addMenu("Experimental")
        button_plain_text = QAction("Plain text monsters",
                                    self,
                                    checkable=True)
        button_plain_text.setStatusTip("Plain text monsters")
        button_plain_text.triggered.connect(self.toggle_monster_bar)
        # raise_exception = QAction("Raise Exception", self)
        # raise_exception.setStatusTip("Raise an Exception")
        # raise_exception.triggered.connect(self.raise_exception)
        self.edit_entries_action = QAction("Edit Entries",
                                           self,
                                           checkable=True)
        self.edit_entries_action.setStatusTip("Enable edit data entries")
        # development
        self.edit_entries_action.setChecked(True)  # default ON
        self.enable_edit_data_entries()
        ##
        self.edit_entries_action.triggered.connect(
            self.enable_edit_data_entries)

        experimental.addAction(button_plain_text)
        experimental.addAction(self.edit_entries_action)
        # experimental.addAction(raise_exception)

        self.window_frame.setLayout(self.window_layout)

    # def raise_exception(self):
    #     raise EnvironmentError("Forced an exception")

    def enable_edit_data_entries(self):
        cond = self.edit_entries_action.isChecked()
        self.monster_table_widget.EDITABLE = False  # not for monsters
        self.spell_table_widget.EDITABLE = cond
        self.item_table_widget.EDITABLE = cond

    def bind_signals(self):
        self.encounterWidget.add_players_button.clicked.connect(
            self.addPlayersToCombat)
        self.encounterWidget.sort_init_button.clicked.connect(
            self.sort_init_handle)
        self.encounterWidget.roll_init_button.clicked.connect(
            self.roll_init_handle)
        self.encounterWidget.save_encounter_button.clicked.connect(
            self.encounterWidget.save)
        self.encounterWidget.load_encounter_button.clicked.connect(
            lambda: self.encounterWidget.load(self.monster_table_widget))
        self.encounterWidget.clear_encounter_button.clicked.connect(
            self.clear_encounter_handle)
        self.bookmark_widget.clear_bookmark_button.clicked.connect(
            self.clear_bookmark_handle)
        self.bookmark_widget.toggle_bookmark_button.clicked.connect(
            self.toggle_bookmark_handle)

        self.add_player_button.clicked.connect(self.add_player)
        sNexus.attackSignal.connect(self.attackSlot)
        sNexus.addSpellsSignal.connect(self.addSpellsToBookmark)
        sNexus.printSignal.connect(self.print)
        sNexus.addMonstersToEncounter.connect(
            self.encounterWidget.addMonsterToEncounter)
        sNexus.setWidgetStretch.connect(self._set_widget_stretch)
        sNexus.viewerSelectChanged.connect(self.viewer_select_changed)

    def _display_ui(self):
        self.setCentralWidget(self.window_frame)

    def _set_widget_stretch(self, widget, stretch):
        self.window_layout.setStretch(widget, stretch)

    def toggle_monster_bar(self):
        if self.monster_viewer_bar.isHidden():
            self.monster_viewer_bar.setHidden(False)
        else:
            self.monster_viewer_bar.setHidden(True)

    def copy_plaintext_monster_to_clipboard(self):
        pyperclip.copy(html2text.html2text(self.monster_viewer.html))

    def viewer_select_changed(self, idx):
        self.right_tab.setCurrentIndex(idx)

    def change_version(self, version):
        if self.system == version:
            return
        self.system = version
        self.clear_bookmark_handle()
        self.clear_encounter_handle()

        self.monster_table_widget.table.clear()
        self.spell_table_widget.table.clear()
        self.item_table_widget.table.clear()

        self.monster_table_widget.filter.clear_filters()

        self.load_resources(self._database_path)

    def addMonsterToBookmark(self, monster):
        row_position = self.bookmark_widget.monster_bookmark.rowCount()
        self.bookmark_widget.monster_bookmark.insertRow(row_position)
        if type(monster) == list:
            for itt, value in enumerate(monster):
                self.bookmark_widget.monster_bookmark.setItem(
                    row_position, itt, QTableWidgetItem(str(value)))
        else:
            self.bookmark_widget.monster_bookmark.setItem(
                row_position, 0, QTableWidgetItem(str(monster.name)))
            self.bookmark_widget.monster_bookmark.setItem(
                row_position, 1, QTableWidgetItem(str(monster.index)))

    def addSpellsToBookmark(self, spells):
        for spell in spells:
            _spell = self.spell_table_widget.find_entry('name', spell)
            self.add_to_bookmark_spell(_spell)

    def add_to_bookmark_spell(self, spell):
        row_position = self.bookmark_widget.spell_bookmark.rowCount()
        self.bookmark_widget.spell_bookmark.insertRow(row_position)
        if type(spell) == list:
            for itt, value in enumerate(spell):
                self.bookmark_widget.spell_bookmark.setItem(
                    row_position, itt, QTableWidgetItem(str(value)))
        elif spell is not None:
            self.bookmark_widget.spell_bookmark.setItem(
                row_position, 0, QTableWidgetItem(str(spell.name)))
            self.bookmark_widget.spell_bookmark.setItem(
                row_position, 1, QTableWidgetItem(str(spell.index)))
            self.bookmark_widget.spell_bookmark.setItem(
                row_position, 2, QTableWidgetItem(str(spell.level)))

    def load_resources(self, database_path):
        self.db = RainyDatabase(database_path, system=self.system)
        self.item_table_widget.set_entries(self.db.get_items())
        self.item_table_widget.fill_table()
        self.item_table_widget.define_filters(self.system)
        self.monster_table_widget.set_entries(self.db.get_monsters())
        self.monster_table_widget.fill_table()
        self.monster_table_widget.define_filters(self.system)
        # self.spell_table_widget.load_all("./spell", "{}/{}/Spells/".format(resource_path, self.version), spell_cls)
        self.spell_table_widget.set_entries(self.db.get_spells())
        self.spell_table_widget.fill_table()
        self.spell_table_widget.define_filters(self.system)

    def add_player(self, player=None):
        self.playerWidget.add(PlayerFrame(self.playerWidget))

    def addPlayersToCombat(self):
        encounterWidget = self.encounterWidget
        characterNames = encounterWidget.getCharacterNames()
        # Get active players

        for entry in self.playerWidget.m_widgetList:
            # character in encounter, and should be
            if entry.getCharacter().getCharName(
            ) in characterNames and entry.isEnabled():
                # print("Character in encounter, and should be")
                encounterWidget.update_character(entry.getCharacter())

            # character in encounter, but shouldn't be
            elif entry.getCharacter().getCharName(
            ) in characterNames and not entry.isEnabled():
                # print("Character in enocunter, shouldn't be")
                # print(entry.getCharacter().getCharName(), entry.isEnabled())
                encounterWidget.remove_character(entry.getCharacter())

            # character not in encounter, but should be
            elif entry.getCharacter().getCharName(
            ) not in characterNames and entry.isEnabled():
                # print("Character not in encounter, should be")
                encounterWidget.addPlayerToEncounter(entry.getCharacter())

            # character not in encounter, and shouldn't be
            else:
                pass

    def sort_init_handle(self):
        self.encounterWidget.sortInitiative()

    def roll_init_handle(self):
        self.encounterWidget.rollInitiative()

    def clear_encounter_handle(self):
        self.encounterWidget.clear()

    def clear_bookmark_handle(self):
        self.bookmark_widget.monster_bookmark.clear()
        self.bookmark_widget.monster_bookmark.setRowCount(0)
        self.bookmark_widget.spell_bookmark.clear()
        self.bookmark_widget.spell_bookmark.setRowCount(0)

    def toggle_bookmark_handle(self):
        self.bookmark_widget.toggle_hide()

    def print(self, s):
        self.middle_frame.setCurrentIndex(GlobalParameters.TEXT_BOX_INDEX)
        self.text_box.append(s)

    def print_attack(self, monster_name, attack):
        attack = attack.strip(" ")
        comp = attack.split("|")
        if attack == "":
            s = "{} used an action".format(monster_name)
        else:
            s = "{} uses {} -- ".format(monster_name, comp[0])

            if comp[1] not in [
                    "", " "
            ]:  # this means there's an attack roll and a damage roll
                attack_roll = roll_function("1d20+" + comp[1])
                s = s + "{}({}) to hit".format(attack_roll,
                                               attack_roll - int(comp[1]))
            damage_roll = roll_function(comp[2])
            if damage_roll is not None:
                if type(damage_roll) is list:
                    halved = [max(1, int(dr / 2)) for dr in damage_roll]
                else:
                    # print("\trainydm - print_attack: \"{}\"".format(damage_roll))
                    halved = max(1, int(damage_roll / 2))
                s = s + " -- for {} ({} halved)".format(
                    str(damage_roll), str(halved))
        self.print(s)

    def extract_and_add_spellbook(self, monster):
        spells = monster.extract_spellbook()
        if spells is not None:
            for spell in spells:
                spell_entry = self.spell_table_widget.find_entry("name", spell)
                if spell_entry is not None:
                    self.add_to_bookmark_spell(spell_entry)
                else:
                    print("Failed to locate spell for", monster.name,
                          "with spellname {}".format(spell))

    def load_meta(self):
        if not os.path.exists("metadata/"):
            os.mkdir("metadata")

        meta_path = os.path.join("metadata", "meta.txt")
        if os.path.exists(meta_path):
            with open(meta_path, "r") as f:
                meta_dict = json.load(f)
                self.system = System.from_plaintext(meta_dict['system'])
                self.settings = meta_dict['settings']
        else:
            self.system = System.DnD5e

    def load_session(self):
        if not os.path.exists("metadata/"):
            os.mkdir("metadata")
        if os.path.exists("metadata/session.txt"):
            with open("metadata/session.txt", "r") as f:
                meta_dict = eval(f.read())
                for monster_tuple in meta_dict['bookmark_meta']:
                    self.addMonsterToBookmark(monster_tuple)

                for player in meta_dict['player_meta']:
                    player_dict = json.loads(player)
                    self.playerWidget.add(
                        PlayerFrame(self.playerWidget,
                                    charName=player_dict["characterName"],
                                    playerName=player_dict["playerName"],
                                    init=player_dict["initiative"],
                                    perception=player_dict["perception"],
                                    insight=player_dict["insight"],
                                    isEnabled=player_dict["isEnabled"]))

                for entry in meta_dict['initiative_meta']:
                    entry_dict = json.loads(entry)
                    if entry_dict["type"] == "Monster":
                        self.encounterWidget.add(
                            MonsterWidget(self.monster_table_widget.find_entry(
                                "name", entry_dict["monster"]),
                                          self.encounterWidget,
                                          viewer=self.monster_viewer,
                                          init=entry_dict["init"],
                                          hp=entry_dict["hp"]))
                    elif entry_dict["type"] == "Player":
                        self.encounterWidget.add(
                            PlayerWidget(
                                self.encounterWidget,
                                self.playerWidget.findCharacterByName(
                                    entry_dict["name"])))

    def closeEvent(self, event):
        bookmark_meta = self.bookmark_widget.monster_bookmark.jsonlify()
        initiative_meta = self.encounterWidget.jsonlify()
        player_meta = self.playerWidget.jsonlify()

        with open("metadata/session.txt", "w") as f:
            json.dump(
                dict(bookmark_meta=bookmark_meta,
                     initiative_meta=initiative_meta,
                     player_meta=player_meta), f)

        with open("metadata/meta.txt", "w") as f:
            json.dump(
                dict(system=System.to_plaintext(self.system),
                     settings=self.settings), f)

    # SLOTS
    @pyqtSlot(str, str)
    def attackSlot(self, name, attack):
        self.print_attack(name, attack)
        self.middle_frame.setCurrentIndex(GlobalParameters.TEXT_BOX_INDEX)

    def excepthook(self, type, value, tb):
        box = QMessageBox()
        box.setWindowTitle("Oof!")
        box.setText("RainyDM has crashed!")
        box.setIcon(QMessageBox.Critical)
        details = "".join(traceback.format_exception(type, value, tb))
        box.setDetailedText(details)

        spacer = QSpacerItem(500, 0, QSizePolicy.Minimum, QSizePolicy.Minimum)
        box.layout().addItem(spacer,
                             box.layout().rowCount(), 0, 1,
                             box.layout().columnCount())

        box.exec_()
        old_excepthook(type, value, tb)
        self.close()

    def validate_views(self):
        for spell in self.db.get_spells().values():
            self.spell_viewer.draw_view(spell)
        for monster in self.db.get_monsters().values():
            self.monster_viewer.draw_view(monster)
        for item in self.db.get_items().values():
            self.item_viewer.draw_view(item)