コード例 #1
0
class Form(QWidget):
    def __init__(self):
        QWidget.__init__(self, flags=Qt.Widget)
        self.tbw = QTabWidget()
        self.init_widget()

    def init_widget(self):
        """
		현재 위젯의 모양등을 초기화
		"""
        self.setWindowTitle("Tab Widget")
        form_lbx = QBoxLayout(QBoxLayout.TopToBottom, parent=self)
        self.setLayout(form_lbx)

        # 탭 추가 버튼 생성
        tbw_addbtn = QToolButton()
        self.tbw.setCornerWidget(tbw_addbtn, Qt.TopLeftCorner)  # 버튼 위치
        tbw_addbtn.setAutoRaise(True)  # 마우스가 올라오면 올라옴
        tbw_addbtn.setIcon(QIcon("plus_icon.png"))  # 아이콘 지정
        tbw_addbtn.clicked.connect(self.add_new_tab)  # 클릭시 시그널 지정
        form_lbx.addWidget(self.tbw)

        # 기본 탭 생성
        self.add_new_tab()

    @pyqtSlot()
    def add_new_tab(self):
        """
		텍스트 에디트를 가진 텝을 생성
		"""
        self.tbw.addTab(QTextEdit(), "tab #%d" % (self.tbw.count() + 1))
コード例 #2
0
class MainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        url = "http://127.0.0.1:43110/1HeLLo4uzjaLetFx6NH3PMwFP3qbRbTf3D/"
        if "url" in kwargs:
            url = kwargs["url"]
            del kwargs["url"]

        if "zeronet_path" in kwargs:
            self.zeronet_path = kwargs["zeronet_path"]
            del kwargs["zeronet_path"]

        super(MainWindow, self).__init__(*args, **kwargs)

        # Tabs
        self.tabs = QTabWidget()
        self.tabs.setTabsClosable(True)
        self.tabs.tabCloseRequested.connect(self.close_tab)

        # New tab button
        #self.tab_add_button_index = self.tabs.addTab(QWidget(), '+')
        self.add_tab_button = QToolButton()
        self.add_tab_button.setText('+')
        self.add_tab_button.setStyleSheet(
            'QToolButton {border: none; margin: 4px 20px 4px 0px; height: 480px; border-left: 1px solid lightgrey; padding: 0px 4px 0px 4px; font-weight: bold; color: #5d5b59}'
            'QToolButton:hover { background-color: lightgrey }'
            'QToolButton:pressed { background-color: grey }')
        self.add_tab_button.clicked.connect(self.new_tab_clicked)
        self.tabs.setCornerWidget(self.add_tab_button)

        # Navigation bar
        self.navigation = NavigationBar()
        self.navigation.url_bar.returnPressed.connect(self.navigate_to_url)

        # Back
        self.navigation.back_btn.triggered.connect(
            lambda: self.tabs.currentWidget().back())

        # Next
        self.navigation.next_btn.triggered.connect(
            lambda: self.tabs.currentWidget().forward())

        # Reload
        self.navigation.reload_btn.triggered.connect(
            lambda: self.tabs.currentWidget().reload())
        self.navigation.shortcut_reload.activated.connect(
            lambda: self.tabs.currentWidget().reload())
        self.navigation.shortcut_reload_f5.activated.connect(
            lambda: self.tabs.currentWidget().reload())

        # Home
        self.navigation.home_btn.triggered.connect(self.go_home)

        # Menu: Edit config action
        self.navigation.edit_config_action.triggered.connect(
            self.edit_zeronet_config_file)

        # Add new tab
        self.add_new_tab(url, "Home")

        # Get everything fitting in the main window
        self.addToolBar(self.navigation)
        self.setCentralWidget(self.tabs)
        self.show()
        self.setWindowTitle("ZeroNet Browser")
        self.setWindowIcon(QIcon("icons/zeronet-logo.svg"))
        self.showMaximized()

    def contextMenuEvent(self, event):
        print(event)

    def update_url_bar(self, q, browser=None):

        if browser != self.tabs.currentWidget():
            # If this signal is not from the current tab, ignore
            return

        url_array = q.toString().split('/')[3:]
        formatted_url = '/'.join(str(x) for x in url_array)
        self.navigation.url_bar.setText('zero://' + formatted_url)
        self.navigation.url_bar.setCursorPosition(0)

        if (self.tabs.currentWidget().can_go_back()):
            self.navigation.back_btn.setDisabled(False)
        else:
            self.navigation.back_btn.setDisabled(True)

        if (self.tabs.currentWidget().can_go_forward()):
            self.navigation.next_btn.setDisabled(False)
        else:
            self.navigation.next_btn.setDisabled(True)

    def navigate_to_url(self):
        # Get url
        url = self.navigation.url_bar.text()

        if url.startswith('zero://'):
            # ZeroNet protocol
            url_array = url.split('/')
            url = 'http://127.0.0.1:43110/' + url_array[2]
        elif url.startswith('http://'):
            # http protocol
            pass
        else:
            # Nothing mentionned
            url = 'http://127.0.0.1:43110/' + url

        self.tabs.currentWidget().setUrl(QUrl(url))

    def go_home(self):
        self.tabs.currentWidget().setUrl(
            QUrl("http://127.0.0.1:43110/1HeLLo4uzjaLetFx6NH3PMwFP3qbRbTf3D/"))

    def new_tab_clicked(self):
        self.add_new_tab(
            "http://127.0.0.1:43110/1HeLLo4uzjaLetFx6NH3PMwFP3qbRbTf3D/",
            "Home")

    def get_link_url_from_context_menu(self):
        tab = self.tabs.currentWidget()
        page = tab.page()
        context = page.contextMenuData()
        qurl = context.linkUrl()
        return qurl.url()

    def open_in_new_tab(self):
        url = self.get_link_url_from_context_menu()
        self.add_new_tab(url, "Home")

    # Doesnt feel right to have it here but it is working
    def open_in_new_window(self):
        url = self.get_link_url_from_context_menu()
        kwargs = {"url": url}
        self.window = self.__class__(**kwargs)

    def add_new_tab(self, qurl, label):
        # Instead of browser it should be called WebView !
        browser = Browser()

        # Triggered open in new tab
        openLinkInNewTabAction = browser.pageAction(
            QWebEnginePage.OpenLinkInNewTab)
        openLinkInNewWindowAction = browser.pageAction(
            QWebEnginePage.OpenLinkInNewWindow)
        openLinkInNewTabAction.triggered.connect(self.open_in_new_tab)
        openLinkInNewWindowAction.triggered.connect(self.open_in_new_window)
        self.addAction(openLinkInNewTabAction)

        browser.urlChanged.connect(
            lambda qurl, browser=browser: self.update_url_bar(qurl, browser))
        indexTab = self.tabs.addTab(browser, label)
        # Maybe change current index after loading?
        self.tabs.setCurrentIndex(indexTab)
        # We need to update the url !
        if qurl.startswith('zero://'):
            # ZeroNet protocol
            url_array = qurl.split('/')
            qurl = 'http://127.0.0.1:43110/' + url_array[2]
        elif qurl.startswith('http://'):
            # http protocol
            pass
        else:
            # Nothing mentionned
            qurl = 'http://127.0.0.1:43110/' + qurl

        currentTab = self.tabs.currentWidget()
        currentTab.loadFinished.connect(self.page_loaded)
        index = self.tabs.currentIndex()
        currentTab.titleChanged.connect(
            lambda title, index=index: self.tabs.setTabText(index, title))
        currentTab.iconChanged.connect(
            lambda icon, index=index: self.tabs.setTabIcon(index, icon))

        currentTab.setUrl(QUrl(qurl))
        return indexTab

    def page_loaded(self, ok):
        if ok:
            currentTab = self.tabs.currentWidget()
            index = self.tabs.currentIndex()
            label = currentTab.title()
            icon = currentTab.icon()
            self.tabs.setTabIcon(index, icon)
            self.tabs.setTabText(index, label)

    def close_tab(self, index):
        if self.tabs.count() == 1:
            self.tabs.currentWidget().setUrl(
                QUrl(
                    "http://127.0.0.1:43110/1HeLLo4uzjaLetFx6NH3PMwFP3qbRbTf3D/"
                ))
            return
        self.tabs.removeTab(index)

    def edit_zeronet_config_file(self):
        filepath = os.path.join(os.sep, self.zeronet_path, "zeronet.conf")

        if sys.platform.startswith('darwin'):  # macOS
            subprocess.run(['open', filepath])
        elif sys.platform.startswith('win'):  # Windows
            os.startfile(filepath)
        else:  # linux variants
            subprocess.run(['xdg-open', filepath])
コード例 #3
0
class MyTableWidget(QWidget):
    def __init__(self, parent, cornerwidget):
        super(QWidget, self).__init__(parent)
        self.layout = QVBoxLayout(self)
        self.history = {}
        # Initialize tab screen
        self.tabs = QTabWidget(movable=True, tabsClosable=True, tabShape=1)

        self.tabs.resize(0, 500)

        # Add tabs

        self.tabs.tabCloseRequested.connect(self.remove_tab)
        #self.tabs.tabBarDoubleClicked.connect( self.new_tab )
        # Create first tab

        # Add tabs to widget
        self.layout.addWidget(self.tabs)

        self.layout.setContentsMargins(0, 10, 0, 0)
        self.layout.setSpacing(0)
        self.url = 'http://google.com'

        self.gridLayout = QGridLayout()

        self.searchBar = QLineEdit()
        self.goback = QPushButton('B')
        self.goforward = QPushButton('F')
        self.reload = QPushButton('r')
        self.home = QPushButton('h')
        self.gridLayout.addWidget(self.goback, 0, 0)
        self.gridLayout.addWidget(self.goforward, 0, 1)
        self.gridLayout.addWidget(self.reload, 0, 2)
        self.gridLayout.addWidget(self.home, 0, 3)
        self.gridLayout.addWidget(self.searchBar, 0, 4)
        self.gridLayout.setSpacing(0)
        self.gridLayout.setContentsMargins(0, 5, 5, 4)
        self.layout.addLayout(self.gridLayout)
        #self.layout.addWidget(self.gridLayout)
        self.searchBar.setText(self.url)
        self.goback.clicked.connect(lambda: self.tabs.currentWidget().back())

        self.goforward.clicked.connect(
            lambda: self.tabs.currentWidget().forward())
        self.reload.clicked.connect(lambda: self.tabs.currentWidget().reload())
        self.searchBar.returnPressed.connect(self.loadpage)

        self.setLayout(self.layout)
        self.new_tab()

        self.goback.setStyleSheet(
            ":hover{background-color:#00596b;}"
            "QPushButton{background-color: #004551;border-left-style: none;border-top-style: none;border-bottom-style: none;width:40px;height:29px!important; margin:0!important;}"
        )
        self.goforward.setStyleSheet(
            ":hover{background-color:#00596b;}"
            "QPushButton{background-color: #004551;border-left-style: none;border-top-style: none;border-bottom-style: none;width:40px;height:29px!important; margin:0!important;}"
        )
        self.reload.setStyleSheet(
            ":hover{background-color:#00596b;}"
            "QPushButton{background-color: #004551;border-left-style: none;border-top-style: none;border-bottom-style: none;width:40px;height:29px!important; margin:0!important;}"
        )
        self.home.setStyleSheet(
            ":hover{background-color:#00596b;}"
            "QPushButton{background-color: #004551;border-left-style: none;border-top-style: none;border-bottom-style: none;width:40px;height:29px!important; margin:0!important;}"
        )

        self.addtabbutton = QPushButton("+")
        self.cn = QWidget()
        self.layout1 = QHBoxLayout(self.cn)
        self.layout1.addWidget(self.addtabbutton)
        self.addtabbutton.setStyleSheet(
            ":hover{background-color:#00596b;color:white;}"
            "QPushButton{background-color: transparent;width:40px;height:30px;padding-top:3px;border:1px solid black;border-top:none;}"
        )
        self.layout1.setSpacing(0)
        self.cn.setStyleSheet("background-color: #004551;")
        self.layout1.setContentsMargins(0, 0, 0, 0)
        self.addtabbutton.clicked.connect(self.new_tab)

        #self.tabs.tabBarDoubleClicked.connect( self.new_tab )

        self.tabs.setCornerWidget(cornerwidget)
        self.tabs.setCornerWidget(self.cn, corner=Qt.TopLeftCorner)
        self.tabs.currentChanged.connect(self.changeurl)

    def forward(self):

        self.view.page().triggerAction(QWebEnginePage.Forward)

    def back(self, browser=None):
        #self.view.page().action(QWebEnginePage.Back)

        self.view.page().triggerAction(QWebEnginePage.Back)
        print('forward enabled',
              self.view.page().action(QWebEnginePage.Forward).isEnabled())

    def changeurl(self):
        if self.tabs.currentWidget().url():
            qurl = self.tabs.currentWidget().url()
            self.searchBar.setText(qurl.toString())

        else:
            self.searchBar.setText("History")

    def mouseDoubleClickEvent(self, event):
        self.offset = event.pos()
        y_w = self.offset.y()
        if y_w < 10:

            self.new_tab()

    def loadpage(self):
        if self.searchBar.text().lower() == "history":
            self.showHistory()
        else:
            self.url = QUrl(self.searchBar.text())
            if self.url.scheme() == "":

                self.url.setScheme("https")
            self.tabs.currentWidget().setUrl(self.url)

    def update_history(self):
        if self.tabs.currentWidget().url():
            qurl = self.tabs.currentWidget().url()
            x = dt.now()

            self.history[x.strftime("%c")] = qurl.toString()
        print(self.history)

    def showHistory(self):
        d = QDialog()
        vbox = QVBoxLayout()
        for h in self.history:
            h1 = QLabel()
            h1.setText(h + " -->" + self.history[h])
            vbox.addWidget(h1)
        d.setLayout(vbox)

        d.setWindowModality(Qt.ApplicationModal)
        d.exec_()

    def remove_tab(self, currentIndex):
        self.tabs.removeTab(currentIndex)

    def new_tab(self, z=0):
        if z == 0:
            self.view = QWebEngineView()
            self.defaulturl = 'http://google.com'
            self.view.load(PyQt5.QtCore.QUrl(self.defaulturl))

            i = self.tabs.addTab(self.view, "Google")
            self.view.urlChanged.connect(self.changeurl)
            self.view.loadFinished.connect(self.update_history)
            self.view.loadFinished.connect(
                lambda _, i=i, browser=self.view: self.tabs.setTabText(
                    i,
                    browser.page().title()))

        else:
            self.tab1 = QWidget()
            return self.tabs.addTab(self.tab1, "History")
コード例 #4
0
class TabToolbar(QToolBar):
    """[summary]

    Args:
        _TabToolbar ([type]): [description]

    Returns:
        [type]: [description]
    """

    Minimized = QtCore.pyqtSignal()
    Maximized = QtCore.pyqtSignal()
    SpecialTabClicked = QtCore.pyqtSignal()
    StyleChanged = QtCore.pyqtSignal()

    def __init__(self,
                 parent: QWidget = None,
                 group_maxheight: int = 75,
                 group_rowcount: int = 3):
        super(TabToolbar, self).__init__(parent)
        style.register_default_styles()
        self.group_rowcount = group_rowcount
        self.group_maxheight = group_maxheight
        self.has_specialtab = False
        self.current_index = 0
        self.ignore_styleevent = False
        self.is_shown = True
        self._is_minimized = False
        self.maxheight = QtWidgets.QWIDGETSIZE_MAX
        self._style = style.StyleParams()
        self.setObjectName("TabToolbar")

        # self.tempShowTimer = QtCore.QTimer()
        # self.tempShowTimer.setSingleShot(True)
        # self.tempShowTimer.setInterval(QApplication.doubleClickInterval())

        self.setProperty("TabToolbar", QtCore.QVariant(True))
        self.layout().setContentsMargins(0, 0, 0, 0)
        self.layout().setSpacing(0)
        self.setContentsMargins(0, 0, 0, 0)
        self.setFloatable(False)
        self.setMovable(False)
        self.setAllowedAreas(QtCore.Qt.TopToolBarArea)
        self.tabBar = QTabWidget(self)

        self.tabBar.setProperty("TTWidget", QtCore.QVariant(True))
        self.tabBar.tabBar().setProperty("TTTab", QtCore.QVariant(True))
        self.tabBarHandle = self.addWidget(self.tabBar)
        self.tabBar.setUsesScrollButtons(True)

        self.cornerActions = QFrame(self)
        self.cornerActions.setFrameShape(QFrame.NoFrame)
        self.cornerActions.setLineWidth(0)
        self.cornerActions.setContentsMargins(0, 0, 0, 0)
        self.cornerActions.setSizePolicy(QSizePolicy.Preferred,
                                         QSizePolicy.Minimum)
        self.cornerLayout = QHBoxLayout(self.cornerActions)

        self.cornerLayout.setContentsMargins(0, 0, 0, 0)
        self.cornerLayout.setSpacing(0)
        self.cornerLayout.setDirection(QBoxLayout.LeftToRight)
        self.cornerActions.setLayout(self.cornerLayout)

        self.hideAction = QAction(self)
        self.hideAction.setCheckable(True)
        self.hideAction.setText("▲")
        self.hideButton = QToolButton(self.tabBar)
        self.hideButton.setProperty("TTHide", QtCore.QVariant(True))
        self.hideButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextOnly)
        self.hideButton.setDefaultAction(self.hideAction)
        self.hideButton.setAutoRaise(True)
        self.hideButton.setSizePolicy(QSizePolicy.Expanding,
                                      QSizePolicy.Expanding)

        self.hideAction.triggered.connect(self._hideaction)
        self.tabBar.tabBarDoubleClicked.connect(self.hideAction.trigger)
        self.tabBar.tabBarClicked.connect(self.current_tabchanged)
        self.tabBar.currentChanged.connect(self.focus_changed)
        self.cornerLayout.addWidget(self.hideButton)
        self.tabBar.setCornerWidget(self.cornerActions)
        self.set_style(style.get_defaultstyle())

    def _hideaction(self):
        # self.tempShowTimer.start()
        self._is_minimized = self.hideAction.isChecked()
        self.hideAction.setText("▼" if self._is_minimized else "▲")
        self.hide_at(self.tabBar.currentIndex())
        if self._is_minimized:
            self.Minimized.emit()
        else:
            self.Maximized.emit()

    def event(self, event: QtCore.QEvent):
        if event.type(
        ) == QtCore.QEvent.StyleChange and not self.ignore_styleevent:
            # TODO: Validatre if we need a timer
            stylename = (self._style.objectName()
                         if self._style else style.get_defaultstyle())
            self.set_style(stylename)
        return super(TabToolbar, self).event(event)

    def focus_changed(self, old: QWidget = None, now: QWidget = None):
        if now and now != self:
            if self.isMinimized() and self.is_shown:
                parent = now
                while parent:
                    parent = parent.parent()
                    if parent == self:
                        return
                self.hide_at(self.current_index)

    def rowcount(self):
        return self.group_rowcount

    def group_maxheight(self):
        return self.group_maxheight * style.get_scalefactor(self)

    def set_style(self, stylename: str):
        self.ignore_styleevent = True
        self._style = style.create_style(stylename)
        stylesheet = style.get_stylesheet(self._style)
        self.setStyleSheet(stylesheet)
        self.ignore_styleevent = False
        self.StyleChanged.emit()

    def get_style(self) -> str:
        if self._style:
            return self._style.objectName()
        return ""

    def add_corneraction(self, action: QAction):
        action_button = QToolButton(self.tabBar)
        action_button.setProperty("TTInternal", QtCore.QVariant(True))
        action_button.setToolButtonStyle(QtCore.Qt.ToolButtonIconOnly)
        action_button.setDefaultAction(action)
        action_button.setAutoRaise(True)
        action_button.setSizePolicy(QSizePolicy.Expanding,
                                    QSizePolicy.Expanding)
        self.cornerActions.layout().addWidget(action_button)

    def set_specialtabenabled(self, enabled: bool):
        self.has_specialtab = enabled
        self.tabBar.tabBar().setProperty("TTSpecial", QtCore.QVariant(enabled))
        if enabled and self.tabBar.count() > 0:
            self.tabBar.setCurrentIndex(1)

    def hide_action(self) -> QAction:
        return self.hideAction

    def tab_clicked(self, index: int):
        if self.tempShowTimer.isActive() or (index == 0
                                             and self.has_specialtab):
            return
        if self._is_minimized:
            if self.is_shown and index != self.current_index:
                return
            self._is_minimized = self.is_shown
            self.hide_at(index)
            self._is_minimized = True

    def current_tabchanged(self, index: int):
        QtCore.QSignalBlocker(self.tabBar)
        if index == 0 and self.has_specialtab:
            self.tabBar.setCurrentIndex(self.current_index)
            self.SpecialTabClicked.emit()
        else:
            self.current_index = index

    @property
    def current_tab(self) -> int:
        return self.current_index

    def set_currenttab(self, index: int):
        self.tabBar.setCurrentIndex(index)

    def hide_at(self, index: int):
        if self._is_minimized:
            minheight = self.tabBar.tabBar().height() + 2
            self.tabBar.setMaximumHeight(minheight)
            self.tabBar.setMinimumHeight(minheight)
            self.setMaximumHeight(minheight)
            self.setMinimumHeight(minheight)
            self.is_shown = False
        else:
            self.tabBar.setCurrentIndex(index)
            if not self.is_shown:
                self.tabBar.setMaximumHeight(self.maxheight)
                self.tabBar.setMinimumHeight(self.maxheight)
                self.setMaximumHeight(self.maxheight)
                self.setMinimumHeight(self.maxheight)
                self.tabBar.adjustSize()
            self.setFocus()
            self.is_shown = True

    def hide_tab(self, index: int):
        page = self.sender()
        QtCore.QSignalBlocker(page)
        for i in range(self.tabBar.count()):
            if self.tabBar.widget(i) == page:
                self.tabBar.removeTab(i)
                return
        self.current_index = self.tabBar.currentIndex()

    @QtCore.pyqtSlot(int)
    def _adjustverticalsize(self, vsize: int):
        self.maxheight = vsize + self.tabBar.tabBar().height() + 6
        self.setMaximumHeight(self.maxheight)
        self.setMinimumHeight(self.maxheight)

    def adjust_verticalsize(self, vsize: int):
        QtCore.QTimer.singleShot(0, lambda: self._adjustverticalsize(vsize)
                                 )  # type: ignore[attr-defined]
        # self._AdjustVerticleSize(vSize)

    def show_tab(self, index: int):
        tab_page = self.sender()
        QtCore.QSignalBlocker(tab_page)
        self.tabBar.insertTab(index, tab_page, tab_page.objectName())
        self.current_index = self.tabBar.currentIndex()

    def add_page(self, page_name: str) -> page.Page:
        tab_page = page.Page(self.tabBar.count(), page_name)
        QtCore.QSignalBlocker(tab_page)
        tab_page.Hiding.connect(self.hide_tab)
        tab_page.Showing.connect(self.show_tab)
        self.tabBar.addTab(tab_page, page_name)
        return tab_page
コード例 #5
0
        super(TabCornerWidget, self).resizeEvent(event)
        # 更新按钮高度
        if hasattr(self, 'buttonAdd'):
            self.buttonAdd.setFixedSize(self.height(), self.height())


if __name__ == '__main__':
    import sys

    app = QApplication(sys.argv)
    app.setStyle(TabCornerStyle())

    tab1 = QTabWidget()
    cor1 = TabCornerWidget(tab1)
    cor1.signalTabAdd.connect(lambda: tab1.addTab(QWidget(tab1), 'tab' + str(tab1.count() + 1)))
    tab1.setCornerWidget(cor1, Qt.TopRightCorner)
    tab1.show()

    tab2 = QTabWidget()
    tab2.setTabPosition(QTabWidget.South)  # tab 标签方向
    cor2 = TabCornerWidget(tab2)
    cor2.signalTabAdd.connect(lambda: tab2.addTab(QWidget(tab2), 'tab' + str(tab2.count() + 1)))
    tab2.setCornerWidget(cor2, Qt.BottomRightCorner)
    tab2.show()

    for i in range(10):
        tab1.addTab(QWidget(tab1), 'tab' + str(i + 1))
        tab2.addTab(QWidget(tab1), 'tab' + str(i + 1))

    sys.exit(app.exec_())
コード例 #6
0
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
コード例 #7
0
class MainWindow(QMainWindow):
    """Show the main window of SCCT."""

    EXIT_CODE_REBOOT = -123

    def __init__(self, controller, app, showChangelog):
        """Init the main window."""
        try:
            super().__init__()

            self._save = True
            self.tlock = TriggerLock()
            self.controller = controller

            self.max_no_sets = scctool.settings.max_no_sets
            self.scoreWidth = 35
            self.raceWidth = 45
            self.labelWidth = 25
            self.mimumLineEditWidth = 130

            self.createTabs()
            self.createMatchDataTabs()
            self.createHorizontalGroupBox()
            self.createLowerTabWidget()

            self.createMenuBar()

            mainLayout = QVBoxLayout()
            mainLayout.addWidget(self.tabs, 0)
            mainLayout.addWidget(self.matchDataTabWidget, 1)
            # mainLayout.addWidget(self.fromMatchDataBox, 1)
            mainLayout.addWidget(self.lowerTabWidget, 0)
            mainLayout.addWidget(self.horizontalGroupBox, 0)

            self.setWindowTitle("StarCraft Casting Tool v{}".format(
                scctool.__version__))

            self.window = QWidget()
            self.window.setLayout(mainLayout)
            self.setCentralWidget(self.window)

            # self.size
            self.statusBar()

            self.leds = dict()
            for scope in self.controller.websocketThread.get_primary_scopes():
                self.leds[scope] = LedIndicator(self)

            for key, led in self.leds.items():
                self.controller.toogleLEDs(0, key, self)
                self.statusBar().addPermanentWidget(led)

            self.app = app
            self.controller.setView(self)
            self.controller.refreshButtonStatus()

            self.processEvents()
            self.settings = QSettings(ClientConfig.APP_NAME,
                                      ClientConfig.COMPANY_NAME)
            self.restoreGeometry(
                self.settings.value("geometry", self.saveGeometry()))
            self.restoreState(
                self.settings.value("windowState", self.saveState()))

            self.mysubwindows = dict()

            self.show()
            self.raise_()

            if showChangelog:
                self.openChangelog()

        except Exception as e:
            module_logger.exception("message")

    def showAbout(self):
        """Show subwindow with about info."""
        html = markdown2.markdown_path(scctool.settings.getResFile("about.md"))

        html = html.replace("%VERSION%", scctool.__version__)
        if (not scctool.__new_version__):
            new_version = _("StarCraft Casting Tool is up to date.")
        else:
            new_version = _("The new version {} is available!").format(
                scctool.__latest_version__)
        html = html.replace('%NEW_VERSION%', new_version)

        # use self as parent here
        QMessageBox.about(self, _("StarCraft Casting Tool - About"), html)

    def closeEvent(self, event):
        """Close and clean up window."""
        try:
            try:
                for name, window in self.mysubwindows.items():
                    if (window and window.isVisible()):
                        window.close()
            finally:
                self.settings.setValue("geometry", self.saveGeometry())
                self.settings.setValue("windowState", self.saveState())
                self.controller.cleanUp(self._save)
                QMainWindow.closeEvent(self, event)
                # event.accept()
        except Exception as e:
            module_logger.exception("message")

    def createMenuBar(self):
        """Create the menu bar."""
        try:
            menubar = self.menuBar()
            settingsMenu = menubar.addMenu(_('Settings'))

            apiAct = QAction(QIcon(scctool.settings.getResFile('browser.png')),
                             _('Browser Sources'), self)
            apiAct.setToolTip(_('Edit Settings for all Browser Sources'))
            apiAct.triggered.connect(self.openBrowserSourcesDialog)
            settingsMenu.addAction(apiAct)
            apiAct = QAction(QIcon(scctool.settings.getResFile('twitch.png')),
                             _('Twitch && Nightbot'), self)
            apiAct.setToolTip(
                _('Edit Intro-Settings and API-Settings'
                  ' for Twitch and Nightbot'))
            apiAct.triggered.connect(self.openApiDialog)
            settingsMenu.addAction(apiAct)
            styleAct = QAction(
                QIcon(scctool.settings.getResFile('pantone.png')), _('Styles'),
                self)
            styleAct.setToolTip('')
            styleAct.triggered.connect(self.openStyleDialog)
            settingsMenu.addAction(styleAct)
            miscAct = QAction(
                QIcon(scctool.settings.getResFile('settings.png')), _('Misc'),
                self)
            miscAct.setToolTip('')
            miscAct.triggered.connect(self.openMiscDialog)
            settingsMenu.addAction(miscAct)

            self.createBrowserSrcMenu()

            ProfileMenu(self, self.controller)

            self.createLangMenu()

            infoMenu = menubar.addMenu(_('Info && Links'))

            myAct = QAction(QIcon(scctool.settings.getResFile('about.png')),
                            _('About'), self)
            myAct.triggered.connect(self.showAbout)
            infoMenu.addAction(myAct)

            myAct = QAction(QIcon(scctool.settings.getResFile('readme.ico')),
                            _('Readme'), self)
            myAct.triggered.connect(self.openReadme)
            infoMenu.addAction(myAct)

            websiteAct = QAction(
                QIcon(scctool.settings.getResFile('youtube.png')),
                _('Video Tutorial'), self)
            websiteAct.triggered.connect(lambda: self.controller.openURL(
                "https://youtu.be/j5iWa4JB8bM"))
            infoMenu.addAction(websiteAct)

            myAct = QAction(QIcon(scctool.settings.getResFile('update.png')),
                            _('Check for new version'), self)
            myAct.triggered.connect(lambda: self.controller.checkVersion(True))
            infoMenu.addAction(myAct)

            myAct = QAction(
                QIcon(scctool.settings.getResFile('changelog.png')),
                _('Changelog'), self)
            myAct.triggered.connect(self.openChangelog)
            infoMenu.addAction(myAct)

            myAct = QAction(QIcon(scctool.settings.getResFile('folder.png')),
                            _('Open log folder'), self)
            myAct.triggered.connect(lambda: self.controller.open_file(
                scctool.settings.getAbsPath(scctool.settings.getLogDir())))
            infoMenu.addAction(myAct)

            infoMenu.addSeparator()

            websiteAct = QAction(
                QIcon(scctool.settings.getResFile('scct.ico')),
                'StarCraft Casting Tool', self)
            websiteAct.triggered.connect(lambda: self.controller.openURL(
                "https://teampheenix.github.io/StarCraft-Casting-Tool/"))
            infoMenu.addAction(websiteAct)

            discordAct = QAction(
                QIcon(scctool.settings.getResFile('discord.png')), 'Discord',
                self)
            discordAct.triggered.connect(
                lambda: self.controller.openURL("https://discord.gg/G9hFEfh"))
            infoMenu.addAction(discordAct)

            ixAct = QAction(QIcon(scctool.settings.getResFile('icon.png')),
                            'team pheeniX', self)
            ixAct.triggered.connect(
                lambda: self.controller.openURL("http://team-pheenix.de"))
            infoMenu.addAction(ixAct)

            alphaAct = QAction(QIcon(scctool.settings.getResFile('alpha.png')),
                               'AlphaTL', self)
            alphaAct.triggered.connect(
                lambda: self.controller.openURL("https://alpha.tl"))
            infoMenu.addAction(alphaAct)

            rstlAct = QAction(QIcon(scctool.settings.getResFile('rstl.png')),
                              'RSTL', self)
            rstlAct.triggered.connect(
                lambda: self.controller.openURL("http://hdgame.net/en/"))
            infoMenu.addAction(rstlAct)

            infoMenu.addSeparator()

            myAct = QAction(QIcon(scctool.settings.getResFile('patreon.png')),
                            _('Become a Patron'), self)
            myAct.triggered.connect(lambda: self.controller.openURL(
                "https://www.patreon.com/StarCraftCastingTool"))
            infoMenu.addAction(myAct)

            myAct = QAction(QIcon(scctool.settings.getResFile('donate.ico')),
                            _('Donate via PayPal'), self)
            myAct.triggered.connect(lambda: self.controller.openURL(
                "https://paypal.me/StarCraftCastingTool"))
            infoMenu.addAction(myAct)

        except Exception as e:
            module_logger.exception("message")

    def createLangMenu(self):
        menubar = self.menuBar()

        langMenu = menubar.addMenu(_('Language'))

        language = scctool.settings.config.parser.get("SCT", "language")

        languages = []
        languages.append({
            'handle': 'de_DE',
            'icon': 'de.png',
            'name': 'Deutsch',
            'active': True
        })
        languages.append({
            'handle': 'en_US',
            'icon': 'en.png',
            'name': 'English',
            'active': True
        })
        languages.append({
            'handle': 'fr_FR',
            'icon': 'fr.png',
            'name': 'Français',
            'active': True
        })
        languages.append({
            'handle': 'ru_RU',
            'icon': 'ru.png',
            'name': 'Pусский',
            'active': True
        })

        for lang in languages:
            myAct = QAction(QIcon(scctool.settings.getResFile(lang['icon'])),
                            lang['name'],
                            self,
                            checkable=True)
            myAct.setChecked(language == lang['handle'])
            myAct.setDisabled(not lang['active'])
            myAct.triggered.connect(
                lambda x, handle=lang['handle']: self.changeLanguage(handle))
            langMenu.addAction(myAct)

    def createBrowserSrcMenu(self):
        menubar = self.menuBar()
        main_menu = menubar.addMenu(_('Browser Sources'))

        srcs = []
        srcs.append({
            'name': _('Intro'),
            'file': 'intro.html',
            'settings': lambda: self.openBrowserSourcesDialog('intro')
        })
        srcs.append({
            'name':
            _('Mapstats'),
            'file':
            'mapstats.html',
            'settings':
            lambda: self.openBrowserSourcesDialog('mapstats')
        })
        srcs.append({'name': _('Score'), 'file': 'score.html'})
        srcs.append({
            'name':
            _('Map Icons Box'),
            'settings':
            lambda: self.openBrowserSourcesDialog('mapicons_box'),
            'sub': [{
                'name': _('Icon Set {}').format(1),
                'file': 'mapicons_box_1.html'
            }, {
                'name': _('Icon Set {}').format(2),
                'file': 'mapicons_box_2.html'
            }, {
                'name': _('Icon Set {}').format(3),
                'file': 'mapicons_box_3.html'
            }]
        })
        srcs.append({
            'name':
            _('Map Icons Landscape'),
            'settings':
            lambda: self.openBrowserSourcesDialog("mapicons_landscape"),
            'sub': [{
                'name': _('Icon Set {}').format(1),
                'file': 'mapicons_landscape_1.html'
            }, {
                'name': _('Icon Set {}').format(2),
                'file': 'mapicons_landscape_2.html'
            }, {
                'name': _('Icon Set {}').format(3),
                'file': 'mapicons_landscape_3.html'
            }]
        })
        srcs.append({
            'name':
            _('Misc'),
            'sub': [{
                'name': _('Logo {}').format(1),
                'file': 'logo1.html'
            }, {
                'name': _('Logo {}').format(2),
                'file': 'logo2.html'
            }, {
                'name': _('UI Logo {}').format(1),
                'file': 'ui_logo_1.html'
            }, {
                'name': _('UI Logo {}').format(2),
                'file': 'ui_logo_2.html'
            }, {
                'name': _('Aligulac (only 1vs1)'),
                'file': 'aligulac.html'
            }, {
                'name': _('Countdown'),
                'file': 'countdown.html'
            }, {
                'name': _('League (ALphaTL && RSTL only)'),
                'file': 'league.html'
            }, {
                'name': _('Matchbanner (AlphaTL)'),
                'file': 'matchbanner.html',
                'settings': lambda: self.openMiscDialog('alphatl')
            }]
        })

        act = QAction(QIcon(scctool.settings.getResFile('folder.png')),
                      _('Open Folder'), self)
        act.triggered.connect(lambda: self.controller.open_file(
            scctool.settings.getAbsPath(scctool.settings.casting_html_dir)))
        main_menu.addAction(act)
        main_menu.addSeparator()

        for src in srcs:
            myMenu = QMenu(src['name'], self)
            sub = src.get('sub', False)
            if sub:
                for icon in sub:
                    mySubMenu = QMenu(icon['name'], self)
                    icon['file'] = os.path.join(
                        scctool.settings.casting_html_dir, icon['file'])
                    act = QAction(
                        QIcon(scctool.settings.getResFile('html.png')),
                        _('Open in Browser'), self)
                    act.triggered.connect(
                        lambda x, file=icon['file']: self.controller.openURL(
                            scctool.settings.getAbsPath(file)))
                    mySubMenu.addAction(act)
                    act = QAction(
                        QIcon(scctool.settings.getResFile('copy.png')),
                        _('Copy URL to Clipboard'), self)
                    act.triggered.connect(
                        lambda x, file=icon['file']: QApplication.clipboard(
                        ).setText(scctool.settings.getAbsPath(file)))
                    mySubMenu.addAction(act)
                    if icon.get('settings', None) is not None:
                        act = QAction(
                            QIcon(scctool.settings.getResFile('browser.png')),
                            _('Settings'), self)
                        act.triggered.connect(icon['settings'])
                        mySubMenu.addAction(act)
                    myMenu.addMenu(mySubMenu)
            else:
                src['file'] = os.path.join(scctool.settings.casting_html_dir,
                                           src['file'])
                act = QAction(QIcon(scctool.settings.getResFile('html.png')),
                              _('Open in Browser'), self)
                act.triggered.connect(
                    lambda x, file=src['file']: self.controller.openURL(
                        scctool.settings.getAbsPath(file)))
                myMenu.addAction(act)
                act = QAction(QIcon(scctool.settings.getResFile('copy.png')),
                              _('Copy URL to Clipboard'), self)
                act.triggered.connect(
                    lambda x, file=src['file']: QApplication.clipboard(
                    ).setText(scctool.settings.getAbsPath(file)))
                myMenu.addAction(act)

            if src.get('settings', None) is not None:
                act = QAction(
                    QIcon(scctool.settings.getResFile('browser.png')),
                    _('Settings'), self)
                act.triggered.connect(src['settings'])
                myMenu.addAction(act)
            main_menu.addMenu(myMenu)

        main_menu.addSeparator()

        apiAct = QAction(QIcon(scctool.settings.getResFile('browser.png')),
                         _('Settings'), self)
        apiAct.setToolTip(_('Edit Settings for all Browser Sources'))
        apiAct.triggered.connect(self.openBrowserSourcesDialog)
        main_menu.addAction(apiAct)

        styleAct = QAction(QIcon(scctool.settings.getResFile('pantone.png')),
                           _('Styles'), self)
        styleAct.setToolTip('')
        styleAct.triggered.connect(self.openStyleDialog)
        main_menu.addAction(styleAct)

    def openApiDialog(self):
        """Open subwindow with connection settings."""
        self.mysubwindows['connections'] = SubwindowConnections()
        self.mysubwindows['connections'].createWindow(self)
        self.mysubwindows['connections'].show()

    def openStyleDialog(self):
        """Open subwindow with style settings."""
        self.mysubwindows['styles'] = SubwindowStyles()
        self.mysubwindows['styles'].createWindow(self)
        self.mysubwindows['styles'].show()

    def openMiscDialog(self, tab=''):
        """Open subwindow with misc settings."""
        self.mysubwindows['misc'] = SubwindowMisc()
        self.mysubwindows['misc'].createWindow(self, tab)
        self.mysubwindows['misc'].show()

    def openBrowserSourcesDialog(self, tab=''):
        """Open subwindow with misc settings."""
        self.mysubwindows['browser'] = SubwindowBrowserSources()
        self.mysubwindows['browser'].createWindow(self, tab)
        self.mysubwindows['browser'].show()

    def openReadme(self):
        """Open subwindow with readme viewer."""
        self.mysubwindows['readme'] = SubwindowMarkdown()
        self.mysubwindows['readme'].createWindow(
            self, _("Readme"), scctool.settings.getResFile('readme.ico'),
            scctool.settings.getResFile("../README.md"))
        self.mysubwindows['readme'].show()

    def openChangelog(self):
        """Open subwindow with readme viewer."""
        self.mysubwindows['changelog'] = SubwindowMarkdown()
        self.mysubwindows['changelog'].createWindow(
            self, "StarCraft Casting Tool " + _("Changelog"),
            scctool.settings.getResFile("changelog.png"),
            scctool.settings.getResFile("../CHANGELOG.md"))
        self.mysubwindows['changelog'].show()

    def changeLanguage(self, language):
        """Change the language."""
        scctool.settings.config.parser.set("SCT", "language", language)
        self.restart()

    def updateAllMapCompleters(self):
        for idx in range(self.matchDataTabWidget.count()):
            self.matchDataTabWidget.widget(idx).updateMapCompleters()

    def updateAllPlayerCompleters(self):
        for idx in range(self.matchDataTabWidget.count()):
            self.matchDataTabWidget.widget(idx).updatePlayerCompleters()

    def updateAllMapButtons(self):
        for idx in range(self.matchDataTabWidget.count()):
            self.matchDataTabWidget.widget(idx).updateMapButtons()

    def createMatchDataTabs(self):
        self.matchDataTabWidget = QTabWidget()
        self.matchDataTabWidget.setMovable(True)
        closeable = self.controller.matchControl.countMatches() > 1
        self.matchDataTabWidget.setUsesScrollButtons(True)
        for match in self.controller.matchControl.getMatches():
            MatchDataWidget(self, self.matchDataTabWidget, match, closeable)

        container = QWidget()
        buttonLayout = QHBoxLayout()
        buttonLayout.setContentsMargins(2, 1, 1, 2)
        buttonLayout.setSpacing(1)
        button = QPushButton()
        pixmap = QIcon(scctool.settings.getResFile('add.png'))
        button.setIcon(pixmap)
        button.setFixedSize(28, 28)
        # button.setFlat(True)
        button.setToolTip(_('Add Match Tab'))
        button.clicked.connect(self.addMatchTab)
        buttonLayout.addWidget(button)
        button = QPushButton()
        button.setFixedSize(28, 28)
        pixmap = QIcon(scctool.settings.getResFile('copy.png'))
        button.setIcon(pixmap)
        # button.setFlat(True)
        button.setToolTip(_('Copy Match Tab'))
        button.clicked.connect(self.copyMatchTab)
        buttonLayout.addWidget(button)
        container.setLayout(buttonLayout)
        self.matchDataTabWidget.setCornerWidget(container)

        tabBar = self.matchDataTabWidget.tabBar()
        tabBar.setExpanding(True)
        self.matchDataTabWidget.currentChanged.connect(
            self.currentMatchTabChanged)
        tabBar.tabMoved.connect(self.tabMoved)

    def addMatchTab(self):
        match = self.controller.matchControl.newMatchData()
        MatchDataWidget(self, self.matchDataTabWidget, match)
        count = self.matchDataTabWidget.count()
        self.matchDataTabWidget.setCurrentIndex(count - 1)
        if count > 1:
            for idx in range(count):
                self.matchDataTabWidget.widget(idx).setClosable(True)

    def copyMatchTab(self):
        matchId = self.controller.matchControl.selectedMatchId()
        data = self.controller.matchControl.selectedMatch().getData()
        match = self.controller.matchControl.newMatchData(data)
        self.controller.logoManager.copyMatch(match.getControlID(), matchId)
        MatchDataWidget(self, self.matchDataTabWidget, match)
        count = self.matchDataTabWidget.count()
        self.matchDataTabWidget.setCurrentIndex(count - 1)
        if count > 1:
            for idx in range(count):
                self.matchDataTabWidget.widget(idx).setClosable(True)

    def currentMatchTabChanged(self, idx):
        dataWidget = self.matchDataTabWidget.widget(idx)
        ident = dataWidget.matchData.getControlID()
        self.controller.matchControl.selectMatch(ident)
        with self.tlock:
            self.controller.updateMatchFormat()

    def tabMoved(self, toIdx, fromIdx):
        self.controller.matchControl.updateOrder(toIdx, fromIdx)

    def createTabs(self):
        """Create tabs in main window."""
        try:
            # Initialize tab screen
            self.tabs = QTabWidget()
            self.tab1 = QWidget()
            self.tab2 = QWidget()
            # self.tabs.resize(300,200)

            # Add tabs
            self.tabs.addTab(self.tab1, _("Match Grabber for AlphaTL && RSTL"))
            self.tabs.addTab(self.tab2, _("Custom Match"))

            # Create first tab
            self.tab1.layout = QVBoxLayout()

            self.le_url = MatchComboBox(self)
            self.le_url.returnPressed.connect(self.refresh_click)

            minWidth = self.scoreWidth + 2 * self.raceWidth + \
                2 * self.mimumLineEditWidth + 4 * 6
            self.le_url.setMinimumWidth(minWidth)

            self.pb_openBrowser = QPushButton(_("Open in Browser"))
            self.pb_openBrowser.clicked.connect(self.openBrowser_click)
            width = (self.scoreWidth + 2 * self.raceWidth +
                     2 * self.mimumLineEditWidth + 4 * 6) / 2 - 2
            self.pb_openBrowser.setMinimumWidth(width)

            container = QHBoxLayout()
            label = QLabel()
            label.setFixedWidth(self.labelWidth)
            container.addWidget(label, 0)
            label = QLabel(_("Match-URL:"))
            label.setMinimumWidth(80)
            container.addWidget(label, 0)
            container.addWidget(self.le_url, 1)
            button = QPushButton()
            pixmap = QIcon(scctool.settings.getResFile('alpha.png'))
            button.setIcon(pixmap)
            button.clicked.connect(
                lambda: self.controller.openURL("https://alpha.tl/"))
            container.addWidget(button, 0)
            button = QPushButton()
            pixmap = QIcon(scctool.settings.getResFile('rstl.png'))
            button.setIcon(pixmap)
            button.clicked.connect(
                lambda: self.controller.openURL("http://hdgame.net/en/"))
            container.addWidget(button, 0)

            self.tab1.layout = QFormLayout()
            self.tab1.layout.addRow(container)

            container = QHBoxLayout()

            # self.pb_download = QPushButton("Download Images from URL")
            # container.addWidget(self.pb_download)
            label = QLabel()
            label.setFixedWidth(self.labelWidth)
            container.addWidget(label, 0)
            label = QLabel()
            label.setMinimumWidth(80)
            container.addWidget(label, 0)
            self.pb_refresh = QPushButton(_("Load Data from URL"))
            self.pb_refresh.clicked.connect(self.refresh_click)
            container.addWidget(self.pb_openBrowser, 3)
            container.addWidget(self.pb_refresh, 3)

            self.tab1.layout.addRow(container)
            self.tab1.setLayout(self.tab1.layout)

            # Create second tab

            self.tab2.layout = QVBoxLayout()

            container = QHBoxLayout()

            label = QLabel()
            label.setMinimumWidth(self.labelWidth)
            container.addWidget(label, 0)

            label = QLabel(_("Match Format:"))
            label.setMinimumWidth(80)
            container.addWidget(label, 0)

            container.addWidget(QLabel(_("Best of")), 0)

            self.cb_bestof = QComboBox()
            for idx in range(0, scctool.settings.max_no_sets):
                self.cb_bestof.addItem(str(idx + 1))
            self.cb_bestof.setCurrentIndex(3)
            string = _('"Best of 6/4": First, a Bo5/3 is played and the'
                       ' ace map gets extended to a Bo3 if needed;'
                       ' Best of 2: Bo3 with only two maps played.')
            self.cb_bestof.setToolTip(string)
            self.cb_bestof.setMaximumWidth(40)
            self.cb_bestof.currentIndexChanged.connect(self.changeBestOf)
            container.addWidget(self.cb_bestof, 0)

            container.addWidget(QLabel(_(" but at least")), 0)

            self.cb_minSets = QComboBox()

            self.cb_minSets.setToolTip(
                _('Minimum number of maps played (even if the match'
                  ' is decided already)'))
            self.cb_minSets.setMaximumWidth(40)
            container.addWidget(self.cb_minSets, 0)
            container.addWidget(QLabel(" " + _("maps") + "  "), 0)
            self.cb_minSets.currentIndexChanged.connect(
                lambda idx: self.highlightApplyCustom())

            self.cb_allkill = QCheckBox(_("All-Kill Format"))
            self.cb_allkill.setChecked(False)
            self.cb_allkill.setToolTip(
                _('Winner stays and is automatically'
                  ' placed into the next set'))
            self.cb_allkill.stateChanged.connect(self.allkill_change)
            container.addWidget(self.cb_allkill, 0)

            self.cb_solo = QCheckBox(_("1vs1"))
            self.cb_solo.setChecked(False)
            self.cb_solo.setToolTip(_('Select for solo (non-team matches)'))
            container.addWidget(self.cb_solo, 0)
            self.cb_solo.stateChanged.connect(
                lambda idx: self.highlightApplyCustom())

            label = QLabel("")
            container.addWidget(label, 1)

            self.applycustom_is_highlighted = False

            self.pb_applycustom = QToolButton()
            action = QAction(_("Apply Format"))
            action.triggered.connect(self.applycustom_click)
            self.pb_applycustom.setDefaultAction(action)
            self.custom_menu = QMenu(self.pb_applycustom)
            for format, icon in \
                    self.controller.matchControl.getCustomFormats():
                if icon:
                    action = self.custom_menu.addAction(
                        QIcon(scctool.settings.getResFile(icon)), format)
                else:
                    action = self.custom_menu.addAction(format)
                action.triggered.connect(
                    lambda x, format=format: self.applyCustomFormat(format))
            self.pb_applycustom.setMenu(self.custom_menu)
            self.pb_applycustom.setPopupMode(QToolButton.MenuButtonPopup)

            self.pb_applycustom.setFixedWidth(150)
            container.addWidget(self.pb_applycustom, 0)

            self.defaultButtonPalette = self.pb_applycustom.palette()

            self.tab2.layout.addLayout(container)

            container = QHBoxLayout()

            label = QLabel()
            label.setMinimumWidth(self.labelWidth)
            container.addWidget(label, 0)

            label = QLabel(_("Match-URL:"))
            label.setMinimumWidth(80)
            container.addWidget(label, 0)

            self.le_url_custom = MonitoredLineEdit()
            self.le_url_custom.setAlignment(Qt.AlignCenter)
            self.le_url_custom.setToolTip(
                _('Optionally specify the Match-URL,'
                  ' e.g., for Nightbot commands'))
            self.le_url_custom.setPlaceholderText(
                _("Specify the Match-URL of your Custom Match"))

            completer = QCompleter(["http://"], self.le_url_custom)
            completer.setCaseSensitivity(Qt.CaseInsensitive)
            completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
            completer.setWrapAround(True)
            self.le_url_custom.setCompleter(completer)
            self.le_url_custom.setMinimumWidth(360)
            self.le_url_custom.textModified.connect(self.highlightApplyCustom)

            container.addWidget(self.le_url_custom, 11)

            label = QLabel("")
            container.addWidget(label, 1)

            self.pb_resetdata = QPushButton(_("Reset Match Data"))
            self.pb_resetdata.setFixedWidth(150)
            self.pb_resetdata.clicked.connect(self.resetdata_click)
            container.addWidget(self.pb_resetdata, 0)

            self.tab2.layout.addLayout(container)

            self.tab2.setLayout(self.tab2.layout)

        except Exception as e:
            module_logger.exception("message")

    def allkill_change(self):
        try:
            self.controller.matchControl.\
                selectedMatch().setAllKill(self.cb_allkill.isChecked())
        except Exception as e:
            module_logger.exception("message")

    def changeBestOf(self, bestof):
        """Change the minimum sets combo box on change of BoX."""
        bestof = bestof + 1
        self.cb_minSets.clear()
        self.highlightApplyCustom()
        for idx in range(0, bestof):
            self.cb_minSets.addItem(str(idx + 1))
            if bestof == 2:
                self.cb_minSets.setCurrentIndex(1)
            else:
                self.cb_minSets.setCurrentIndex((bestof - 1) / 2)

    def createHorizontalGroupBox(self):
        """Create horizontal group box for tasks."""
        try:
            self.horizontalGroupBox = QGroupBox(_("Tasks"))
            layout = QHBoxLayout()

            self.pb_twitchupdate = QPushButton(_("Update Twitch Title"))
            self.pb_twitchupdate.clicked.connect(self.updatetwitch_click)

            self.pb_nightbotupdate = QPushButton(_("Update Nightbot"))
            self.pb_nightbotupdate.clicked.connect(self.updatenightbot_click)

            self.pb_resetscore = QPushButton(_("Reset Score"))
            self.pb_resetscore.clicked.connect(self.resetscore_click)

            layout.addWidget(self.pb_twitchupdate)
            layout.addWidget(self.pb_nightbotupdate)
            layout.addWidget(self.pb_resetscore)

            self.horizontalGroupBox.setLayout(layout)

        except Exception as e:
            module_logger.exception("message")

    def createLowerTabWidget(self):
        """Create the tab widget at the bottom."""
        try:
            self.lowerTabWidget = QTabWidget()
            self.createBackgroundTasksTab()
            self.countdownTab = CountdownWidget(self.controller, self)
            self.lowerTabWidget.addTab(self.backgroundTasksTab,
                                       _("Background Tasks"))
            self.lowerTabWidget.addTab(self.countdownTab, _("Countdown"))
        except Exception as e:
            module_logger.exception("message")

    def createBackgroundTasksTab(self):
        """Create group box for background tasks."""
        try:

            self.backgroundTasksTab = QWidget()

            self.cb_autoUpdate = QCheckBox(_("Auto Score Update"))
            self.cb_autoUpdate.setChecked(False)
            string = _('Automatically detects the outcome' +
                       ' of SC2 matches that are ' +
                       'played/observed in your SC2-client' +
                       ' and updates the score accordingly.')
            self.cb_autoUpdate.setToolTip(string)
            self.cb_autoUpdate.stateChanged.connect(self.autoUpdate_change)

            self.cb_autoToggleScore = QCheckBox(_("Set Ingame Score"))
            self.cb_autoToggleScore.setChecked(False)
            string = _('Automatically sets the score of your ingame' +
                       ' UI-interface at the begining of a game.')
            self.cb_autoToggleScore.setToolTip(string)
            self.cb_autoToggleScore.stateChanged.connect(
                self.autoToggleScore_change)

            self.cb_autoToggleProduction = QCheckBox(
                _("Toggle Production Tab"))
            self.cb_autoToggleProduction.setChecked(False)
            string = _('Automatically toggles the production tab of your' +
                       ' ingame UI-interface at the begining of a game.')
            self.cb_autoToggleProduction.setToolTip(string)
            self.cb_autoToggleProduction.stateChanged.connect(
                self.autoToggleProduction_change)

            self.cb_autoTwitch = QCheckBox(_("Auto Twitch Update"))
            self.cb_autoTwitch.setChecked(False)
            self.cb_autoTwitch.stateChanged.connect(self.autoTwitch_change)

            self.cb_autoNightbot = QCheckBox(_("Auto Nightbot Update"))
            self.cb_autoNightbot.setChecked(False)
            self.cb_autoNightbot.stateChanged.connect(self.autoNightbot_change)

            if (not scctool.settings.windows):
                self.cb_autoToggleScore.setEnabled(False)
                self.cb_autoToggleScore.setAttribute(Qt.WA_AlwaysShowToolTips)
                self.cb_autoToggleScore.setToolTip(_('Only Windows'))
                self.cb_autoToggleProduction.setEnabled(False)
                self.cb_autoToggleProduction.setAttribute(
                    Qt.WA_AlwaysShowToolTips)
                self.cb_autoToggleProduction.setToolTip(_('Only Windows'))

            layout = QGridLayout()

            layout.addWidget(self.cb_autoTwitch, 0, 0)
            layout.addWidget(self.cb_autoNightbot, 0, 1)

            layout.addWidget(self.cb_autoUpdate, 1, 0)
            layout.addWidget(self.cb_autoToggleScore, 1, 1)
            layout.addWidget(self.cb_autoToggleProduction, 1, 2)

            self.backgroundTasksTab.setLayout(layout)

        except Exception as e:
            module_logger.exception("message")

    def autoTwitch_change(self):
        """Handle change of auto twitch check box."""
        try:
            if (self.cb_autoTwitch.isChecked()):
                self.controller.autoRequestsThread.activateTask('twitch')
            else:
                self.controller.autoRequestsThread.deactivateTask('twitch')
        except Exception as e:
            module_logger.exception("message")

    def autoNightbot_change(self):
        """Handle change of auto twitch check box."""
        try:
            if (self.cb_autoNightbot.isChecked()):
                self.controller.autoRequestsThread.activateTask('nightbot')
            else:
                self.controller.autoRequestsThread.deactivateTask('nightbot')
        except Exception as e:
            module_logger.exception("message")

    def autoUpdate_change(self):
        """Handle change of auto score update check box."""
        try:
            if (self.cb_autoUpdate.isChecked()):
                self.controller.runSC2ApiThread("updateScore")
            else:
                self.controller.stopSC2ApiThread("updateScore")
        except Exception as e:
            module_logger.exception("message")

    def autoToggleScore_change(self):
        """Handle change of toggle score check box."""
        try:
            if (self.cb_autoToggleScore.isChecked()):
                self.controller.runSC2ApiThread("toggleScore")
            else:
                self.controller.stopSC2ApiThread("toggleScore")
        except Exception as e:
            module_logger.exception("message")

    def autoToggleProduction_change(self):
        """Handle change of toggle production tab check box."""
        try:
            if (self.cb_autoToggleProduction.isChecked()):
                self.controller.runSC2ApiThread("toggleProduction")
            else:
                self.controller.stopSC2ApiThread("toggleProduction")
        except Exception as e:
            module_logger.exception("message")

    def applyCustomFormat(self, format):
        """Handle click to apply custom format."""
        QApplication.setOverrideCursor(Qt.WaitCursor)
        try:
            with self.tlock:
                self.controller.matchControl.\
                    selectedMatch().applyCustomFormat(format)
                self.controller.updateMatchFormat()
                matchWidget = self.matchDataTabWidget.currentWidget()
                matchWidget.updateForms()
                self.resizeWindow()
            self.highlightApplyCustom(False)
        except Exception as e:
            module_logger.exception("message")
        finally:
            QApplication.restoreOverrideCursor()

    def applycustom_click(self):
        """Handle click to apply custom match."""
        QApplication.setOverrideCursor(Qt.WaitCursor)
        try:
            with self.tlock:
                self.statusBar().showMessage(_('Applying Custom Match...'))
                msg = self.controller.applyCustom(
                    int(self.cb_bestof.currentText()),
                    self.cb_allkill.isChecked(), self.cb_solo.isChecked(),
                    int(self.cb_minSets.currentText()),
                    self.le_url_custom.text().strip())
                self.statusBar().showMessage(msg)
            self.highlightApplyCustom(False)
        except Exception as e:
            module_logger.exception("message")
        finally:
            QApplication.restoreOverrideCursor()

    def resetdata_click(self):
        """Handle click to reset the data."""
        QApplication.setOverrideCursor(Qt.WaitCursor)
        try:
            with self.tlock:
                msg = self.controller.resetData()
                self.statusBar().showMessage(msg)
        except Exception as e:
            module_logger.exception("message")
        finally:
            QApplication.restoreOverrideCursor()

    def refresh_click(self):
        """Handle click to refresh/load data from an URL."""
        QApplication.setOverrideCursor(Qt.WaitCursor)
        try:
            url = self.le_url.lineEdit().text()
            with self.tlock:
                self.statusBar().showMessage(_('Reading {}...').format(url))
                msg = self.controller.refreshData(url)
                self.statusBar().showMessage(msg)
        except Exception as e:
            module_logger.exception("message")
        finally:
            QApplication.restoreOverrideCursor()

    def openBrowser_click(self):
        """Handle request to open URL in browser."""
        try:
            url = self.le_url.text()
            self.controller.openURL(url)
        except Exception as e:
            module_logger.exception("message")

    def updatenightbot_click(self):
        """Handle click to change nightbot command."""
        try:
            self.statusBar().showMessage(_('Updating Nightbot Command...'))
            msg = self.controller.updateNightbotCommand()
            self.statusBar().showMessage(msg)
        except Exception as e:
            module_logger.exception("message")

    def updatetwitch_click(self):
        """Handle click to change twitch title."""
        try:
            self.statusBar().showMessage(_('Updating Twitch Title...'))
            msg = self.controller.updateTwitchTitle()
            self.statusBar().showMessage(msg)
        except Exception as e:
            module_logger.exception("message")

    def resetscore_click(self, myteam=False):
        """Handle click to reset the score."""
        try:
            self.statusBar().showMessage(_('Resetting Score...'))
            with self.tlock:
                matchDataWidget = self.matchDataTabWidget.currentWidget()
                for set_idx in range(self.max_no_sets):
                    matchDataWidget.sl_score[set_idx].setValue(0)
                    self.controller.matchControl.selectedMatch().setMapScore(
                        set_idx, 0, overwrite=True)
                self.controller.autoSetNextMap()
                if myteam:
                    matchDataWidget.sl_team.setValue(0)
                    self.controller.matchControl.selectedMatch().setMyTeam(0)
                if not self.controller.resetWarning():
                    self.statusBar().showMessage('')

        except Exception as e:
            module_logger.exception("message")

    def highlightApplyCustom(self, highlight=True, force=False):
        if not force and not self.tlock.trigger():
            return
        try:
            if self.applycustom_is_highlighted == highlight:
                return highlight
        except AttributeError:
            return False

        if highlight:
            myPalette = self.pb_applycustom.palette()
            myPalette.setColor(QPalette.Background, Qt.darkBlue)
            myPalette.setColor(QPalette.ButtonText, Qt.darkBlue)
            self.pb_applycustom.setPalette(myPalette)
        else:
            self.pb_applycustom.setPalette(self.defaultButtonPalette)

        self.applycustom_is_highlighted = highlight
        return highlight

    def logoDialog(self, team, matchDataWidget):
        """Open dialog for team logo."""
        self.controller.logoManager.resetLogoChanged()
        self.mysubwindows['icons'] = SubwindowLogos()
        self.mysubwindows['icons'].createWindow(self, self.controller, team,
                                                matchDataWidget)
        self.mysubwindows['icons'].show()

    def resizeWindow(self):
        """Resize the window height to size hint."""
        if (not self.isMaximized()):
            self.processEvents()
            self.resize(self.width(), self.sizeHint().height())

    def processEvents(self):
        """Process ten PyQt5 events."""
        for i in range(0, 10):
            self.app.processEvents()

    def restart(self, save=True):
        """Restart the main window."""
        self._save = save
        self.close()
        self.app.exit(self.EXIT_CODE_REBOOT)
コード例 #8
0
ファイル: UI.py プロジェクト: Gabrielvth/BrinoPy
class Centro(QWidget):
    def __init__(self, parent=None):
        super(Centro, self).__init__()
        self.widget_abas = None
        self.menu = None
        self.indexer = None
        self.parent = parent
        self.pacotes = dict()
        self.temp_build = mkdtemp('build')
        self.temp_cache = mkdtemp('cache')
        self.log = None
        self.init_ui()

    # noinspection PyUnresolvedReferences
    def init_ui(self):
        # Define grid
        layout = QGridLayout(self)
        layout.setRowStretch(0, 7.5)
        layout.setRowStretch(1, 2.5)
        layout.setColumnMinimumWidth(0, 60)
        layout.setSpacing(5)
        layout.setContentsMargins(0, 0, 0, 0)

        # Cria menu
        self.menu = Menu.Menu(self)
        layout.addWidget(self.menu, 0, 0, 2, 2)

        # Botao para criar nova aba
        btn = QPushButton(self)
        btn.clicked.connect(self.nova_aba)
        btn.setStatusTip("Abrir nova aba")

        # Cria o widget abas
        self.widget_abas = QTabWidget(self.parent)
        self.widget_abas.tabCloseRequested.connect(self.remover_aba)
        self.widget_abas.setTabsClosable(False)
        self.widget_abas.setCornerWidget(btn, Qt.TopRightCorner)
        self.widget_abas.setStyleSheet("background:#252525;")
        layout.addWidget(self.widget_abas, 0, 1, 1, 2)

        # Cria log
        self.log = QPlainTextEdit(self)
        self.log.setStyleSheet(
            "border-radius:5px;background:#101010;margin-bottom:5px;margin-right:5px;"
        )
        self.log.setReadOnly(True)
        self.log.setStatusTip("Log")
        layout.addWidget(self.log, 1, 1, 1, 2)

        # Carrega pacotes de hardware
        self.init_pacotes()
        # Cria menu de placas
        self.criar_menu_placas()
        self.criar_menu_exemplos()

        # Adiciona a aba de boas vindas
        self.widget_abas.addTab(BoasVindas(self), "Bem-Vindo")
        self.show()

    def init_pacotes(self):
        """
        Carrega os pacotes de hardware do Arduino
        :return:
            None
        """
        pasta_hardware = os.path.join('builder', 'hardware')
        self.indexer = IndexadorContribuicao(os.path.join('builder'),
                                             pasta_hardware)
        self.indexer.parse_index()
        self.indexer.sincronizar_com_arquivos()
        self.carregar_hardware(pasta_hardware)
        self.carregar_hardware_contribuido(self.indexer)
        self.carregar_hardware(
            os.path.join(Main.get_caminho_padrao(), 'hardware'))

    def remover_aba(self, index, fechando=False):
        """
        Remove a aba
        :param index:
            Indice da aba
        :param fechando:
            Indica se o programa esta fechando
            default: False
        :return:
            None
        """
        if self.widget_abas.count() > 1 or fechando:
            # Se o index for argumento padrao do sinal (QT)
            if type(index) is not int:
                self.remover_aba(self.widget_abas.currentIndex())
            else:
                arquivo = self.widget_abas.widget(index)
                self.widget_abas.setCurrentIndex(index)
                if not arquivo.salvo:
                    ret = QMessageBox(self)
                    ret.setText(
                        "Gostaria de salvar este código antes de sair?")
                    ret.setIcon(QMessageBox.Question)
                    ret.addButton("Não Salvar", QMessageBox.NoRole)
                    ret.addButton("Cancelar", QMessageBox.RejectRole)
                    ret.addButton("Salvar", QMessageBox.AcceptRole)
                    ret = ret.exec_()
                    if ret == 1:
                        return False
                    elif ret == 2:
                        self.salvar()
                if arquivo is not None:
                    arquivo.deleteLater()
                self.widget_abas.removeTab(index)
        if self.widget_abas.count() == 1:
            self.widget_abas.setTabsClosable(False)

        return True

    def nova_aba(self, path="", salvar_caminho=True):
        """
        Criar nova aba de editor de texto
        :param path:
            Caminho para o arquivo a ser aberto
        :param salvar_caminho:
            Se o caminho deve ser definido como local para salvar
        :return:
            None
        """
        if self.widget_abas.count() == 0 or path:
            editor = EditorDeTexto.CodeEditor(self.widget_abas,
                                              False,
                                              path=path,
                                              salvar_caminho=salvar_caminho)
        else:
            editor = EditorDeTexto.CodeEditor(self.widget_abas,
                                              True,
                                              path=path,
                                              salvar_caminho=salvar_caminho)
        if self.widget_abas.count() == 1:
            self.widget_abas.setTabsClosable(True)
        identificador_aba = editor.get_nome()
        if len(identificador_aba) > 10:
            identificador_aba = identificador_aba[:10] + "..."
        editor.setStyleSheet("background:#252525")
        # Adiciona a aba se o arquivo tiver nome
        if editor.get_nome():
            self.widget_abas.addTab(editor, identificador_aba)
        if editor.get_nome() == "":
            self.remover_aba(self.widget_abas.count() - 1)
        else:
            self.widget_abas.setCurrentIndex(self.widget_abas.count() - 1)
        # Define que nao eh necessario salvar pois acabou de ser aberto
        editor.set_salvo(True)

    def abrir(self, caminho=None, exemplo=True):
        """
        Abrir arquivo .ino ou .brpp em nova aba
        :param caminho:
            endereço para abrir
        :return:
            None
        """
        if caminho is None or not caminho:
            salvar_caminho = True
            dialogo = self.criar_dialogo_arquivo("Abrir arquivo", "Abrir")
            if dialogo.exec_() == QFileDialog.Accepted:
                caminho = dialogo.selectedFiles()[0]
                # Testa se o arquivo existe
                if os.path.exists(caminho):
                    self.nova_aba(caminho, salvar_caminho)
                else:
                    QMessageBox(QMessageBox.Warning, "Erro",
                                "O arquivo não existe", QMessageBox.NoButton,
                                self).show()
        else:
            self.nova_aba(caminho)
            widget = self.widget_abas.widget(self.widget_abas.currentIndex())
            if exemplo:
                widget.caminho = ""

    def salvar(self):
        """
        Salvar arquivo da aba atual
        :return:
            None
        """
        editor = self.widget_abas.widget(self.widget_abas.currentIndex())
        caminho = editor.get_caminho()
        # Testa se a aba eh a de boas vindas
        if caminho == 0:
            return
        # Testa se a aba eh a de boas vindas
        editor.set_salvo(True)
        if caminho != "":
            if not os.path.exists(os.path.dirname(caminho)):
                try:
                    os.makedirs(os.path.dirname(caminho))
                except OSError as exc:  # Guard against race condition
                    if exc.errno != exc.errno.EEXIST:
                        raise
            with open(editor.get_caminho(), "w") as arquivo:
                arquivo.write(editor.get_texto())
        else:
            self.salvar_como()

    def salvar_como(self):
        """
        Salvar arquivo atual como
        :return:
            None
        """
        editor = self.widget_abas.widget(self.widget_abas.currentIndex())
        caminho = editor.get_caminho()
        # Testa se a aba eh a de boas vindas
        if caminho == 0:
            return
        caminho = editor.get_caminho()
        dialogo = self.criar_dialogo_arquivo('Salvar arquivo', 'Salvar')
        if dialogo.exec_() == QFileDialog.Accepted:
            caminho = dialogo.selectedFiles()[0]
            # Verifica se a pessoa selecionou a pasta ao inves do arquivo em si
            if not ntpath.basename(caminho).__contains__(".brpp"):
                caminho = os.path.join(caminho,
                                       ntpath.basename(caminho) + ".brpp")
            # Troca o identificador da aba
            identificador_aba = ntpath.basename(caminho).replace(".brpp", "")
            if len(identificador_aba) > 10:
                identificador_aba = identificador_aba[:10] + "..."
            self.widget_abas.setTabText(self.widget_abas.currentIndex(),
                                        identificador_aba)
            editor.set_caminho(caminho)
            self.salvar()

    def selecionar_texto(self, cursor, texto, indice_inicial, comprimento):
        """
        Seleciona texto
        :param cursor:
            Cursor do documento
        :param texto:
            Texto a ser selecionado
        :param indice_inicial:
            Ponto de onde comecar a busca
        :param comprimento:
            Tamanho do texto
        :return cursor:
            Cursor com a selecao
        """
        conteudo = self.widget_abas.widget(
            self.widget_abas.currentIndex()).toPlainText()
        indice_comeco = conteudo.find(texto, indice_inicial)
        if indice_comeco == -1:
            indice_comeco = conteudo.find(texto, 0)
        if not indice_comeco == -1:
            cursor.setPosition(indice_comeco, QTextCursor.MoveAnchor)
            cursor.setPosition(indice_comeco + comprimento,
                               QTextCursor.KeepAnchor)
            return cursor
        return -1

    def comentar_linha(self):
        """
        comenta a linha
        :return:
            None
        """
        editor = self.widget_abas.widget(self.widget_abas.currentIndex())
        caminho = editor.get_caminho()
        # Testa se a aba eh a de boas vindas
        if caminho == 0:
            return
        cursor_atual = editor.textCursor()
        posicao = cursor_atual.position()
        bloco_atual = cursor_atual.block()
        cursor = QTextCursor(bloco_atual)
        editor.setTextCursor(cursor)
        texto = bloco_atual.text()
        if texto.strip().startswith("//"):
            cursor = self.selecionar_texto(cursor, '/', cursor.position(), 2)
            cursor.removeSelectedText()
            cursor.setPosition(posicao - 2)
            editor.setTextCursor(cursor)
        else:
            editor.insertPlainText('//')
            cursor.setPosition(posicao + 2)
            editor.setTextCursor(cursor)

    def achar(self):
        """
        Achar palavra chave no codigo
        :return:
            None
        """
        editor = self.widget_abas.widget(self.widget_abas.currentIndex())
        caminho = editor.get_caminho()
        # Testa se a aba eh a de boas vindas
        if caminho == 0:
            return
        texto, ok = QInputDialog.getText(None, "Buscar", "Achar:")
        if ok and texto != "":
            cursor = editor.textCursor()
            cursor = self.selecionar_texto(cursor, texto, cursor.position(),
                                           len(texto))
            if not cursor == -1:
                editor.setTextCursor(cursor)

    def achar_e_substituir(self):
        """
        Achar e substituir palavras chave por outras
        :return:
            None
        """
        editor = self.widget_abas.widget(self.widget_abas.currentIndex())
        caminho = editor.get_caminho()
        # Testa se a aba eh a de boas vindas
        if caminho == 0:
            return
        texto, ok = QInputDialog.getText(None, "Achar", "Achar:")
        subs, ok = QInputDialog.getText(None, "Substituir", "Substituir:")
        if ok and texto != "":
            cursor = editor.textCursor()
            cursor = self.selecionar_texto(cursor, texto, cursor.position(),
                                           len(texto))
            if not cursor == -1:
                cursor.removeSelectedText()
                editor.setTextCursor(cursor)
                editor.insertPlainText(subs)
        return

    @staticmethod
    def criar_dialogo_arquivo(titulo, acao):
        """
        Cria dialogo personalizado para buscar arquivos
        :param titulo:
            Titulo de aba
        :param acao:
            Texto do botao de selecionar
        :return dialogo:
            dialogo
        """
        dialogo = QFileDialog()
        dialogo.setWindowTitle(titulo)
        dialogo.setLabelText(QFileDialog.FileName, "Arquivo:")
        dialogo.setLabelText(QFileDialog.LookIn, "Buscar em:")
        dialogo.setLabelText(QFileDialog.FileType, "Tipo de arquivo:")
        dialogo.setLabelText(QFileDialog.Accept, acao)
        dialogo.setLabelText(QFileDialog.Reject, "Cancelar")
        dialogo.setNameFilters(
            ["Rascunhos Br.ino (*.brpp)", "Rascunhos Arduino (*.ino)"])
        dialogo.selectNameFilter("Rascunhos Br.ino (*.brpp)")
        dialogo.setDirectory(get_caminho_padrao())
        return dialogo

    def abrir_serial(self):
        """
        Abre o monitor serial
        :return:
            None
        """
        self.parent.abrir_serial()

    def carregar_hardware(self, pasta):
        """
        Carrega as opcoes de hardware do Arduino
        :param pasta:
            Diretorio do hardware
        :return:
            None
        """
        if not os.path.isdir(pasta):
            return
        lista = [
            os.path.join(pasta, pasta_) for pasta_ in os.listdir(pasta)
            if os.path.isdir(os.path.join(pasta, pasta_))
        ]
        if len(lista) == 0:
            return
        lista = sorted(lista, key=str.lower)
        lista.remove(os.path.join(pasta, "tools"))
        for item in lista:
            nome_item = os.path.basename(item)
            if nome_item in self.pacotes:
                pacote_alvo = self.pacotes.get(nome_item)
            else:
                pacote_alvo = PacoteAlvo(nome_item)
                self.pacotes[nome_item] = pacote_alvo
            self.carregar_pacote_alvo(pacote_alvo, item)

    def carregar_hardware_contribuido(self, indexer):
        """
        :param indexer:
            Indexador de contribuicoes
        :return:
            None
        """
        for pacote in indexer.criar_pacotes_alvo():
            if self.pacotes.get(pacote.get_id(), False):
                self.pacotes[pacote.get_id()] = pacote

    @staticmethod
    def carregar_pacote_alvo(pacote_alvo, pasta):
        """
        Carrega o pacote alvo
        :param pacote_alvo:
            Pacote de hardware
        :param pasta:
            Diretorio do pacote
        :return:
            None
        """
        pastas = os.listdir(pasta)
        if len(pastas) == 0:
            return
        for item in pastas:
            plataforma_alvo = PlataformaAlvo(item, os.path.join(pasta, item),
                                             pacote_alvo)
            pacote_alvo.get_plataformas()[item] = plataforma_alvo

    def criar_menu_placas(self):
        """
        Cria o menu das placas
        :return:
            None
        """
        self.menus_personalizados = list()
        titulos_menus_personalizados = list()
        for pacote_alvo in self.pacotes.values():
            for plataforma_alvo in pacote_alvo.get_lista_plataformas():
                titulos_menus_personalizados += plataforma_alvo.get_menus(
                ).values()
        for titulo_menu_personalizado in titulos_menus_personalizados:
            menu = QMenu(titulo_menu_personalizado)
            self.menus_personalizados.append(menu)
        placas = QActionGroup(self.parent)
        placas.setExclusive(True)
        for pacote_alvo in self.pacotes.values():
            for plataforma_alvo in pacote_alvo.get_lista_plataformas():
                nome = plataforma_alvo.get_preferencias().get("name")
                self.parent.menu_placas.addAction(QAction(nome, self))
                for placa in plataforma_alvo.get_placas().values():
                    if not placa.get_preferencias().get('hide'):
                        self.parent.menu_placas.addAction(
                            placa.criar_acao(self))

    def criar_menu_portas(self):
        """
        Cria o menu das portas
        :return:
            None
        """
        for acao in self.parent.menu_portas.actions():
            self.parent.menu_portas.removeAction(acao)
        portas = QActionGroup(self.parent)
        portas.setExclusive(True)
        n_portas = len(self.serial_ports())
        if n_portas > 0:
            for porta in self.serial_ports():
                porta_acao = Porta.criar_acao(porta, self)
                self.parent.menu_portas.addAction(porta_acao)
                if n_portas == 1:
                    Preferencias.set('serial.port', porta)
        else:
            self.parent.menu_portas.addAction(
                QAction("Não há portas disponíveis", self))

    def criar_menu_exemplos(self):
        """
        Cria o menu exemplos
        :return:
            None
        """
        caminho_exemplos = os.path.join('recursos', 'exemplos')
        pastas_exemplo = [
            x for x in os.listdir(caminho_exemplos)
            if os.path.isdir(os.path.join(caminho_exemplos, x))
        ]
        pastas_exemplo.sort()
        for pasta_exemplo in pastas_exemplo:
            menu = self.parent.menu_exemplos.addMenu(pasta_exemplo)
            for exemplo in os.listdir(
                    os.path.join(caminho_exemplos, pasta_exemplo)):
                exemplo_acao = QAction(exemplo, self)
                caminho_exemplo = os.path.join(caminho_exemplos, pasta_exemplo,
                                               exemplo, exemplo + ".brpp")
                menu.addAction(exemplo_acao)
                exemplo_acao.triggered.connect(
                    functools.partial(self.abrir, caminho_exemplo, True))

    def on_troca_placa_ou_porta(self):
        """
        Troca a placa
        :return:
            None
        """
        plataforma = self.get_plataforma_alvo()
        pastas_bibliotecas = list()
        # if plataforma:
        # core = self.get_preferencias_placa()
        pasta_plataforma = plataforma.get_pasta()
        pastas_bibliotecas.append(os.path.join(pasta_plataforma, 'libraries'))
        pastas_bibliotecas.append(
            os.path.join(get_caminho_padrao(), 'bibliotecas'))

    def get_preferencias_placa(self):
        """
        Busca as preferencias da palca que esta sendo utilizada
        :return prefs:
            Retorna as preferencias
        """
        placa_alvo = self.get_placa_alvo()
        if placa_alvo is None:
            return None
        id_placa = placa_alvo.get_id()
        prefs = placa_alvo.get_preferencias()
        nome_extendido = prefs.get("name")
        for id_menu in placa_alvo.get_ids_menus():
            if not placa_alvo.tem_menu(id_menu):
                continue
            entrada = Preferencias.get("custom_" + id_menu)
            if entrada is not None and entrada.startswith(id_placa):
                id_selecao = entrada[len(id_placa) + 1:]
                prefs.update(
                    placa_alvo.get_preferencias_menu(id_menu, id_selecao))
                nome_extendido += ", " + placa_alvo.get_label_menu(
                    id_menu, id_selecao)
        prefs['name'] = nome_extendido
        ferramentas = list()
        plataforma = self.indexer.get_plataforma_contribuida(
            self.get_plataforma_alvo())
        if plataforma is not None:
            ferramentas.extend(plataforma.get_ferramentas_resolvidas())

        core = prefs.get("build.core")
        if core is not None and core.__contains__(":"):
            separado = core.split(":")
            referenciada = self.get_plataforma_atual_do_pacote(separado[0])
            if referenciada is not None:
                plat_referenciada = self.indexer.get_plataforma_contribuida(
                    referenciada)
                ferramentas.extend(
                    plat_referenciada.get_ferramentas_resolvidas())
        prefix = "runtime.tools."
        for tool in ferramentas:
            pasta = tool.get_pasta_instalada()
            caminho = os.path.abspath(pasta)
            prefs[(prefix + tool.get_nome() + ".path")] = caminho
            Preferencias.set(prefix + tool.get_nome() + ".path", caminho)
            Preferencias.set(
                prefix + tool.get_nome() + "-" + tool.get_versao() + ".path",
                caminho)
        return prefs

    def get_placa_alvo(self):
        """
        Busca a placa alvo
        :return
            placa alvo:
        """
        plataforma_alvo = self.get_plataforma_alvo()
        if plataforma_alvo:
            placa = Preferencias.get('board')
            return plataforma_alvo.get_placa(placa)

    def get_plataforma_alvo(self, pacote=None, plataforma=None):
        """
        Pega a plataforma alvo
        :param pacote:
            Pacote da plataforma
        :param plataforma:
            A plataforma
        :return plataforma_alvo:
            Plataforma alvo
        """
        if pacote is None:
            pacote = Preferencias.get('target_package')
        if plataforma is None:
            plataforma = Preferencias.get('target_platform')
        p = self.pacotes.get(pacote)
        plataforma_alvo = p.get(plataforma)
        return plataforma_alvo

    def get_plataforma_atual_do_pacote(self, pacote):
        """
        :param pacote:
            Pacote da plataforma
        :return:
            Retorna a plataforma alvo
        """
        return self.get_plataforma_alvo(pacote,
                                        Preferencias.get("target_platform"))

    def compilar(self):
        """
        Compila o codigo da aba atual
        :return:
            None
        """
        self.salvar()
        self.log.clear()
        editor = self.widget_abas.widget(self.widget_abas.currentIndex())
        caminho = editor.get_caminho()
        # Testa se a aba eh a de boas vindas
        if caminho == 0 or caminho == '':
            return None
        placa_alvo = self.get_placa_alvo()
        plataforma_alvo = placa_alvo.get_plataforma()
        pacote_alvo = plataforma_alvo.get_pacote()
        # Transforma o codigo brpp em ino
        traduzir(caminho)
        resultado = compilar_arduino_builder(caminho, placa_alvo,
                                             plataforma_alvo, pacote_alvo,
                                             self.temp_build, self.temp_cache)
        self.log.insertPlainText(str(resultado, sys.stdout.encoding))

    def upload(self):
        """
        Compila e carrega o codigo da aba atual
        :return:
            None
        """
        self.compilar()
        editor = self.widget_abas.widget(self.widget_abas.currentIndex())
        caminho = editor.get_caminho()
        # Testa se a aba eh a de boas vindas
        if caminho == 0 or caminho == '':
            return None
        caminho = editor.get_caminho()
        # Ajustes do Arduino
        # TODO Terminar ajustes
        caminho_temp = self.temp_build
        uploader = None
        if uploader is None:
            uploader = Uploader.get_uploader_por_preferencias()
            uploader = Uploader.UploaderSerial(False)
        sucesso = False
        nome = os.path.basename(caminho).replace("brpp", "ino")
        sucesso = uploader.upload_usando_preferencias(self, caminho_temp,
                                                      os.path.basename(nome))

    @staticmethod
    def serial_ports():
        """
        Lista as portas seriais disponiveis
        :raises EnvironmentError:
            Plataforma desconhecida ou nao suportada
        :returns:
            Lista das portas seriais disponiveis
        """
        if sys.platform.startswith('win'):
            ports = ['COM%s' % (i + 1) for i in range(256)]
        elif sys.platform.startswith('linux') or sys.platform.startswith(
                'cygwin'):
            # this excludes your current terminal "/dev/tty"
            ports = glob.glob('/dev/tty[A-Za-z]*')
        elif sys.platform.startswith('darwin'):
            ports = glob.glob('/dev/tty.*')
        else:
            raise EnvironmentError('Unsupported platform')

        result = []
        for port in ports:
            try:
                s = serial.Serial(port)
                s.close()
                result.append(port)
            except (OSError, serial.SerialException):
                pass
        return result

    def get_menu_personalizado_placa(self, title):
        for menu in self.menus_personalizados:
            if menu.title() == title:
                return menu

    def instalar_biblioteca(self):
        caminho_bibliotecas = os.path.join(get_caminho_padrao(), "bibliotecas")
        dialogo = QFileDialog()
        dialogo.setWindowTitle("Escolher biblioteca")
        dialogo.setLabelText(QFileDialog.FileName, "Arquivo:")
        dialogo.setLabelText(QFileDialog.LookIn, "Buscar em:")
        dialogo.setLabelText(QFileDialog.FileType, "Tipo de arquivo:")
        dialogo.setLabelText(QFileDialog.Accept, "Escolher")
        dialogo.setLabelText(QFileDialog.Reject, "Cancelar")
        dialogo.setFileMode(QFileDialog.DirectoryOnly)
        dialogo.setDirectory(get_caminho_padrao())
        if dialogo.exec_() == QFileDialog.Accepted:
            caminho = dialogo.selectedUrls()[0].path()
            if (caminho.startswith("/") and os.name == 'nt'):
                caminho = caminho[1:]
            # Testa se o arquivo existe
            if os.path.exists(caminho):
                try:
                    shutil.copytree(
                        caminho,
                        os.path.join(caminho_bibliotecas,
                                     os.path.basename(caminho)))
                    # Directories are the same
                except shutil.Error as e:
                    print('Directory not copied. Error: %s' % e)
                    # Any error saying that the directory doesn't exist
                except OSError as e:
                    print('Directory not copied. Error: %s' % e)
            else:
                QMessageBox(QMessageBox.Warning, "Erro",
                            "O arquivo não existe", QMessageBox.NoButton,
                            self).show()
        else:
            return
コード例 #9
0
ファイル: MsUiDesign.py プロジェクト: life4love/MikroScript
class MsUiDesign(QMainWindow):
    def __init__(self, parent=None):
        self.appctxt = ApplicationContext()
        super(MsUiDesign, self).__init__(parent)
        self.setWindowTitle("MikroScript")
        self.setStyleSheet(COLOR_BG)
        self.resize(1128, 768)
        self.setMinimumSize(1128, 768)
        self.setWindowIcon(QIcon(self.appctxt.get_resource("favicon.png")))

        # Updated by Pinkesh Shah on 29-Apr-20
        # Start Region
        self.activeJobTabs = []
        # End Region

        self.tabCtr = 0
        self.tabview = QTabWidget()
        # self.tabview.setStyleSheet(CSS.CSS_TAB)

        self.conn = sqlite3.connect("MikroScript.db")

        self.changeStyle('Windows')
        self.createMenuBar()
        self.tree_dock_widget()
        self.card_dock_widget()
        self.create_dock_widget_area()
        # self.createBottomArea()

        # mainLayout = QGridLayout()
        # # mainLayout.addLayout(self.TopArea   , 0, 0, 1, 3)
        # # mainLayout.addLayout(self.LeftArea  , 1, 0, 1, 1)
        # mainLayout.addLayout(self.RightArea , 1, 1, 1, 2)
        # # mainLayout.addLayout(self.BottomArea, 2, 0, 1, 3)
        # # mainLayout.addWidget(self.topLeftGroupBox, 1, 0)
        # # mainLayout.addWidget(self.topRightGroupBox, 1, 1)
        # # mainLayout.addWidget(self.bottomLeftTabWidget, 2, 0)
        # # mainLayout.addWidget(self.bottomRightGroupBox, 2, 1)
        # # mainLayout.addWidget(self.progressBar, 3, 0, 1, 2)
        # # mainLayout.setRowStretch(1, 1)
        # mainLayout.setColumnStretch(1, 1)
        # mainLayout.setColumnStretch(2, 1)

        # self.plusButton.setFixedSize(20, 20)  # Small Fixed size
        addButton = QPushButton(
            QIcon(self.appctxt.get_resource("add-24px.svg")), "")
        addButton.clicked.connect(self.ActionNew)

        self.tabview.setMovable(True)
        self.tabview.setTabsClosable(True)
        self.tabview.tabCloseRequested.connect(self.removeTab)
        self.tabview.setCornerWidget(addButton)
        # self.tabview = CustomTabWidget()
        self.setCentralWidget(self.tabview)
        self.ActionNew()
        self.get_job_list()

    def removeTab(self, index):
        tab = self.tabview.widget(index)

        # Updated by Pinkesh Shah on 30-Apr-20
        # Start Region
        tab_Name = self.tabview.tabText(index)
        self.activeJobTabs.remove(tab_Name)
        # End Region

        if tab is not None:
            tab = None
            self.tabview.removeTab(index)

    def createMenuBar(self):

        actNew = QAction(
            QIcon(
                self.appctxt.get_resource(
                    "outline_insert_drive_file_black_18dp.png")), "&New")
        actNew.triggered.connect(self.ActionNew)
        actNew.setShortcut(QKeySequence.New)

        # actOpen = QAction(QIcon(self.appctxt.get_resource("outline_folder_black_18dp.png")), "&Open")
        # actOpen.triggered.connect(self.ActionOpen)
        # actOpen.setShortcut(QKeySequence.Open)

        actSave = QAction(
            QIcon(self.appctxt.get_resource("outline_save_black_18dp.png")),
            "&Save")
        actSave.triggered.connect(self.ActionSave)
        actSave.setShortcut(QKeySequence.Save)

        actQuit = QAction(
            QIcon(
                self.appctxt.get_resource(
                    "outline_exit_to_app_black_18dp.png")), "&Quit")
        actQuit.triggered.connect(self.ActionQuit)
        actQuit.setShortcut(QKeySequence.Quit)

        self.actExecute = QAction(
            QIcon(
                self.appctxt.get_resource(
                    "outline_play_circle_outline_black_18dp.png")), "E&xecute")
        self.actExecute.triggered.connect(self.ActionExecute)
        self.actExecute.setShortcut(QKeySequence.Refresh)

        actPause = QAction(
            QIcon(self.appctxt.get_resource("pause_circle_outline-24px.svg")),
            "Pause")
        actPause.triggered.connect(self.ActionPause)
        actPause.setShortcut(QKeySequence.Refresh)

        actStop = QAction(QIcon(self.appctxt.get_resource("stop-24px.svg")),
                          "Stop")
        actStop.triggered.connect(self.ActionStop)
        actStop.setShortcut(QKeySequence.Refresh)

        actReset = QAction(
            QIcon(self.appctxt.get_resource("outline_replay_black_18dp.png")),
            "&Reset")
        actReset.triggered.connect(self.ActionReset)
        actReset.setShortcut(QKeySequence.Replace)

        # actCut = QAction(QIcon(self.appctxt.get_resource("outline_file_copy_black_18dp.png")), "Cu&t")
        # actCut.setShortcut(QKeySequence.Cut)
        #
        # actCopy = QAction(QIcon(self.appctxt.get_resource("outline_insert_drive_file_black_18dp.png")), "&Copy")
        # actCopy.setShortcut(QKeySequence.Copy)
        #
        # actPaste = QAction(QIcon(self.appctxt.get_resource("outline_insert_drive_file_black_18dp.png")), "&Paste")
        # actPaste.setShortcut(QKeySequence.Paste)

        # actAbout = QAction("&About")

        # menuFile = self.menuBar().addMenu("&File")
        # menuFile.addAction(actNew)
        # # menuFile.addAction(actOpen)
        # menuFile.addAction(actSave)
        # menuFile.addSeparator()
        # menuFile.addAction(actQuit)

        # menuEdit = self.menuBar().addMenu("&Edit")
        # menuEdit.addAction(actCut)
        # menuEdit.addAction(actCopy)
        # menuEdit.addAction(actPaste)

        # menuView = self.menuBar().addMenu("&View")
        # menuRun = self.menuBar().addMenu("&Run")
        # menuRun.addAction(self.actExecute)
        # menuWin = self.menuBar().addMenu("&Window")

        # menuHelp = self.menuBar().addMenu("Help")
        # menuHelp.addAction(actAbout)

        ###################################################################

        toolbtnNew = QToolButton()
        toolbtnNew.setDefaultAction(actNew)
        toolbtnNew.setToolTip("New Job - CTRL + N")

        # toolbtnOpen = QToolButton()
        # toolbtnOpen.setDefaultAction(actOpen)
        # toolbtnOpen.setToolTip("Open File")

        toolbtnSave = QToolButton()
        toolbtnSave.setDefaultAction(actSave)
        toolbtnSave.setToolTip("Save File")

        toolbtnExecute = QToolButton()
        toolbtnExecute.setDefaultAction(self.actExecute)
        toolbtnExecute.setToolTip("Execute - F5")

        toolbtnPause = QToolButton()
        toolbtnPause.setDefaultAction(actPause)
        toolbtnPause.setToolTip("Pause")

        toolbtnStop = QToolButton()
        toolbtnStop.setDefaultAction(actStop)
        toolbtnStop.setToolTip("Stop")

        toolbtnReset = QToolButton()
        toolbtnReset.setDefaultAction(actReset)
        toolbtnReset.setToolTip("Reset")

        styleComboBox = QComboBox()
        styleComboBox.addItems(QStyleFactory.keys())

        styleLabel = QLabel("&Style:")
        styleLabel.setBuddy(styleComboBox)
        styleComboBox.activated[str].connect(self.changeStyle)

        self.toolBar = QToolBar()
        self.toolBar.addWidget(toolbtnNew)
        # toolBar.addWidget(toolbtnOpen)
        self.toolBar.addWidget(toolbtnSave)
        self.toolBar.addSeparator()
        self.toolBar.addWidget(toolbtnExecute)
        self.toolBar.addWidget(toolbtnPause)
        self.toolBar.addWidget(toolbtnStop)
        self.toolBar.addWidget(toolbtnReset)
        self.toolBar.addWidget(styleComboBox)
        self.toolBar.setMovable(False)
        self.toolBar.addSeparator()
        # toolBar.addWidget(styleLabel)
        # toolBar.addWidget(styleComboBox)
        self.addToolBar(self.toolBar)

    def build_job_frame(self, name):
        job_frame = QFrame()
        # job_frame.   connect(self.load_job)
        job_frame.setMinimumSize(220, 80)

        # job_frame.setFrameShape(QFrame.Box)
        # job_frame.setFrameShadow(QFrame.Raised)
        job_frame.setFrameShape(QFrame.StyledPanel)
        job_frame.setFrameShadow(QFrame.Plain)
        job_frame.setLineWidth(0)
        job_frame.setMidLineWidth(0)
        # job_frame.setFrameStyle()
        job_frame.setStyleSheet(CSS.CSS_FRAME)

        layout = QHBoxLayout()
        label = QLabel(name)
        label.setStyleSheet(CSS.CSS_FRAME_MIKROTIK_LABEL)
        # label.setStyleSheet(CSS.CSS_FRAME_LABEL)
        layout.addWidget(label, 0, Qt.AlignTop)
        # layout.addWidget(QPushButton(QIcon(self.appctxt.get_resource("outline_play_circle_outline_black_18dp.png")), ""))

        # Updated by Pinkesh Shah on 27-Apr-20
        # Start Region
        layout.addSpacing(2)
        vendorLabel = QLabel("Mikrotik")
        vendorLabel.setFixedSize(50, 15)
        vendorLabel.setStyleSheet(CSS.CSS_FRAME_LABEL)
        # mikrotikLabel.setStyleSheet(CSS.CSS_FRAME_MIKROTIK_LABEL)
        layout.addWidget(vendorLabel, 0, Qt.AlignTop)
        # End Region

        img = QImage(
            self.appctxt.get_resource(
                "outline_play_circle_outline_black_18dp.png"))
        lbl_img = QLabel("")
        lbl_img.setPixmap(QPixmap.fromImage(img))
        # lbl_img.resize(img.width(), img.height())

        job_frame.setLayout(layout)
        # count = self.dock_layout.count()
        self.dock_layout.addWidget(job_frame)

        # Updated by Pinkesh Shah on 27-Apr-20
        # Start Region
        self.dock_layout.setSpacing(10)
        # End Region

        # Updated by Pinkesh Shah on 05-May-20 to disable Scheduler layout
        # Start Region
        self.groupBox.setMinimumHeight(self.groupBox.sizeHint().height() +
                                       FRAME_SIZE)
        # self.jobsGroupBox.setMinimumHeight(self.jobsGroupBox.sizeHint().height() + FRAME_SIZE)
        # End Region

        # Updated by Pinkesh Shah on 05-May-20 to disable Scheduler layout
        # Start Region

        # Updated by Pinkesh Shah on 28-Apr-20
        # Start Region
        self.groupBox.setMaximumWidth(250)
        # End Region

        # self.jobsGroupBox.setMaximumWidth(250)
        # End Region

        # Updated by Pinkesh Shah on 05-May-20 to disable Scheduler layout
        # Start Region
        # self.groupBox.setStyleSheet(CSS.CSS_FRAME_GROUP_BOX)
        # self.jobsGroupBox.setStyleSheet(CSS.CSS_GROUP_BOX)
        # End Region

        return job_frame

    def tree_dock_widget(self):
        self.dock_widget = QTreeView()

    def card_dock_widget(self):

        # Updated by Pinkesh Shah on 05-May-20 to disable Scheduler layout
        # Start Region
        # self.dockWidgetGroupBox = QGroupBox("")
        # self.dockWidgetLayout = QVBoxLayout()
        # self.jobsGroupBox = QGroupBox("Jobs")

        # Scheduler
        # self.scheduledGroupBox = QGroupBox("Scheduled")
        # self.scheduledLayout = QVBoxLayout()
        # self.scheduledGroupBox.setLayout(self.scheduledLayout)
        # self.scheduledScroll = QScrollArea()
        # self.scheduledScroll.setWidget(self.scheduledGroupBox)
        # self.scheduledScroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        # self.scheduledLayout.addWidget(QLabel("Test Label"))
        # self.dockWidgetGroupBox.setLayout(self.dockWidgetLayout)
        # End Region

        self.dock_layout = QVBoxLayout()

        # Updated by Pinkesh Shah on 05-May-20 to disable Scheduler layout
        # Start Region
        self.groupBox = QGroupBox("")
        self.groupBox.setLayout(self.dock_layout)
        self.groupBox.setStyleSheet(CSS.CSS_FRAME_GROUP_BOX)
        # self.jobsGroupBox.setLayout(self.dock_layout)
        # End Region

        # Updated by Pinkesh Shah on 05-May-20 to disable Scheduler layout
        # Start Region

        # Updated by Pinkesh Shah on 27-Apr-20
        # Start Region
        # self.groupBox.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.groupBox.setSizePolicy(QSizePolicy.MinimumExpanding,
                                    QSizePolicy.MinimumExpanding)
        # End Region

        # self.jobsGroupBox.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)
        # End Region

        self.dock_widget = QScrollArea()
        self.dock_widget.setStyleSheet(CSS.CSS_SCROLLBAR)

        # Updated by Pinkesh Shah on 05-May-20 to disable Scheduler layout
        # Start Region
        self.dock_widget.setWidget(self.groupBox)
        # self.dock_widget.setWidget(self.jobsGroupBox)
        # End Region

        self.dock_widget.setWidgetResizable(True)

        # Updated by Pinkesh Shah on 28-Apr-20
        # Start Region
        self.dock_widget.setMinimumWidth(270)
        self.dock_widget.setMaximumWidth(400)
        self.dock_widget.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        # End Region

        # Updated by Pinkesh Shah on 05-May-20 to disable Scheduler layout
        # Start Region
        # self.dockWidgetLayout.addWidget(self.dock_widget)
        # self.dockWidgetLayout.addWidget(self.scheduledScroll)
        # End Region

    def create_dock_widget_area(self):
        docWidget = QDockWidget("Script Jobs")

        # Updated by Pinkesh Shah on 05-May-20 to disable Scheduler layout
        # Start Region
        docWidget.setWidget(self.dock_widget)
        # docWidget.setWidget(self.dockWidgetGroupBox)
        # End Region

        # docWidget.setLayout(layout)
        docWidget.DockWidgetFeatures(QDockWidget.DockWidgetVerticalTitleBar)
        docWidget.setFloating(False)
        self.addDockWidget(Qt.LeftDockWidgetArea, docWidget, Qt.Vertical)

        docWidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

    def createBottomArea(self):
        status = QStatusBar()
        self.setStatusBar(status)

    ################# All Action starts from here

    def ActionOpen(self):
        print("Open")

    def ActionPause(self):
        print("Pause")

    def ActionStop(self):
        print("Stop")

    def ActionReset(self):
        print("Reset")

    def ActionQuit(self):
        print("Quit")

    def ActionSave(self):
        self.create_table()
        current_tab_index = self.tabview.currentIndex()
        if current_tab_index >= 0:
            tab = self.tabview.currentWidget()
            job_data = tab.property("OBJECT").get_job_data()
            if len(job_data) > 0:
                if tab.property("NAME") == "":
                    win = SaveWindow()
                    if win.is_accepted():
                        name = win.get_name()
                        _id = self.get_id()
                        tab.setToolTip(name)
                        tab.setWindowTitle(name)
                        tab.setProperty("NAME", name)
                        tab.setProperty("_ID", _id)
                        string = "insert into jobs (id, name, jobs_data, created_on) values (?, ?, ?, ?)"
                        values = [
                            _id, name,
                            json.dumps(job_data),
                            datetime.now()
                        ]
                        self.build_job_frame(name)
                        self.conn.execute(string, values)
                        self.conn.commit()
                else:
                    string = "update jobs set name = ?, jobs_data = ?, updated_on = ? where id = ?"
                    values = [
                        tab.property("NAME"),
                        json.dumps(job_data),
                        datetime.now(),
                        tab.property("_ID")
                    ]
                    self.conn.execute(string, values)
                    self.conn.commit()

    def ActionNew(self, name=None):

        try:
            print("Sub-class")
            self.tabCtr += 1
            tab = QWidget()
            ## tab.setStyleSheet(CSS.CSS_TAB_BASE)
            ## tab.setStyleSheet("{ border-style: solid; background-color:#FBFBFB }")
            center = ScriptExecutor()
            result = center.getExecutorLayout()

            tab.setLayout(result)
            tab.setProperty("OBJECT", center)
            tab.setProperty("TAB_CTR", self.tabCtr)
            tab.setProperty("NAME", "")
            tab.setProperty("_ID", 0)
            # center.getFirstWidget().setFocus(Qt.ActiveWindowFocusReason)
            if name == None:
                name = "Untitled " + str(self.tabCtr)
            self.tabview.addTab(tab, name)
            self.tabview.setCurrentWidget(tab)
            center.host.setFocus()
        except Exception:
            raise
        return tab

    def ActionExecute(self):
        current_tab_index = self.tabview.currentIndex()
        if current_tab_index >= 0:
            tab = self.tabview.currentWidget()
            tab.property("OBJECT").Execute()

    def load_job(self, frame, event):

        job_data = json.loads(frame.property(JOB_DATA))

        # Updated by Pinkesh Shah on 30-Apr-20
        # Start Region
        if frame.property(NAME) not in self.activeJobTabs:
            self.activeJobTabs.append(frame.property(NAME))
            tab = self.ActionNew(frame.property(NAME))
            center = tab.property("OBJECT")
            center.LoadData(job_data)
        # End Region

        # Updated by Pinkesh Shah on 02-May-20
        # Start Region
        else:
            for i in range(self.tabview.count()):
                if frame.property(NAME) == self.tabview.tabText(i):
                    self.tabview.setCurrentIndex(i)
        # End Region

    def create_table(self):

        cursor = self.conn.execute(
            ''' SELECT count(name) FROM sqlite_master WHERE type='table' AND name='Jobs' '''
        )

        # if the count is 1, then table exists
        if not cursor.fetchone()[0] == 1:
            string = "create table Jobs (id INT PRIMARY KEY NOT NULL, name text, jobs_data json, " \
                     "created_on CURRENT_TIMESTAMP, " \
                     "updated_on CURRENT_TIMESTAMP )"

            self.conn.execute(string)
            print("Create Statement:", string)

    def get_id(self):
        cursor = self.conn.execute(''' SELECT MAX(id) as id FROM jobs  ''')
        _id = 0
        for rec in cursor:
            _id = (0 if rec[0] == None else rec[0])
        _id = _id + 1
        cursor.close()
        return _id

    def get_job_list(self):
        string = "select id, name, jobs_data from Jobs order by id"
        cursor = self.conn.execute(string)
        for rec in cursor:
            frame = self.build_job_frame(rec[1])
            frame.setProperty(_ID, rec[0])
            frame.setProperty(NAME, rec[1])
            frame.setProperty(JOB_DATA, rec[2])

            frame.mouseDoubleClickEvent = partial(self.load_job, frame)

    def changeStyle(self, styleName):
        QApplication.setStyle(QStyleFactory.create(styleName))
コード例 #10
0
ファイル: client_tab.py プロジェクト: kyleb000/pclantransfer
class ClientTabManager(QWidget):

    opened_tabs = []

    tab_counter = 0

    client = None

    def __init__(self, parent, clt):
        super().__init__(parent)
        self.client_layout = QVBoxLayout(self)
        self.client = clt

        # Initialize tab screen
        self.client_tabs = QTabWidget()
        self.client_tabs.setTabsClosable(False)
        self.client_tabs.tabCloseRequested.connect(self.close_tab)
        self.client_tabs.tabBarClicked.connect(lambda x: print(x))
        self.client_tabs.resize(900,600)

        # Add tabs
        self.add_tab_button = QToolButton(self)
        self.add_tab_button.setText('+')
        font = self.add_tab_button.font()
        font.setBold(True)
        self.add_tab_button.setFont(font)
        self.client_tabs.setCornerWidget(self.add_tab_button)
        self.add_tab_button.clicked.connect(self.add_tab)
        tab1 = QWidget()
        self.setup_tab(tab1)
        self.opened_tabs.append((tab1, "New Tab"))
        self.client_tabs.addTab(self.opened_tabs[0][0], self.opened_tabs[0][1])

        # Add tabs to widget
        self.client_layout.addWidget(self.client_tabs)
        self.setLayout(self.client_layout)



    def connect(self, ip, port, layout):
        #old_layout = copy.deepcopy(layout)
        deleteLayout(layout)
        try:
            self.client.connect_to_server(ip, int(port))
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Information)
            msg.setText("Connection successful!")
            msg.setWindowTitle("Connection info")
            msg.exec_()
            layout.addWidget(NetworkFolderManager(self, self.client))
        except FailedToConnect as e:
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Error)
            msg.setText("Connection Failed!")
            msg.setInformativeText(str(e))
            msg.setWindowTitle("Connection info")
            msg.exec_()
            self.setup_tab(layout)

        except ClientAlreadyExists as e:
            msg = ReconnectDialog()
            msg.exec_();
            """msg = QMessageBox()
            msg.setIcon(QMessageBox.Information)
            msg.setText("Connection Failed!")
            msg.setInformativeText(str(e))
            msg.setWindowTitle("Connection info")
            msg.exec_()
            self.setup_tab(layout)"""

    def setup_tab(self, tab_widget):
        tab1_layout = QVBoxLayout()

        conn_btn = QPushButton("Connect...")
        conn_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        btn_layout = QHBoxLayout()
        btn_layout.addLayout(QVBoxLayout(), 2)
        btn_layout.addWidget(conn_btn, 3)
        btn_layout.addLayout(QVBoxLayout(), 2)

        ip_layout = QHBoxLayout()
        ip_main_layout = QHBoxLayout()
        ip_label = QLabel("IP Address: ")
        ip_edit = QLineEdit()
        ip_layout.addWidget(ip_label)
        ip_layout.addWidget(ip_edit)
        ip_main_layout.addLayout(QVBoxLayout(), 2)
        ip_main_layout.addLayout(ip_layout, 3)
        ip_main_layout.addLayout(QVBoxLayout(), 2)

        port_layout = QHBoxLayout()
        port_main_layout = QHBoxLayout()
        port_label = QLabel("Port: ")
        port_edit = QLineEdit()
        port_edit.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        port_layout.addWidget(port_label)
        port_layout.addWidget(port_edit)
        port_main_layout.addLayout(QVBoxLayout(), 2)
        port_main_layout.addLayout(port_layout, 3)
        port_main_layout.addLayout(QVBoxLayout(), 2)

        tab_main = QVBoxLayout()
        tab1_layout.addLayout(ip_main_layout, 2)
        tab1_layout.addLayout(port_main_layout, 2)
        tab1_layout.addLayout(btn_layout, 2)

        tab1_layout.setSpacing(20)
        conn_btn.clicked.connect(lambda x: self.connect(ip_edit.text(), port_edit.text(), tab1_layout))

        tab_main.addLayout(QVBoxLayout(), 2)
        tab_main.addLayout(tab1_layout, 3)
        tab_main.addLayout(QVBoxLayout(), 2)
        #tab1_layout.addStretch(100)
        tab_widget.setLayout(tab_main)

    def add_tab(self):
        if not self.tab_counter:
            self.client_tabs.setTabsClosable(True)
        self.tab_counter += 1
        new_tab = (QWidget(), "New Tab")
        self.setup_tab(new_tab[0])
        self.opened_tabs.append(new_tab)
        self.client_tabs.addTab(new_tab[0], new_tab[1])

    def close_tab(self, index):
        if self.tab_counter == 1:
            self.client_tabs.setTabsClosable(False)

        # TODO: Close any client connections and do cleaning up here
        self.client_tabs.removeTab(index)
        self.tab_counter -= 1
コード例 #11
0
ファイル: views.py プロジェクト: Superesse95/PratoFiorito
class CreateApp(QMainWindow):
    '''The main application. The on_configure() method is called when the 'Reconfigure' button pressed on config pane.'''
    def __init__(self):
        super().__init__()

        self.setGeometry(10, 10, 0, 0)
        self.setWindowTitle('Prato Fiorito')

        # °°°°° START MENU BAR °°°°°
        menubar = self.menuBar()  # Barra dei Menu
        # FILE
        fileMenu = menubar.addMenu('File')
        self.saving = QAction('Save',
                              self,
                              triggered=self.save,
                              shortcut='Ctrl+S')
        self.restoring = QAction('Load',
                                 self,
                                 triggered=self.restore,
                                 shortcut='Ctrl+L')
        fileMenu.addAction(self.saving)
        fileMenu.addAction(self.restoring)
        exists = os.path.isfile(sys.path[0] + '/Temp/objs.pkl')
        if (exists == False):
            self.restoring.setDisabled(True)
        # VISTA
        viewMenu = menubar.addMenu('Vista')
        self.day_action = QAction('Day Mode',
                                  self,
                                  checkable=True,
                                  triggered=self.setDayMode,
                                  shortcut='Ctrl+D')
        self.day_action.setChecked(True)
        self.night_action = QAction('Night Mode',
                                    self,
                                    checkable=True,
                                    triggered=self.setNightMode,
                                    shortcut='Ctrl+N')
        self.day_action.setDisabled(True)
        viewMenu.addAction(self.day_action)
        viewMenu.addAction(self.night_action)
        # REGOLE
        rulesMenu = menubar.addMenu('Regole')
        rulesMenu.addAction(
            QAction('Open Rules',
                    self,
                    triggered=self.openRuleFile,
                    shortcut='Ctrl+R'))
        # °°°°° END MENU BAR °°°°°

        # °°°°° START TAB WIDGET °°°°°
        self._root = QTabWidget()
        self._root.setCornerWidget(self._root.tabBar(), Qt.TopLeftCorner)
        self.setCentralWidget(self._root)

        # CONFIGURAZIONE
        self._config = ConfigPane(parameters=[('Beginner', [9, 9, 10]),
                                              ('Intermediate', [16, 16, 40]),
                                              ('Expert', [16, 30, 99]),
                                              ('Custom', [20, 30, 145])],
                                  on_configure=self.on_configure)

        exists = os.path.isfile(sys.path[0] + '/Temp/objs.pkl')
        if (exists):
            self.restore()  # Recupero variabili salvate
            diff = ['Beginner', 'Intermediate', 'Expert', 'Custom']
            self._config._textinputs[diff.index(
                self.difficulties)]['radio_btn'].setChecked(True)
        else:
            self._config._configbutton.click()  # Inizializzazione del gioco

        # RANKING
        self._ranking = ShowRanking()

        self._root.addTab(self._config, 'Configuration')
        self._root.addTab(self._buttons, 'Game')
        self._root.addTab(self._ranking, 'Ranking')

        self._root.currentChanged.connect(self.resize_window)
        self._root.setCurrentIndex(1)
        # °°°°° END TAB WIDGET °°°°°

    # function called when the index of the clicked Tab changes
    def resize_window(
        self
    ):  # Ridmensione l'area della finestra, in relazione allo spazio occupato dai widgets presenti
        if (self._root.currentIndex() == 0):
            self.setFixedSize(500, 500)
        elif (self._root.currentIndex() == 1):
            width = self._buttons.sizeHint().width()
            height = self._buttons.sizeHint().height() + 30
            self.setFixedSize(QSize(width, height))
        elif ((self._root.currentIndex() == 2)):
            width = self._ranking.sizeHint().width() + 40
            height = self._ranking.sizeHint().height() + 40
            self.setFixedSize(QSize(width, height))

    # This is the callback we pass into the constructor of ConfigPane
    # so that it can call us back with the 'New Game' button is
    # pressed.
    def on_configure(self):
        '''Callback for re-configure request on config pane.'''
        self.saving.setDisabled(False)
        self.difficulties = self._config.get_param()[0]['difficulties']
        parameters = self._config.get_param()[0]['values']

        if (len(parameters) > 0):
            n_rows = int(parameters[0].text())
            n_cols = int(parameters[1].text())
            self.bombs = int(parameters[2].text())
            if (n_rows < 1):
                n_rows = 1
            elif (n_rows > 25):
                n_rows = 25
            if (n_cols < 8):
                n_cols = 8
            elif (n_cols > 45):
                n_cols = 45

            if (n_rows == 1 and n_cols == 8):
                self.bombs = 2
            elif (n_rows == 25 and n_cols == 45):
                self.bombs = 500
            elif (n_rows // n_cols >= 1 and self.bombs > 500):
                self.bombs = int(n_rows * n_cols * 0.5)
            elif (n_cols // n_rows >= 1 and self.bombs > 500):
                self.bombs = int(n_rows * n_cols * 0.5)
            elif (self.bombs >= n_rows * n_cols):
                self.bombs = int(n_rows * n_cols * 0.5)

            self._config._textinputs[3]['values'][0].setText(str(n_rows))
            self._config._textinputs[3]['values'][1].setText(str(n_cols))
            self._config._textinputs[3]['values'][2].setText(str(self.bombs))

            self.matrix = create_matrix_of_game(n_rows, n_cols, self.bombs)
            self.m_sum = compute_matrix_sum(self.matrix, n_rows, n_cols)
            self.path_matrix = np.asarray([[' ' for _ in range(n_cols)]
                                           for _ in range(n_rows)])

            print(
                '__________________________________________________________________________'
            )
            print('matrix')
            print()
            print(self.matrix)
            print(
                '__________________________________________________________________________'
            )
            print('m_sum')
            print()
            print(self.m_sum)
            print(
                '__________________________________________________________________________'
            )
            print()

            self._buttons = ButtonPane(width=n_rows,
                                       height=n_cols,
                                       bombs=self.bombs,
                                       diff=self.difficulties,
                                       matrix=self.matrix,
                                       m_sum=self.m_sum,
                                       path_matrix=self.path_matrix,
                                       saving=self.saving,
                                       restoring=self.restoring,
                                       on_configure=self.on_configure)
            self._buttons.manage_ranking.connect(self.set_ranking)
            self._root.removeTab(1)
            self._root.insertTab(1, self._buttons, 'Game')
            self._root.setCurrentIndex(1)
            self._buttons.timer.start(1000)

    def set_ranking(
        self, time
    ):  # Funzione responsabile dell'inserimento in classifica di un eventuale vincitore
        if (self.difficulties != 'Custom'):
            position = Ranking(class_type=self.difficulties).compute_pos(time)
            if (position <= 10 and position != -1):
                self.time = time
                self._buttons.name_zone.show()
                self.setFixedSize(self._buttons.sizeHint())
                self._buttons.submit_btn.clicked.connect(
                    self.result_registration
                )  # Cliccando sul bottone 'Submit' viene chiamata la funzione 'result registration', responsabile della registrazione in classifica

    def result_registration(self):
        name = self._buttons.name.text()
        if (name == ''):
            name = 'unknown'
        my_elem = name + '#' + self.time

        Ranking(class_type=self.difficulties).insert(my_elem=my_elem)
        self._buttons.name_zone.hide()
        self.setFixedSize(self._buttons.sizeHint())
        # Aggiornamento vista classifica
        self._root.removeTab(2)
        self._ranking = ShowRanking()
        self._root.insertTab(2, self._ranking, 'Ranking')

    def setDayMode(self):
        self.setStyleSheet('color: black')
        self.day_action.setDisabled(True)
        self.day_action.setChecked(True)
        self.night_action.setDisabled(False)
        self.night_action.setChecked(False)
        QDay = QPalette()
        self.setPalette(QDay)

    def setNightMode(self):
        self.setStyleSheet('color: gray')
        self.day_action.setDisabled(False)
        self.day_action.setChecked(False)
        self.night_action.setDisabled(True)
        self.night_action.setChecked(True)
        QDark = QDarkPalette()
        self.setPalette(QDark)

    def openRuleFile(self):
        os.system('open ' + sys.path[0] + '/Regole.pdf')

    def save(self):  # Funzione responsabile del salvataggio della partita
        with open(sys.path[0] + '/Temp/objs.pkl', 'wb') as f:
            pickle.dump([
                self.matrix, self.m_sum, self.path_matrix, self.bombs,
                self.difficulties, self._buttons.curr_time,
                self._buttons.label_1.text(),
                self._buttons.label_3.text()
            ], f)
        self.restoring.setDisabled(False)

    def restore(
        self
    ):  # Funzione responsabile del caricamento della partita salvata in precedenza
        exists = os.path.isfile(sys.path[0] + '/Temp/objs.pkl')
        if (exists == True):
            with open(sys.path[0] + '/Temp/objs.pkl', 'rb') as f:
                self.matrix, self.m_sum, self.path_matrix, self.bombs, self.difficulties, curr_time, label_1, label_3 = pickle.load(
                    f)

                width = self.matrix.shape[0]
                height = self.matrix.shape[1]

                self._buttons = ButtonPane(width=width,
                                           height=height,
                                           bombs=self.bombs,
                                           diff=self.difficulties,
                                           matrix=self.matrix,
                                           m_sum=self.m_sum,
                                           path_matrix=self.path_matrix,
                                           saving=self.saving,
                                           restoring=self.restoring,
                                           on_configure=self.on_configure)

                self._buttons.label_1.setText(label_1)
                self._buttons.label_3.setText(label_3)
                self._buttons.manage_ranking.connect(self.set_ranking)
                self._buttons.curr_time = curr_time
                self._buttons.timer.start(1000)

                self._root.removeTab(1)
                self._root.insertTab(1, self._buttons, 'Game')
                self._root.setCurrentIndex(1)

                self.saving.setDisabled(False)

                print(
                    '__________________________________________________________________________'
                )
                print('matrix')
                print()

                print(self.matrix)
                print(
                    '__________________________________________________________________________'
                )
                print('m_sum')
                print()
                print(self.m_sum)
                print(
                    '__________________________________________________________________________'
                )
                print()

                for i in range(width):
                    for j in range(height):
                        self._buttons.btn_matrix[i][j].update()
コード例 #12
0
class MainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        url = "http://127.0.0.1:43110/1HeLLo4uzjaLetFx6NH3PMwFP3qbRbTf3D/"
        if "url" in kwargs:
            url = kwargs["url"]
            print url
            del kwargs["url"]
        super(MainWindow, self).__init__(*args, **kwargs)

        # Tabs
        self.tabs = QTabWidget()
        self.tabs.setTabsClosable(True)
        self.tabs.tabCloseRequested.connect(self.close_tab)

        # New tab button
        #self.tab_add_button_index = self.tabs.addTab(QWidget(), '+')
        self.add_tab_button = QToolButton()
        self.add_tab_button.setText('+')
        self.add_tab_button.setStyleSheet(
            'QToolButton {border: none; margin: 4px 20px 4px 0px; height: 480px; border-left: 1px solid lightgrey; padding: 0px 4px 0px 4px; font-weight: bold; color: #5d5b59}'
            'QToolButton:hover { background-color: lightgrey }'
            'QToolButton:pressed { background-color: grey }')
        self.add_tab_button.clicked.connect(self.new_tab_clicked)
        self.tabs.setCornerWidget(self.add_tab_button)

        # Navigation bar
        self.navigation = NavigationBar()
        self.navigation.url_bar.returnPressed.connect(self.navigate_to_url)

        # Back
        self.navigation.back_btn.triggered.connect(
            lambda: self.tabs.currentWidget().back())

        # Next
        self.navigation.next_btn.triggered.connect(
            lambda: self.tabs.currentWidget().forward())

        # Reload
        self.navigation.reload_btn.triggered.connect(
            lambda: self.tabs.currentWidget().reload())
        self.navigation.shortcut_reload.activated.connect(
            lambda: self.tabs.currentWidget().reload())
        self.navigation.shortcut_reload_f5.activated.connect(
            lambda: self.tabs.currentWidget().reload())

        # Home
        self.navigation.home_btn.triggered.connect(self.go_home)

        # Add new tab
        self.add_new_tab(url, "Home")

        # Get everything fitting in the main window
        self.addToolBar(self.navigation)
        self.setCentralWidget(self.tabs)
        self.show()
        self.setWindowTitle("ZeroNet Browser")
        self.setWindowIcon(QIcon("icons/zeronet-logo.svg"))
        self.showMaximized()

    def update_url_bar(self, q, browser=None):

        if browser != self.tabs.currentWidget():
            # If this signal is not from the current tab, ignore
            return

        url_array = q.toString().split('/')[3:]
        formatted_url = '/'.join(str(x) for x in url_array)
        self.navigation.url_bar.setText('zero://' + formatted_url)
        self.navigation.url_bar.setCursorPosition(0)

        if (self.tabs.currentWidget().can_go_back()):
            self.navigation.back_btn.setDisabled(False)
        else:
            self.navigation.back_btn.setDisabled(True)

        if (self.tabs.currentWidget().can_go_forward()):
            self.navigation.next_btn.setDisabled(False)
        else:
            self.navigation.next_btn.setDisabled(True)

    def navigate_to_url(self):
        # Get url
        url = self.navigation.url_bar.text()

        if url.startswith('zero://'):
            # ZeroNet protocol
            url_array = url.split('/')
            url = 'http://127.0.0.1:43110/' + url_array[2]
        elif url.startswith('http://'):
            # http protocol
            pass
        else:
            # Nothing mentionned
            url = 'http://127.0.0.1:43110/' + url

        self.tabs.currentWidget().setUrl(QUrl(url))

    def go_home(self):
        self.tabs.currentWidget().setUrl(
            QUrl("http://127.0.0.1:43110/1HeLLo4uzjaLetFx6NH3PMwFP3qbRbTf3D/"))

    def new_tab_clicked(self):
        self.add_new_tab(
            "http://127.0.0.1:43110/1HeLLo4uzjaLetFx6NH3PMwFP3qbRbTf3D/",
            "Home")

    def add_new_tab(self, qurl, label):
        # Instead of browser it should be called WebView !
        browser = Browser()
        browser.urlChanged.connect(
            lambda qurl, browser=browser: self.update_url_bar(qurl, browser))
        indexTab = self.tabs.addTab(browser, label)
        self.tabs.setCurrentIndex(indexTab)
        # We need to update the url !
        if qurl.startswith('zero://'):
            # ZeroNet protocol
            url_array = qurl.split('/')
            qurl = 'http://127.0.0.1:43110/' + url_array[2]
        elif qurl.startswith('http://'):
            # http protocol
            pass
        else:
            # Nothing mentionned
            qurl = 'http://127.0.0.1:43110/' + qurl
        self.tabs.currentWidget().setUrl(QUrl(qurl))
        return indexTab

    def close_tab(self, index):
        if self.tabs.count() == 1:
            self.tabs.currentWidget().setUrl(
                QUrl(
                    "http://127.0.0.1:43110/1HeLLo4uzjaLetFx6NH3PMwFP3qbRbTf3D/"
                ))
            return
        self.tabs.removeTab(index)
コード例 #13
0
ファイル: __main__.py プロジェクト: ULUdev/bird-browser
class MainWindow(QMainWindow):
    """
	the main render proccess of the browser including all updating methods and the webview
	"""
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
        self.url = {}
        self.setWindowTitle("Bird-Browser")
        self.wordlist = [
            "dev://", "bookmark://", "bookmarks://", "search://", "http://",
            "https://", "pwd://"
        ]
        self.tabs = QTabWidget()
        self.tabcreate = QPushButton("+")
        self.shortcreatetab = QShortcut(self)
        self.shortcreatetab.setKey("Ctrl+T")
        self.pwdman = pwdmanager.PwdManager(
            config["key"], f"{Path.home()}/.config/bird/database.db")

        if "style" in config:
            innerstyle = f"""
					color: {config['style']['color']};
					background-color: {config['style']['background-color']};
			"""
            self.setStyleSheet(f"""
				QMainWindow{
					{innerstyle}
				}
					""")
            self.tabs.setStyleSheet(f"""
				QTabWidget{
					{innerstyle}
				}
			""")
        else:
            self.setStyleSheet("""
				background-color: rgb(50, 50, 50);
				color: rgb(255, 255, 255);
			""")
            self.tabs.setStyleSheet("""
				background-color: rgb(50, 50, 50);
				color: rgb(255, 255, 255);
			""")
        self.tabs.clear()

        self.tabs.setTabsClosable(True)

        self.createtab()

        #connections
        self.shortcreatetab.activated.connect(self.createtab)
        self.tabcreate.clicked.connect(self.createtab)
        self.tabs.tabCloseRequested.connect(self.closetab)
        self.tabs.setCornerWidget(self.tabcreate)

        #show window
        self.setCentralWidget(self.tabs)
        self.show()

    def updatewin(self, browser: QWebEngineView, boolean=True):
        """
		This Method updates the shown browser window to the current url of the search bar
		it also contains the search engine-integration, and bookmarking
		"""
        url = self.url[str(self.tabs.currentIndex)]
        if url.startswith("search://"):
            search = url.split("search://", 1)[1]
            url = config["search-engine"].format(search=search)
        elif url.startswith("bookmarks://"):
            try:
                name = url.split("bookmarks://", 1)[1]
                url = bmk.getBookmark(cursor, name)[name]
            except ValueError:
                url = "about:blank"
        elif url.startswith("bookmark://"):
            if not "|" in url.split("bookmark://", 1)[1]:
                url = "about:blank"
            else:
                parts = url.split("bookmark://", 1)[1].split("|")
                if parts[1] == "-":
                    parts[1] = browser.url().toString()
                try:
                    bmk.getBookmark(cursor, parts[0])
                    bmk.modifyBookmark(cursor, parts[0], parts[0], parts[1])
                    conn.commit()
                except:
                    bmk.addBookmark(cursor, parts[0], parts[1])
                    conn.commit()
        elif url.startswith("file://"):
            path = url.split("file://", 1)[1]
            if path.startswith("~/"):
                path = f"{Path.home()}/{path.split('~/', 1)[1]}"
            try:
                with open(path, "r") as reqfile:
                    reqcontent = reqfile.read()
                browser.page().setHtml(reqcontent)
                return
            except:
                print(f"Error on requested page: Path '{path}' doesn't exist")
                browser.page().loadUrl(QUrl("about:blank"))
        elif url.startswith("dev://"):
            url = url.split("dev://", 1)[1]
            if not url.startswith("https://") and not url.startswith(
                    "http://"):
                url = "http://" + url
            self.tabs.addTab(devtools.DevToolWidget(url), "dev-tools")
        elif url.startswith("pwd://"):
            self.tabs.addTab(pwdmanager.PwdManagerWidget(self.pwdman),
                             "Passwords")
            return
        elif "additional-search-engines" in config:
            for source in config["additional-search-engines"]:
                if url.startswith(source):
                    search = url.split(source, 1)[1]
                    url = config["additional-search-engines"][source].format(
                        search=search)
                    break
                else:
                    pass
            else:
                if not url.startswith("https://") and not url.startswith(
                        "http://"):
                    url = "http://" + url
        elif not url.startswith("https://") and not url.startswith("http://"):
            url = "http://" + url
        browser.page().load(QUrl(url))
        self.wordlist.append(url)

    def updatetext(self, text: str):
        """
		This Method updates the internal text of the search bar
		"""
        self.url[str(self.tabs.currentIndex)] = text

    def updateurl(self, url, bar):
        """
		This method updates the url bar to the currently displayed url.
		It gets triggered if the displayed page directs you to a different page
		"""
        bar.setText(url.toString())

    def updatetab(self, arg_1, index, browser):
        if len(browser.page().title()) > 20:
            self.tabs.setTabText(index, browser.page().title()[0:17] + "...")
        else:
            self.tabs.setTabText(index, browser.page().title())
        self.tabs.setTabIcon(index, browser.page().icon())

    def updatetitle(self, title: str):
        self.tabs.setTabText(self.tabs.currentIndex(), title)

    def updateicon(self, index, icon):
        self.tabs.setTabIcon(index, icon)

    def closetab(self, index):
        if index == self.tabs.currentIndex():
            self.tabs.setCurrentIndex(index - 1 if index != 0 else index + 1)
        self.tabs.removeTab(index)
        if self.tabs.count() == 0:
            sys.exit(0)

    @pyqtSlot()
    def createtab(self, url: str = config["startup-url"]):
        layout = QGridLayout()
        widget = QWidget()
        widget.setLayout(layout)
        bar = QLineEdit()
        completer = QCompleter(self.wordlist)
        browser = QWebEngineView()
        backbtn = QPushButton("←")
        reloadbtn = QPushButton("reload")
        gotocurrenturlbutton = QPushButton("go!")
        reloadshort = QShortcut(self)
        reloadshort.setKey("Ctrl+R")
        bar.setCompleter(completer)
        reloadshort.activated.connect(browser.reload)
        gotocurrenturlbutton.clicked.connect(
            lambda clicked, browser=browser: self.updatewin(browser, clicked))
        reloadbtn.clicked.connect(browser.reload)
        bar.returnPressed.connect(
            lambda browser=browser: self.updatewin(browser, True))
        bar.textChanged.connect(self.updatetext)
        browser.load(QUrl(url))
        browser.page().urlChanged.connect(
            lambda qurl, bar=bar: self.updateurl(qurl, bar))
        browser.page().loadFinished.connect(
            lambda arg__1, index=self.tabs.indexOf(browser), browser=browser:
            self.updatetab(arg__1, index, browser))
        browser.page().iconChanged.connect(lambda qicon, index=self.tabs.count(
        ): self.updateicon(index, qicon))
        browser.page().setUrlRequestInterceptor(NetworkFilter)
        browser.page().titleChanged.connect(
            lambda title=browser.page().title(): self.updatetitle(title))
        backbtn.clicked.connect(browser.back)
        layout.addWidget(bar, 1, 3)
        layout.addWidget(reloadbtn, 1, 2)
        layout.addWidget(browser, 2, 1, 1, 5)
        layout.addWidget(backbtn, 1, 1)
        layout.addWidget(gotocurrenturlbutton, 1, 4)
        self.tabs.addTab(widget, browser.icon(), browser.title())
        self.tabs.setCurrentIndex(self.tabs.count() - 1)

    def renderDevToolsView(self, webview):
        return self.tabs.setCurrentWidget(
            devtools.DevToolWidget(webview.page().url().toString()))
コード例 #14
0
ファイル: main2.py プロジェクト: Neutree/COMTool
class MainWindow(CustomTitleBarWindowMixin, QMainWindow):
    hintSignal = pyqtSignal(str, str,
                            str)  # type(error, warning, info), title, msg
    # statusBarSignal = pyqtSignal(str, str)
    updateSignal = pyqtSignal(object)
    # countUpdateSignal = pyqtSignal(int, int)
    reloadWindowSignal = pyqtSignal(str, str, object)
    receiveCount = 0
    sendCount = 0
    DataPath = "./"
    app = None
    needRestart = False

    def __init__(self, app, eventFilter, config):
        QMainWindow.__init__(self)
        self.app = app
        self.eventFilter = eventFilter
        self.DataPath = parameters.dataPath
        self.config = config
        log.i("init main window")
        self.initVar()
        self.initWindow()
        self.uiLoadConfigs()
        log.i("init main window complete")
        self.loadPluginsInfoList()
        self.loadPluginItems()
        log.i("load plugin items complete")
        self.initEvent()

    def initVar(self):
        self.loadPluginStr = _("Load plugin from file")
        self.closeTimerId = None
        self.items = []
        self.pluginClasses = []
        self.helpWindow = None

    def loadPluginsInfoList(self):
        for id, pluginClass in builtinPlugins.items():
            self.addPluginInfo(pluginClass)
            self.pluginClasses.append(pluginClass)
        rm = []
        for uid, info in self.config["pluginsInfo"]["external"].items():
            pluginClass = self._importPlugin(info["path"], test=True)
            if pluginClass:
                self.addPluginInfo(pluginClass)
                self.pluginClasses.append(pluginClass)
            else:
                rm.append(uid)
        for uid in rm:
            self.config["pluginsInfo"]["external"].pop(uid)
        # find in python packages
        ignore_paths = ["DLLs"]
        for path in sys.path:
            if os.path.isdir(path) and not path in ignore_paths:
                for name in os.listdir(path):
                    if name.lower().startswith(
                            "comtool_plugin_"
                    ) and not name.endswith("dist-info"):
                        log.i(f"find plugin package <{name}>")
                        pluginClass = __import__(name).Plugin
                        print(pluginClass, self.pluginClasses)
                        if not pluginClass in self.pluginClasses:
                            self.addPluginInfo(pluginClass)
                            self.pluginClasses.append(pluginClass)

    def getPluginClassById(self, id):
        '''
            must call after loadPluginsInfoList
        '''
        for pluginClass in self.pluginClasses:
            if id == pluginClass.id:
                return pluginClass
        return None

    def loadPluginItems(self):
        items = self.config["items"]
        if items:
            for item in items:
                log.i("load plugin item", item["name"])
                pluginClass = self.getPluginClassById(item["pluginId"])
                if pluginClass:
                    setCurr = False
                    if self.config["currItem"] == item["name"]:
                        setCurr = True
                    # check language change, update item name to current lanuage
                    old_name_tail = item["name"].split(" ")[-1]
                    try:
                        int(old_name_tail)
                        item["name"] = pluginClass.name + " " + old_name_tail
                    except Exception:  # for no number tailed name
                        item["name"] = pluginClass.name
                    self.addItem(pluginClass,
                                 nameSaved=item["name"],
                                 setCurrent=setCurr,
                                 connsConfigs=item["config"]["conns"],
                                 pluginConfig=item["config"]["plugin"])
        else:  # load builtin plugins
            for id, pluginClass in builtinPlugins.items():
                self.addItem(pluginClass)

    def addItem(self,
                pluginClass,
                nameSaved=None,
                setCurrent=False,
                connsConfigs=None,
                pluginConfig=None):
        '''
            @name add saved item, not add new item
        '''
        # set here, not set in arg, cause arg can lead to multi item use one object
        if not connsConfigs:
            connsConfigs = {}
        if not pluginConfig:
            pluginConfig = {}
        if nameSaved:
            name = nameSaved
        else:
            numbers = []
            for item in self.items:
                if item.plugin.id == pluginClass.id:
                    name = item.name.replace(item.plugin.name, "").split(" ")
                    if len(name) > 1:
                        number = int(name[-1])
                        numbers.append(number)
                    else:
                        numbers.append(0)
            if numbers:
                numbers = sorted(numbers)
            if (not numbers) or numbers[0] != 0:
                name = pluginClass.name
            else:
                last = numbers[0]
                number = -1
                for n in numbers[1:]:
                    if n != last + 1:
                        number = last + 1
                        break
                    last = n
                if number < 0:
                    number = numbers[-1] + 1
                name = f'{pluginClass.name} {number}'
        item = PluginItem(name, pluginClass, conns, connsConfigs, self.config,
                          pluginConfig, self.hintSignal,
                          self.reloadWindowSignal)
        self.tabAddItem(item)
        self.items.append(item)
        if setCurrent:
            self.tabWidget.setCurrentWidget(item.widget)
        if not nameSaved:
            self.config["items"].append({
                "name": name,
                "pluginId": pluginClass.id,
                "config": {
                    "conns": connsConfigs,
                    "plugin": pluginConfig
                }
            })
        return item

    def tabAddItem(self, item):
        self.tabWidget.addTab(item.widget, item.name)

    def addPluginInfo(self, pluginClass):
        self.pluginsSelector.insertItem(
            self.pluginsSelector.count() - 1,
            f'{pluginClass.name} - {pluginClass.id}')

    def _importPlugin(self, path, test=False):
        if not os.path.exists(path):
            return None
        dir = os.path.dirname(path)
        name = os.path.splitext(os.path.basename(path))[0]
        sys.path.insert(0, dir)
        try:
            print("import")
            pluginClass = __import__(name).Plugin
        except Exception as e:
            import traceback
            msg = traceback.format_exc()
            self.hintSignal.emit("error", _("Error"),
                                 '{}: {}'.format(_("Load plugin failed"), msg))
            return None
        if test:
            sys.path.remove(dir)
        return pluginClass

    def loadExternalPlugin(self, path):
        extPlugsInfo = self.config["pluginsInfo"]["external"]
        found = False
        for uid, info in extPlugsInfo.items():
            if info["path"] == path:
                for pluginClass in self.pluginClasses:
                    # same plugin
                    if uid == pluginClass.id:
                        self.addItem(pluginClass, setCurrent=True)
                        found = True
                        break
                if found:
                    return True, ""
        pluginClass = self._importPlugin(path)
        if not pluginClass:
            return False, _("Load plugin fail")
        extPlugsInfo[pluginClass.id] = {"path": path}
        if not pluginClass in self.pluginClasses:
            self.pluginClasses.append(pluginClass)
            self.addPluginInfo(pluginClass)
        # find old item config for this plugin and recover
        oldFound = False
        for item in self.config["items"]:
            if item["pluginId"] == pluginClass.id:
                self.addItem(pluginClass,
                             nameSaved=item["name"],
                             setCurrent=True,
                             connsConfigs=item["config"]["conns"],
                             pluginConfig=item["config"]["plugin"])
                oldFound = True
                break
        if not oldFound:
            self.addItem(pluginClass, setCurrent=True)
        return True, ""

    def onPluginSelectorChanged(self, idx):
        text = self.pluginsSelector.currentText()
        if text == self.loadPluginStr:
            oldPath = os.getcwd()
            fileName_choose, filetype = QFileDialog.getOpenFileName(
                self, _("Select file"), oldPath, _("python script (*.py)"))
            if fileName_choose != "":
                ok, msg = self.loadExternalPlugin(fileName_choose)
                if not ok:
                    self.hintSignal.emit("error", _("Error"),
                                         f'{_("Load plugin error")}: {msg}')
        else:
            loadID = text.split("-")[-1].strip()
            for pluginClass in self.pluginClasses:
                if loadID == pluginClass.id:
                    self.addItem(pluginClass, setCurrent=True)
                    break

    def initWindow(self):
        # set skin for utils_ui
        utils_ui.setSkin(self.config["skin"])
        # menu layout
        self.settingsButton = QPushButton()
        self.skinButton = QPushButton("")
        self.languageCombobox = ButtonCombbox(icon="fa.language",
                                              btnClass="smallBtn2")
        self.languages = i18n.get_languages()
        for locale in self.languages:
            self.languageCombobox.addItem(self.languages[locale])
        self.aboutButton = QPushButton()
        self.functionalButton = QPushButton()
        self.encodingCombobox = ComboBox()
        self.supportedEncoding = parameters.encodings
        for encoding in self.supportedEncoding:
            self.encodingCombobox.addItem(encoding)
        self.settingsButton.setProperty("class", "menuItem1")
        self.skinButton.setProperty("class", "menuItem2")
        self.aboutButton.setProperty("class", "menuItem3")
        self.functionalButton.setProperty("class", "menuItem4")
        self.settingsButton.setObjectName("menuItem")
        self.skinButton.setObjectName("menuItem")
        self.aboutButton.setObjectName("menuItem")
        self.functionalButton.setObjectName("menuItem")
        # plugins slector
        self.pluginsSelector = ButtonCombbox(icon="fa.plus",
                                             btnClass="smallBtn2")
        self.pluginsSelector.addItem(self.loadPluginStr)
        self.pluginsSelector.activated.connect(self.onPluginSelectorChanged)

        # title bar
        title = parameters.appName + " v" + version.__version__
        iconPath = self.DataPath + "/" + parameters.appIcon
        log.i("icon path: " + iconPath)
        self.titleBar = TitleBar(self,
                                 icon=iconPath,
                                 title=title,
                                 brothers=[],
                                 widgets=[[self.skinButton, self.aboutButton],
                                          []])
        CustomTitleBarWindowMixin.__init__(self,
                                           titleBar=self.titleBar,
                                           init=True)

        # root layout
        self.frameWidget = QWidget()
        self.frameWidget.setMouseTracking(True)
        self.frameWidget.setLayout(self.rootLayout)
        self.setCentralWidget(self.frameWidget)
        # tab widgets
        self.tabWidget = QTabWidget()
        self.tabWidget.setTabsClosable(True)
        # tab left menu
        tabConerWidget = QWidget()
        tabConerLayout = QHBoxLayout()
        tabConerLayout.setSpacing(0)
        tabConerLayout.setContentsMargins(0, 0, 0, 0)
        tabConerWidget.setLayout(tabConerLayout)
        tabConerLayout.addWidget(self.settingsButton)
        # tab right menu
        tabConerWidgetRight = QWidget()
        tabConerLayoutRight = QHBoxLayout()
        tabConerLayoutRight.setSpacing(0)
        tabConerLayoutRight.setContentsMargins(0, 0, 0, 0)
        tabConerWidgetRight.setLayout(tabConerLayoutRight)
        tabConerLayoutRight.addWidget(self.pluginsSelector)
        tabConerLayoutRight.addWidget(self.languageCombobox)
        tabConerLayoutRight.addWidget(self.encodingCombobox)
        tabConerLayoutRight.addWidget(self.functionalButton)
        self.tabWidget.setCornerWidget(tabConerWidget, Qt.TopLeftCorner)
        self.tabWidget.setCornerWidget(tabConerWidgetRight, Qt.TopRightCorner)
        self.contentLayout = QVBoxLayout()
        self.contentWidget.setLayout(self.contentLayout)
        self.contentLayout.setContentsMargins(10, 0, 10, 10)
        self.contentLayout.addWidget(self.tabWidget)

        if sys.platform == 'darwin':
            self.macOsAddDockMenu()

        self.resize(850, 500)
        self.MoveToCenter()
        self.show()

    def add_new_window(self):
        import copy
        mainWindow = MainWindow(self.app, self.eventFilter,
                                copy.deepcopy(self.config))
        self.eventFilter.listenWindow(mainWindow)
        g_all_windows.append(mainWindow)

    def macOsAddDockMenu(self):
        self.dockMenu = QMenu(self)
        self.dockMenu.addAction(_('New Window'), self.add_new_window)
        self.dockMenu.setAsDockMenu()
        self.app.setAttribute(Qt.AA_DontShowIconsInMenus, True)

    def initEvent(self):
        # menu
        self.settingsButton.clicked.connect(self.toggleSettings)
        self.languageCombobox.currentIndexChanged.connect(
            self.onLanguageChanged)
        self.encodingCombobox.currentIndexChanged.connect(lambda: self.bindVar(
            self.encodingCombobox, self.config, "encoding"))
        self.functionalButton.clicked.connect(self.toggleFunctional)
        self.skinButton.clicked.connect(self.skinChange)
        self.aboutButton.clicked.connect(self.showAbout)
        # main
        self.tabWidget.currentChanged.connect(self.onSwitchTab)
        self.tabWidget.tabCloseRequested.connect(self.closeTab)
        # others
        self.updateSignal.connect(self.showUpdate)
        self.hintSignal.connect(self.showHint)
        self.reloadWindowSignal.connect(self.onReloadWindow)

    def bindVar(self,
                uiObj,
                varObj,
                varName: str,
                vtype=None,
                vErrorMsg="",
                checkVar=lambda v: v,
                invert=False):
        objType = type(uiObj)
        if objType == QCheckBox:
            v = uiObj.isChecked()
            if hasattr(varObj, varName):
                varObj.__setattr__(varName, v if not invert else not v)
            else:
                varObj[varName] = v if not invert else not v
            return
        elif objType == QLineEdit:
            v = uiObj.text()
        elif objType == ComboBox:
            if hasattr(varObj, varName):
                varObj.__setattr__(varName, uiObj.currentText())
            else:
                varObj[varName] = uiObj.currentText()
            return
        elif objType == QRadioButton:
            v = uiObj.isChecked()
            if hasattr(varObj, varName):
                varObj.__setattr__(varName, v if not invert else not v)
            else:
                varObj[varName] = v if not invert else not v
            return
        else:
            raise Exception("not support this object")
        if vtype:
            try:
                v = vtype(v)
            except Exception:
                uiObj.setText(str(varObj.__getattribute__(varName)))
                self.hintSignal.emit("error", _("Error"), vErrorMsg)
                return
        try:
            v = checkVar(v)
        except Exception as e:
            self.hintSignal.emit("error", _("Error"), str(e))
            return
        varObj.__setattr__(varName, v)

    def onSwitchTab(self, idx):
        self.config["currItem"] = self.items[idx].name
        item = self.getCurrentItem()
        item.plugin.onActive()

    def closeTab(self, idx):
        # only one, ignore
        if self.tabWidget.count() == 1:
            return
        self.tabWidget.removeTab(idx)
        item = self.items.pop(idx)
        for _item in self.config["items"]:
            if _item["name"] == item.name:
                self.config["items"].remove(_item)
                break

    def updateStyle(self, widget):
        self.frameWidget.style().unpolish(widget)
        self.frameWidget.style().polish(widget)
        self.frameWidget.update()

    def onLanguageChanged(self):
        idx = self.languageCombobox.currentIndex()
        locale = list(self.languages.keys())[idx]
        self.config["locale"] = locale
        i18n.set_locale(locale)
        reply = QMessageBox.question(
            self, _('Restart now?'),
            _("language changed to: ") +
            self.languages[self.config["locale"]] + "\n" +
            _("Restart software to take effect now?"),
            QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        if reply == QMessageBox.Yes:
            self.needRestart = True
            self.close()

    def onReloadWindow(self, title, msg, callback):
        if not title:
            title = _('Restart now?')
        reply = QMessageBox.question(self, title, msg,
                                     QMessageBox.Yes | QMessageBox.No,
                                     QMessageBox.No)
        if reply == QMessageBox.Yes:
            callback(True)
            self.needRestart = True
            self.close()
        else:
            callback(False)

    def MoveToCenter(self):
        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

    def showHint(self, info_type: str, title: str, msg: str):
        if info_type == "info":
            QMessageBox.information(self, title, msg)
        elif info_type == "warning":
            QMessageBox.warning(self, title, msg)
        elif info_type == "error":
            QMessageBox.critical(self, title, msg)

    def closeEvent(self, event):
        if self.closeTimerId:
            event.accept()
            return
        print("----- close event")
        # reply = QMessageBox.question(self, 'Sure To Quit?',
        #                              "Are you sure to quit?", QMessageBox.Yes |
        #                              QMessageBox.No, QMessageBox.No)
        if 1:  # reply == QMessageBox.Yes:
            self.receiveProgressStop = True
            # inform plugins
            for item in self.items:
                item.onDel()
            self.saveConfig()
            # actual exit after 500ms
            self.closeTimerId = self.startTimer(500)
            self.setWindowTitle(_("Closing ..."))
            self.titleBar.setTitle(_("Closing ..."))
            self.setEnabled(False)
            if self.helpWindow:
                self.helpWindow.close()
            event.ignore()
        else:
            event.ignore()

    def timerEvent(self, e):
        if self.closeTimerId:
            log.i("Close window")
            self.killTimer(self.closeTimerId)
            self.close()

    def saveConfig(self):
        # print("save config:", self.config)
        self.config.save(parameters.configFilePath)
        print("save config compelte")

    def uiLoadConfigs(self):
        # language
        try:
            idx = list(self.languages.keys()).index(self.config["locale"])
        except Exception:
            idx = 0
        self.languageCombobox.setCurrentIndex(idx)
        # encoding
        self.encodingCombobox.setCurrentIndex(
            self.supportedEncoding.index(self.config["encoding"]))

    def keyPressEvent(self, event):
        CustomTitleBarWindowMixin.keyPressEvent(self, event)
        item = self.getCurrentItem()
        item.onKeyPressEvent(event)

    def keyReleaseEvent(self, event):
        CustomTitleBarWindowMixin.keyReleaseEvent(self, event)
        item = self.getCurrentItem()
        item.onKeyReleaseEvent(event)

    def getCurrentItem(self):
        widget = self.tabWidget.currentWidget()
        for item in self.items:
            if item.widget == widget:
                return item

    def toggleSettings(self):
        widget = self.getCurrentItem().settingWidget
        if widget.isVisible():
            self.hideSettings()
        else:
            self.showSettings()

    def showSettings(self):
        widget = self.getCurrentItem().settingWidget
        widget.show()
        self.settingsButton.setStyleSheet(
            parameters.strStyleShowHideButtonLeft.replace(
                "$DataPath", self.DataPath))

    def hideSettings(self):
        widget = self.getCurrentItem().settingWidget
        widget.hide()
        self.settingsButton.setStyleSheet(
            parameters.strStyleShowHideButtonRight.replace(
                "$DataPath", self.DataPath))

    def toggleFunctional(self):
        widget = self.getCurrentItem().functionalWidget
        if widget is None:
            return
        if widget.isVisible():
            self.hideFunctional()
        else:
            self.showFunctional()

    def showFunctional(self):
        widget = self.getCurrentItem().functionalWidget
        if not widget is None:
            widget.show()
        self.functionalButton.setStyleSheet(
            parameters.strStyleShowHideButtonRight.replace(
                "$DataPath", self.DataPath))

    def hideFunctional(self):
        widget = self.getCurrentItem().functionalWidget
        if not widget is None:
            widget.hide()
        self.functionalButton.setStyleSheet(
            parameters.strStyleShowHideButtonLeft.replace(
                "$DataPath", self.DataPath))

    def skinChange(self):
        if self.config["skin"] == "light":  # light
            file = open(self.DataPath + '/assets/qss/style-dark.qss',
                        "r",
                        encoding="utf-8")
            self.config["skin"] = "dark"
        else:  # elif self.config["skin"] == 2: # dark
            file = open(self.DataPath + '/assets/qss/style.qss',
                        "r",
                        encoding="utf-8")
            self.config["skin"] = "light"
        self.app.setStyleSheet(file.read().replace("$DataPath", self.DataPath))
        utils_ui.setSkin(self.config["skin"])

    def showAbout(self):
        help = helpAbout.HelpInfo()
        pluginsHelp = {_("About"): help}
        for p in self.pluginClasses:
            if not p.help is None:
                pluginsHelp[p.name] = p.help
        iconPath = self.DataPath + "/" + parameters.appIcon
        self.helpWindow = HelpWidget(pluginsHelp, icon=iconPath)
        self.helpWindow.closed.connect(self.helpWindowClosed)
        self.eventFilter.listenWindow(self.helpWindow)

    def helpWindowClosed(self):
        self.eventFilter.unlistenWindow(self.helpWindow)
        self.helpWindow = None
        # self.helpWindow

    def showUpdate(self, versionInfo):
        versionInt = versionInfo.int()
        if self.config.basic["skipVersion"] and self.config.basic[
                "skipVersion"] >= versionInt:
            return
        msgBox = QMessageBox()
        desc = versionInfo.desc if len(
            versionInfo.desc) < 300 else versionInfo.desc[:300] + " ... "
        link = '<a href="https://github.com/Neutree/COMTool/releases">github.com/Neutree/COMTool/releases</a>'
        info = '{}<br>{}<br><br>v{}: {}<br><br>{}'.format(
            _("New versioin detected, please click learn more to download"),
            link, '{}.{}.{}'.format(versionInfo.major, versionInfo.minor,
                                    versionInfo.dev), versionInfo.name, desc)
        learn = msgBox.addButton(_("Learn More"), QMessageBox.YesRole)
        skip = msgBox.addButton(_("Skip this version"), QMessageBox.YesRole)
        nextTime = msgBox.addButton(_("Remind me next time"),
                                    QMessageBox.NoRole)
        msgBox.setWindowTitle(_("Need update"))
        msgBox.setText(info)
        result = msgBox.exec_()
        if result == 0:
            auto = autoUpdate.AutoUpdate()
            auto.OpenBrowser()
        elif result == 1:
            self.config.basic["skipVersion"] = versionInt

    def autoUpdateDetect(self):
        auto = autoUpdate.AutoUpdate()
        needUpdate, versionInfo = auto.detectNewVersion()
        if needUpdate:
            self.updateSignal.emit(versionInfo)