コード例 #1
0
class ViewSourceDialogTabber(QMainWindow):
    def __init__(self, parent=None, title="Source"):
        super(ViewSourceDialogTabber, self).__init__(parent)
        self.setWindowTitle(title)
        self.tabs = QTabWidget(self)
        self.tabs.setElideMode(Qt.ElideRight)
        self.tabs.setTabsClosable(True)
        self.tabs.tabCloseRequested.connect(self.removeTab)
        self.setCentralWidget(self.tabs)
        self.tabs.currentChanged.connect(self.updateWindowTitle)

    def sizeHint(self):
        return QSize(640, 480)

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

    def addTab(self, title="New Tab", data=""):
        vsd = ViewSourceDialog(self, str(title))
        vsd.setPlainText(data)
        self.tabs.addTab(vsd, tr("Source of %s") % (title, ))
        self.tabs.setCurrentIndex(self.tabs.count() - 1)
        self.raise_()
        self.activateWindow()

    def updateWindowTitle(self):
        try:
            self.setWindowTitle(
                tr("Source of %s") %
                (self.tabs.currentWidget().windowTitle(), ))
        except:
            pass
        if self.tabs.count() == 0:
            self.hide()
コード例 #2
0
class ViewSourceDialogTabber(QMainWindow):
    def __init__(self, parent=None, title="Source"):
        super(ViewSourceDialogTabber, self).__init__(parent)
        self.setWindowTitle(title)
        self.tabs = QTabWidget(self)
        self.tabs.setElideMode(Qt.ElideRight)
        self.tabs.setTabsClosable(True)
        self.tabs.tabCloseRequested.connect(self.removeTab)
        self.setCentralWidget(self.tabs)
        self.tabs.currentChanged.connect(self.updateWindowTitle)
    def sizeHint(self):
        return QSize(640, 480)
    def removeTab(self):
        self.tabs.removeTab(self.tabs.currentIndex())
    def addTab(self, title="New Tab", data=""):
        vsd = ViewSourceDialog(self, str(title))
        vsd.setPlainText(data)
        self.tabs.addTab(vsd, tr("Source of %s") % (title,))
        self.tabs.setCurrentIndex(self.tabs.count()-1)
        self.raise_()
        self.activateWindow()
    def updateWindowTitle(self):
        try: self.setWindowTitle(tr("Source of %s") % (self.tabs.currentWidget().windowTitle(),))
        except: pass
        if self.tabs.count() == 0:
            self.hide()
コード例 #3
0
class SettingsDialog(QDialog):
    __tab_classes = [SettingsDialogGeneral, SettingsDialogUpdates]

    def __init__(self, main_window):
        super().__init__(main_window)
        if os.name == 'nt':
            self.setWindowTitle(_("Options"))
        else:
            self.setWindowTitle(_("Preferences"))

        layout = QVBoxLayout()

        self.__tabs = QTabWidget()
        layout.addWidget(self.__tabs)

        for tab_class in self.__tab_classes:
            self.__tabs.addTab(tab_class(self), "")

        self.__button_box = QDialogButtonBox(QDialogButtonBox.Ok
                                             | QDialogButtonBox.Cancel
                                             | QDialogButtonBox.Apply)

        self.__button_box.button(QDialogButtonBox.Apply).clicked.connect(
            self.__apply_clicked)

        self.__button_box.accepted.connect(self.__accept_clicked)
        self.__button_box.rejected.connect(self.reject)

        layout.addWidget(self.__button_box)

        self.setLayout(layout)

        Application().event_dispatcher.subscribe(LanguageChangedEvent,
                                                 self.__language_changed)

        self.__reload_texts()

    def __apply_clicked(self, checked=False):
        self.__apply_settings()

    def __accept_clicked(self):
        self.__apply_settings()
        self.accept()

    def __apply_settings(self):
        for no in range(self.__tabs.count()):
            self.__tabs.widget(no).apply_settings()

    def __language_changed(self, event):
        self.__reload_texts()

    def __reload_texts(self):
        self.__button_box.button(QDialogButtonBox.Ok).setText(_("Ok"))
        self.__button_box.button(QDialogButtonBox.Cancel).setText(_("Cancel"))
        self.__button_box.button(QDialogButtonBox.Apply).setText(_("Apply"))

        for no in range(self.__tabs.count()):
            widget = self.__tabs.widget(no)
            widget.reload_texts()
            self.__tabs.setTabText(no, widget.get_name())
コード例 #4
0
class WholeTestView(QDialog):
    def __init__(self, fnames):
        super(WholeTestView, self).__init__()
        self.pageList = fnames
        self.numberOfPages = len(fnames)
        grid = QGridLayout()
        self.pageTabs = QTabWidget()
        self.tabs = {}
        self.closeButton = QPushButton("&Close")
        self.maxNormButton = QPushButton("&Max/Norm")
        self.pButton = QPushButton("&Previous")
        self.nButton = QPushButton("&Next")
        grid.addWidget(self.pageTabs, 1, 1, 6, 6)
        grid.addWidget(self.pButton, 7, 1)
        grid.addWidget(self.nButton, 7, 2)
        grid.addWidget(self.closeButton, 7, 7)
        grid.addWidget(self.maxNormButton, 1, 7)
        self.setLayout(grid)
        self.pButton.clicked.connect(self.previousTab)
        self.nButton.clicked.connect(self.nextTab)
        self.closeButton.clicked.connect(self.closeWindow)
        self.maxNormButton.clicked.connect(self.swapMaxNorm)

        self.setMinimumSize(500, 500)

        self.show()
        self.buildTabs()

    def swapMaxNorm(self):
        """Toggles the window size between max and normal"""
        if self.windowState() != Qt.WindowMaximized:
            self.setWindowState(Qt.WindowMaximized)
        else:
            self.setWindowState(Qt.WindowNoState)

    def closeEvent(self, event):
        self.closeWindow()

    def closeWindow(self):
        self.close()

    def nextTab(self):
        t = self.pageTabs.currentIndex() + 1
        if t >= self.pageTabs.count():
            t = 0
        self.pageTabs.setCurrentIndex(t)
        self.tabs[t].forceRedrawOrSomeBullshit()

    def previousTab(self):
        t = self.pageTabs.currentIndex() - 1
        if t < 0:
            t = self.pageTabs.count() - 1
        self.pageTabs.setCurrentIndex(t)
        self.tabs[t].forceRedrawOrSomeBullshit()

    def buildTabs(self):
        for k in range(0, self.numberOfPages):
            self.tabs[k] = ExamViewWindow(self.pageList[k])
            self.pageTabs.addTab(self.tabs[k], "{}".format(k + 1))
コード例 #5
0
class MainWidget(QWidget):
    def __init__(self, width, height, manager, perm_dict):
        super().__init__()
        self.manager = manager
        self.perm_dict = perm_dict
        self.translation = Translation(perm_dict)

        self.setWindowTitle(Constants.WINDOW_NAME)
        self.resize(width, height)

        layout = QGridLayout()
        layout.setContentsMargins(0, 0, 0, 0)

        self.tab_widget = QTabWidget()
        layout.addWidget(self.tab_widget)

        self.setLayout(layout)

        self.show()

        self.restart()

    def restart(self):
        while self.tab_widget.count() > 0:
            self.tab_widget.removeTab(0)

        # TODO uncomment once finished
        self.tab_widget.addTab(OverviewPage(self.manager, self.perm_dict),
                               self.translation.get_text("overview"))
コード例 #6
0
class QTabManager(object):
    parent_tab_widget = None
    max_tab_count = 7
    current_index_count = 0

    @classmethod
    def setParentWidget(self, parent_widget):
        self.parent_tab_widget = parent_widget

    @classmethod
    def createTab(self, title):
        if self.parent_tab_widget is None:
            self.parent_tab_widget = QTabWidget()
            self.parent_tab_widget.setMovable(True)

        if self.parent_tab_widget.count() < self.max_tab_count:
            figure_tab = QWidget()
            self.parent_tab_widget.addTab(
                figure_tab, title + " " + str(self.current_index_count + 1))
            layout = QVBoxLayout()
        else:
            figure_tab = self.parent_tab_widget.widget(
                self.current_index_count)
            figure_tab.setWindowTitle(title + " " +
                                      str(self.current_index_count + 1))
            layout = figure_tab.layout()
            clearLayout(layout)
        # Update index and connect event
        self.current_index_count = (self.current_index_count +
                                    1) % self.max_tab_count
        return figure_tab, layout
コード例 #7
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))
コード例 #8
0
ファイル: tabproxystyle.py プロジェクト: nkpatro/pipewidgets
    def subElementRect(self, element, option, widget):
        rect = QProxyStyle.subElementRect(element, option, widget)
        tabWidget = QTabWidget(widget)

        if not tabWidget:
            if element == QStyle.SE_TabWidgetLeftCorner:
                if not tabWidget.count():
                    rect.setHeight(tabWidget.cornerWidget(Qt.TopLeftCorner).height())
            elif element == QStyle.SE_TabWidgetRightCorner:
                if not tabWidget.count():
                    rect.setHeight(tabWidget.cornerWidget(Qt.TopRightCorner).height())
            if element == QStyle.SE_TabWidgetTabPane:
                if not tabWidget.count():
                    rect.setTop(tabWidget.cornerWidget(Qt.TopLeftCorner).height())

        return rect
コード例 #9
0
class ProductLists(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        super().__init__()
        self.tabsList = []
        self.layout = QVBoxLayout(self)
        self.reader = JsonReader()
        self.tabs = QTabWidget()
        self.addTabs()
        self.layout.addWidget(self.tabs)
        self.setLayout(self.layout)

    def addTabs(self):
        self.lists = self.reader.readLists()

        for list in self.lists:
            self.tabsList.append(DisplayList(list))

        self.tabsList.append(CreateNewList(self.reloadList))

        for index, tab in enumerate(self.tabsList):
            if (index < len(self.tabsList) - 1):
                self.tabs.addTab(tab, f'{self.lists[index]["list_name"]}')
            else:
                self.tabs.addTab(tab, '+')

    def reloadList(self):
        self.lists = self.reader.readLists()
        list = self.lists[self.tabs.count() - 1]
        self.tabs.addTab(DisplayList(list), f'{list["list_name"]}')
コード例 #10
0
class TransactionTab(QWidget):
    def __init__(self, parent):
        super(TransactionTab, self).__init__(parent=parent)
        layout = QVBoxLayout(self)
        self.table = TransactionTable(self)
        self.table.objectSelected.connect(self.set_instance)
        layout.addWidget(self.table)
        self.tabs = QTabWidget()
        self.debit_credit = DebitCreditTab(self)
        self.tabs.addTab(self.debit_credit, "Transaction")
        self.transfer = TransferTab(self)
        self.tabs.addTab(self.transfer, "Transfer")
        self.opening_balance = OpeningBalanceTab(self)
        self.tabs.addTab(self.opening_balance, "Opening Balance")
        layout.addWidget(self.tabs)
        self.setLayout(layout)
        self.debit_credit.refresh.connect(self.table.refresh)
        self.transfer.refresh.connect(self.table.refresh)

    def set_instance(self, instance):
        ix = self.get_tab_index(instance)
        for i in range(0, self.tabs.count()):
            tab: TransactionForm = self.tabs.widget(i)
            tab.set_instance(instance if i == ix else None)
        self.tabs.setCurrentIndex(ix)

    _types = {"C": 0, "D": 0, "T": 1, "O": 2}

    def get_tab_index(self, instance):
        return self._types.get(instance.type) if instance else 0
コード例 #11
0
ファイル: main_screen.py プロジェクト: devhashtag/2IC80
class MainScreen(AsyncWidget):
    def __init__(self, interface, parent=None):
        super().__init__(parent)

        self.interface = interface
        self.setWindowTitle('Main screen')

        self.tab_widget = QTabWidget()

        layout = QHBoxLayout(self)
        layout.addWidget(self.tab_widget)

    @property
    def tabs(self):
        n_tabs = self.tab_widget.count()
        tabs = [self.tab_widget.widget(i) for i in range(n_tabs)]

        return tabs

    def add_tab(self, tab, name):
        self.tab_widget.addTab(tab, name)

    def remove_tab(self, tab):
        try:
            index = self.tabs.index(tab)
            self.tab_widget.removeTab(index)
        except ValueError:
            raise ValueError(f'{tab} is not in the list of tabs')
コード例 #12
0
ファイル: test_pipeline.py プロジェクト: fredtcaroli/ezCV-GUI
    def test_add_operator(self, operators_tab_widget: QTabWidget, controller):
        controller.add_operator(GaussianBlur)
        size = operators_tab_widget.count()
        assert size == 1

        operator_name = list(controller.operators.keys())[0]
        name_in_list = operators_tab_widget.tabText(0)
        assert name_in_list == operator_name
コード例 #13
0
class MonoidPreferencesWindow(QDialog):
    """
    Applications Preferences window.
    """
    def __init__(self, app, *args, **kwargs):
        super(MonoidPreferencesWindow, self).__init__(*args, **kwargs)

        self.setWindowTitle("Settings")
        self.app = app

        # Place the tab widget inside layout to get some margin.
        self.tabs = QTabWidget(self)
        self.tabs.currentChanged.connect(self.updateHeight)

        layout = QVBoxLayout(self)
        layout.addWidget(self.tabs)

        # Create each tab.
        self.generalTab = GeneralTab(self, app.settings)
        self.headerTab = HeaderTab(self, app.settings)

        # Add all the tabs.
        self.tabs.addTab(self.generalTab, "General")
        self.tabs.addTab(self.headerTab, "Header")

    def show(self, *args):
        """
        Set the size to a fixed one after showing the window to disable the minimize and maximize button.
        """
        super(MonoidPreferencesWindow, self).show(*args)
        self.setFixedSize(self.minimumSizeHint())

    def updateHeight(self, index):
        """
        Set the window height to the minimum required space.
        :param index: index of the currently selected tab
        """
        # Resize all tabs.
        for i in range(self.tabs.count()):
            if i != index:
                widget = self.tabs.widget(i)
                widget.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
                widget.resize(widget.sizeHint())
                widget.adjustSize()

        widget = self.tabs.widget(index)
        if widget:
            widget.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
            widget.resize(widget.minimumSizeHint())
            widget.adjustSize()

            # Resize the tab widget.
            self.tabs.resize(self.tabs.minimumSizeHint())
            self.tabs.adjustSize()

            # Resize the window to the fixed minimum size.
            self.setFixedSize(self.minimumSizeHint())
            self.adjustSize()
コード例 #14
0
ファイル: Project1.py プロジェクト: Prithvi3141/Project1
class OuterWidget(QWidget):
    def __init__(self, callerObject):
        super(QWidget, self).__init__(callerObject)

        self.caller = callerObject

        self.layout = QVBoxLayout(self)

        self.tabs = QTabWidget()
        self.tab1 = Form(self)

        self.tabs.setTabsClosable(True)
        self.tabs.tabCloseRequested.connect(self.tabs.removeTab)

        self.tab1.refreshRead()

        self.tabs.addTab(self.tab1, "Home")

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

    #This function is to load a tab for Average of Temperature and Humidity
    def aver(self):
        tempAvg = np.mean(listTemperature)
        humidAvg = np.mean(listHumidity)
        dateTime = datetime.today()
        print("listTemperature: ", listTemperature[0:100], "\n")
        print('Average Temperature: {0:0.1f}'.format(tempAvg))

        self.tab2 = Average(self)

        temper = '{0:0.2f}'.format(tempAvg) + ' C'
        humid = '{0:0.2f}'.format(humidAvg) + ' %'
        date = '{:%Y-%m-%d %H:%M}'.format(dateTime)

        self.tab2.textBrowser.setText(temper)
        self.tab2.textBrowser_2.setText(humid)
        self.tab2.textBrowser_3.setText(date)

        if self.tabs.count() < 2:
            averageIndex = self.tabs.addTab(self.tab2, "Mean Values")
            self.tabs.setCurrentIndex(averageIndex)
        else:
            self.tabs.setCurrentIndex(1)

    #This function is used to close this rudimentary thermostat application
    def closeApp(self):
        self.tabs.removeTab(1)
        self.tabs.removeTab(0)

        self.layout.removeWidget(self.tabs)
        self.caller.close()

    #This function is used to close the tab that was opened for Mean Data of temperature and Humidity
    def closeAvgTab(self):
        index = self.tabs.currentIndex()
        self.tabs.removeTab(index)
コード例 #15
0
ファイル: main_window.py プロジェクト: awolk/SEASide-py
class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setWindowTitle('SEASide')
        self.resize(1000, 560)
        # Connection
        self._config = Configuration()
        server_names = tuple(sorted(SERVERS.keys()))
        # Interface
        self._widg = QWidget(self)
        self.setCentralWidget(self._widg)
        # Server selection dropdown
        self._dropdown = QComboBox()
        self._dropdown.addItems(server_names)
        default_server_name = self._config.get_default_server()
        self._dropdown.setCurrentIndex(
            self._dropdown.findText(default_server_name))
        # Connect button
        self._button = QPushButton('Connect')
        self._button.clicked.connect(self._new_tab)
        # Tab view
        self._tab_view = QTabWidget()
        self._tab_view.setTabsClosable(True)
        self._tab_view.tabCloseRequested.connect(self._close_tab)
        # Default tab
        default_tab = MasterTab(SERVERS[self._config.get_default_server()],
                                self._config)
        self._tab_view.addTab(default_tab, default_server_name)
        # Layout setup
        conn_layout = QHBoxLayout()
        top_layout = QVBoxLayout()
        # conn_layout.addStretch(1)
        conn_layout.addWidget(self._button)
        conn_layout.addWidget(self._dropdown)
        conn_widg = QWidget()
        conn_widg.setLayout(conn_layout)
        top_layout.addWidget(conn_widg)
        top_layout.addWidget(self._tab_view)
        self._widg.setLayout(top_layout)

    @pyqtSlot()
    def _new_tab(self):
        server_name = str(self._dropdown.currentText())
        server = SERVERS[server_name]
        self._config.set_default_server(server_name)
        tab = MasterTab(server, self._config)
        self._tab_view.addTab(tab, server_name)
        self._tab_view.setCurrentIndex(self._tab_view.count() - 1)

    @pyqtSlot(int)
    def _close_tab(self, index):
        conn = self._tab_view.widget(index).get_connection()
        conn.close_connection()
        self._tab_view.removeTab(index)

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

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

        self.initUI()

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

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

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

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

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

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

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

    def splitIntoPackets(self):
        pass

    def run_ndis(self):
        pass
コード例 #17
0
ファイル: danaquery.py プロジェクト: wllacer/dana-cube
class SesionTab(QWidget):
    def __init__(self, conn, confName, holder=None, parent=None):
        super(SesionTab, self).__init__(parent)
        self.conn = conn
        self.confName = confName
        self.holder = holder
        self.tabQueries = QTabWidget()
        self.tabQueries.setTabShape(QTabWidget.Triangular)
        meatLayout = QVBoxLayout()
        meatLayout.addWidget(self.tabQueries)
        self.setLayout(meatLayout)

        self.addQuery()

    def addQuery(self):
        #self.tabQueries.addTab(QueryTab(self.conn,self.confName,holder=self.holder),"{}:{}".format(self.confName, self.tabQueries.count() +1))
        self.tabQueries.addTab(
            myQueryTab(self.conn, holder=self.holder),
            "{}:{}".format(self.confName,
                           self.tabQueries.count() + 1))
        self.tabQueries.setCurrentIndex(self.tabQueries.count() - 1)

    def openQuery(self):
        #self.tabQueries.addTab(QueryTab(self.conn,self.confName,holder=self.holder),"{}:{}".format(self.confName, #self.tabQueries.count() +1))
        #self.tabQueries.setCurrentIndex(self.tabQueries.count() -1)
        self.tabQueries.currentWidget().readQuery()

    def saveQuery(self):
        self.tabQueries.currentWidget().writeQuery()

    def saveAsQuery(self):
        self.tabQueries.currentWidget().writeQuery(True)

    def closeQuery(self):
        tabId = self.tabQueries.currentIndex()
        self.tabQueries.removeTab(tabId)

    def execute(self):
        self.tabQueries.currentWidget().execute()

    def reformat(self):
        self.tabQueries.currentWidget().reformat()
コード例 #18
0
class CueSettings(QDialog):

    on_apply = QtCore.pyqtSignal(dict)

    def __init__(self, widgets=[], cue=None, check=False, **kwargs):
        super().__init__(**kwargs)

        conf = {}

        if(cue is not None):
            conf = deepcopy(cue.properties())
            self.setWindowTitle(conf['name'])

        self.setWindowModality(QtCore.Qt.ApplicationModal)
        self.setMaximumSize(635, 530)
        self.setMinimumSize(635, 530)
        self.resize(635, 530)

        self.sections = QTabWidget(self)
        self.sections.setGeometry(QtCore.QRect(5, 10, 625, 470))

        wsize = QtCore.QSize(625, 470 - self.sections.tabBar().height())

        for widget in widgets:
            widget = widget(wsize, cue)
            widget.set_configuration(conf)
            widget.enable_check(check)
            self.sections.addTab(widget, widget.Name)

        self.dialogButtons = QDialogButtonBox(self)
        self.dialogButtons.setGeometry(10, 490, 615, 30)
        self.dialogButtons.setStandardButtons(QDialogButtonBox.Cancel |
                                              QDialogButtonBox.Ok |
                                              QDialogButtonBox.Apply)

        self.dialogButtons.rejected.connect(self.reject)
        self.dialogButtons.accepted.connect(self.accept)
        apply = self.dialogButtons.button(QDialogButtonBox.Apply)
        apply.clicked.connect(self.apply)

    def accept(self):
        self.apply()
        super().accept()

    def apply(self):
        new_conf = {}

        for n in range(self.sections.count()):
            deep_update(new_conf, self.sections.widget(n).get_configuration())

        self.on_apply.emit(new_conf)
コード例 #19
0
class ExcelTabContainer(QWidget):
    emit_dict = pyqtSignal(list)
    graph_xaxis = pyqtSignal(list)

    def __init__(self, title='Text Window', parent=None):
        super(ExcelTabContainer, self).__init__(parent)
        self.setWindowTitle(title)
        self.tabs = QTabWidget(self)
        v_box_layout = QVBoxLayout()
        v_box_layout.addWidget(self.tabs, alignment=Qt.AlignCenter)
        h_box = QHBoxLayout()
        h_box.addLayout(v_box_layout)
        self.setLayout(h_box)
        self.tabs.currentChanged.connect(self.tab_change_event)
        self.hide()

    def tab_change_event(self):
        index = self.tabs.currentIndex()
        handle = self.tabs.widget(index).children()
        try:
            use_handle = handle[1]
            use_handle.selected_data.connect(self.get_page_data)
        except Exception as e:
            print("passed due to {}".format(e))

    def get_page_data(self, stuff):
        try:
            indexices = self.tabs.count()
            for thing in stuff:
                client = thing.get_name()
                for list_position, curve in enumerate(thing.curves):
                    for index in range(indexices):
                        value = self.tabs.widget(
                            index).children()[1].return_cell_value(
                                client, curve)
                        thing.data[curve].append('%s-%s' % (index, value))
            self.emit_dict.emit(stuff)
        except Exception as e:
            print("passed due to {}".format(e))

    def append_spreadsheet(self, spreadsheet, sheet_title):
        tab = QWidget(self)
        vBoxlayout = QVBoxLayout()
        excel_window = ExcelPageWidget(spreadsheet, sheet_title)
        vBoxlayout.addWidget(excel_window, alignment=Qt.AlignCenter)
        h_box = QHBoxLayout()
        h_box.addLayout(vBoxlayout)
        tab.setLayout(h_box)
        self.tabs.addTab(tab, sheet_title)
        self.show()
コード例 #20
0
class BrowserWindow(QMainWindow):
    name = "PyQt5-WebBrowser"
    version = "2.0 Beta 3"
    date = "2018.12.03"

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setWindowTitle(self.name + " " + self.version)
        self.setWindowIcon(QIcon('Assets/main.png'))
        self.resize(1200, 900)
        self.tabs = QTabWidget()
        self.tabs.setTabsClosable(True)
        self.tabs.setMovable(True)
        self.tabs.setTabShape(0)
        self.setCentralWidget(self.tabs)
        self.tabs.tabCloseRequested.connect(self.close_current_tab)
        # self.tabs.currentChanged.connect(lambda i: self.setWindowTitle(self.tabs.tabText(i) + " - " + self.name))
        self.init_tab = BrowserTab(self)
        self.init_tab.browser.load(QUrl("http://www.hao123.com/"))
        self.add_new_tab(self.init_tab)

    def add_blank_tab(self):
        blank_tab = BrowserTab(self)
        self.add_new_tab(blank_tab)

    def add_new_tab(self, tab):
        i = self.tabs.addTab(tab, "")
        self.tabs.setCurrentIndex(i)
        tab.back_button.triggered.connect(tab.browser.back)
        tab.next_button.triggered.connect(tab.browser.forward)
        tab.stop_button.triggered.connect(tab.browser.stop)
        tab.refresh_button.triggered.connect(tab.browser.reload)
        tab.home_button.triggered.connect(tab.navigate_to_home)
        tab.enter_button.triggered.connect(tab.navigate_to_url)
        tab.add_button.triggered.connect(self.add_blank_tab)
        tab.set_button.triggered.connect(tab.create_about_window)
        tab.url_text_bar.returnPressed.connect(tab.navigate_to_url)
        tab.browser.urlChanged.connect(tab.renew_urlbar)
        tab.browser.loadProgress.connect(tab.renew_progress_bar)
        tab.browser.titleChanged.connect(lambda title: (self.tabs.setTabText(
            i, title), self.tabs.setTabToolTip(i, title)))
        tab.browser.iconChanged.connect(
            lambda icon: self.tabs.setTabIcon(i, icon))

    def close_current_tab(self, i):
        if self.tabs.count() > 1:
            self.tabs.removeTab(i)
        else:
            self.close()
コード例 #21
0
class TAOutputTab(QWidget):
    def __init__(self, ctx):
        super(TAOutputTab, self).__init__()
        self.ctx = ctx

        stacked_widget = QWidget()
        self.stacked_layout = QStackedLayout()
        self.stacked_layout.addWidget(self.create_empty_widget())
        self.stacked_layout.addWidget(self.create_data_widget())
        stacked_widget.setLayout(self.stacked_layout)

        layout = QHBoxLayout()
        layout.setContentsMargins(5, 5, 5, 5)
        layout.addWidget(stacked_widget)
        self.setLayout(layout)

    def display_empty(self):
        self.stacked_layout.setCurrentIndex(0)

    def display_data(self):
        self.stacked_layout.setCurrentIndex(1)

    def create_empty_widget(self):
        label = QLabel("You first have to successfully run the allocation.")
        label.setAlignment(Qt.AlignCenter)

        return label

    def create_data_widget(self):
        self.tabs = QTabWidget()
        self.tabs.setTabPosition(QTabWidget.South)
        return self.tabs

    def not_empty(self):
        m_tab = self.tableWidget.rowCount()
        n_tab = self.tableWidget.columnCount()
        return any(
            self.tableWidget.item(i, j).text() for j in range(n_tab)
            for i in range(m_tab))

    def update_tables_from_data(self):
        for i in range(self.tabs.count()):
            self.tabs.removeTab(0)

        for i in range(len(self.ctx.app_data.results)):
            self.tabs.addTab(TAAllocationOutputTab(self.ctx, i),
                             "Allocation {}".format(i + 1))

        return
コード例 #22
0
ファイル: macros.py プロジェクト: swipswaps/guppy-proxy
class MacroWidget(QWidget):
    # Tabs containing both int and active macros

    def __init__(self, client, *args, **kwargs):
        self.client = client
        QWidget.__init__(self, *args, **kwargs)

        self.setLayout(QVBoxLayout())
        self.layout().setContentsMargins(0, 0, 0, 0)
        self.tab_widg = QTabWidget()

        self.active_widg = ActiveMacroWidget(client)
        self.active_ind = self.tab_widg.count()
        self.tab_widg.addTab(self.active_widg, "Active")

        self.int_widg = IntMacroWidget(client)
        self.int_ind = self.tab_widg.count()
        self.tab_widg.addTab(self.int_widg, "Intercepting")

        self.warning_widg = QLabel(
            "<h1>Warning! Macros may cause instability</h1><p>Macros load and run python files into the Guppy process. If you're not careful when you write them you may cause Guppy to crash. If an active macro ends up in an infinite loop you may need to force kill the application when you quit.</p><p><b>PROCEED WITH CAUTION</b></p>"
        )
        self.warning_widg.setWordWrap(True)
        self.tab_widg.addTab(self.warning_widg, "Warning")

        self.layout().addWidget(self.tab_widg)

    def show_active(self):
        self.tab_widg.setCurrentIndex(self.active_ind)

    def show_int(self):
        self.tab_widg.setCurrentIndex(self.int_ind)

    def add_requests(self, reqs):
        # Add requests to active macro inputw
        self.active_widg.add_requests(reqs)
コード例 #23
0
class WritePanel(SubWindow, WindowSystemController):

    '''
    'Write' main panel. Detachable
    '''

    def __init__(self, parent=None, parent_window_system_controller=None):
        '''

        '''
        super(WritePanel, self).__init__(
            parent=parent, parent_window_system_controller=parent_window_system_controller)

        self.setWindowTitle(_("Write"))
        self.setObjectName("write_sub_window")
        self.dock_system = DockSystem(
            self, self,  DockSystem.DockTypes.WritePanelDock)

        # connect core signal to open sheets :
        cfg.core.tree_sheet_manager.sheet_is_opening.connect(
            self.open_write_tab)

        # Project tree view dock :
        self.dock_system.add_dock("write-tree-dock",  Qt.LeftDockWidgetArea)

        # set TabWidget:
        self.tab_widget = QTabWidget(self)
        self.setCentralWidget(self.tab_widget)

        # subscribe
        cfg.core.subscriber.subscribe_update_func_to_domain(
            self._clear_project,  "core.project.close")

    def open_write_tab(self, tree_sheet):

        new_write_tab = WriteTab(self, self)
        new_write_tab.tree_sheet = tree_sheet
        self.tab_widget.addTab(new_write_tab, new_write_tab.tab_title)
        # temp for test:
        new_write_tab.dock_system.add_dock("properties-dock")

    def _clear_project(self):
        # TODO: make that cleaner
        for i in range(0, self.tab_widget.count()):
            widget = self.tab_widget.widget(i)
            widget.close()
            widget.deleteLater()
        self.tab_widget.clear()
コード例 #24
0
ファイル: sub_window.py プロジェクト: harvey-git/skribisto
class WritePanel(SubWindow, WindowSystemController):
    '''
    'Write' main panel. Detachable
    '''
    def __init__(self, parent=None, parent_window_system_controller=None):
        '''

        '''
        super(WritePanel, self).__init__(
            parent=parent,
            parent_window_system_controller=parent_window_system_controller)

        self.setWindowTitle(_("Write"))
        self.setObjectName("write_sub_window")
        self.dock_system = DockSystem(self, self,
                                      DockSystem.DockTypes.WritePanelDock)

        # connect core signal to open sheets :
        cfg.core.tree_sheet_manager.sheet_is_opening.connect(
            self.open_write_tab)

        # Project tree view dock :
        self.dock_system.add_dock("write-tree-dock", Qt.LeftDockWidgetArea)

        # set TabWidget:
        self.tab_widget = QTabWidget(self)
        self.setCentralWidget(self.tab_widget)

        # subscribe
        cfg.core.subscriber.subscribe_update_func_to_domain(
            self._clear_project, "core.project.close")

    def open_write_tab(self, tree_sheet):

        new_write_tab = WriteTab(self, self)
        new_write_tab.tree_sheet = tree_sheet
        self.tab_widget.addTab(new_write_tab, new_write_tab.tab_title)
        # temp for test:
        new_write_tab.dock_system.add_dock("properties-dock")

    def _clear_project(self):
        # TODO: make that cleaner
        for i in range(0, self.tab_widget.count()):
            widget = self.tab_widget.widget(i)
            widget.close()
            widget.deleteLater()
        self.tab_widget.clear()
コード例 #25
0
class VectorFrame(GenericFrame):
    def __init__(self, parent=None):
        super().__init__(QHBoxLayout(), 'Vector Frame', parent=parent)
        self.tabs = QTabWidget()
        self.vectors = None

        self.init_frame()

    def init_frame(self):
        self.setFrameShape(QFrame.StyledPanel)
        self.populate_tabs()

        self.layout.addWidget(self.tabs)

    def populate_tabs(self):
        self.tabs.clear()
        self.vectors = get_vector_list()

        if self.vectors:
            for vector in self.vectors:
                print(vector)
                self.initialize_tab(vector)

        # TODO: Program to open vector from vector db
        # self.tabs.addTab(QWidget(), '+')

        self.tabs.setTabsClosable(True)
        self.tabs.tabCloseRequested.connect(lambda i: self.tabs.removeTab(i))

    def initialize_tab(self, vector):
        frame = GenericFrame(QHBoxLayout(), 'vector tab', self)

        splitter = QSplitter(Qt.Horizontal)

        # TODO: Make generic table class, populate with vector nodes & significant log entries
        splitter.addWidget(NodeTableFrame())
        splitter.addWidget(GraphFrame(vector, frame))
        splitter.setSizes([600, 600])

        frame.layout.addWidget(splitter)
        self.tabs.addTab(frame, vector.get("Name"))

    def delete_tab(self, vector):
        for i in range(0, self.tabs.count()):
            if vector.get("Name") == self.tabs.tabText(i):
                self.tabs.removeTab(i)
コード例 #26
0
class AccountsTabsWidget(QWidget):
  def __init__(self, accounts_thread):
    super().__init__()
    self.accounts_thread = accounts_thread
    layout = QGridLayout()
    layout.setContentsMargins(0, 0, 0, 0)
    self.tab_widget = QTabWidget()
    layout.addWidget(self.tab_widget)
    self.setLayout(layout)
    self.show()
    self.restart()

  def restart(self):
    while self.tab_widget.count() > 0:
      self.tab_widget.removeTab(0)

    self.tab_widget.addTab(Overview(self.accounts_thread), Translation.get_text("overview"))
    self.tab_widget.addTab(AddAccount(self.accounts_thread), Translation.get_text("add_accounts"))
コード例 #27
0
class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.tabs = QTabWidget()
        self.init_ui()

    def update_file(self):
        self.tabs.clear()
        for f in QApplication.instance().diagram_list():
            self.add(f)

    def init_ui(self):
        file_menu = QMenu("&File", self)

        update_action = file_menu.addAction("update")
        update_action.triggered.connect(self.update_file)

        quit_action = file_menu.addAction("E&xit")
        quit_action.triggered.connect(QApplication.instance().quit)
        self.menuBar().addMenu(file_menu)
        self.setCentralWidget(self.tabs)

    def add(self, file):
        tab_name = os.path.basename(file)

        view = None
        for i in range(self.tabs.count()):
            if self.tabs.tabText(i) == tab_name:
                view = self.tabs.widget(i)
                break

        if view is None:
            m = magic.from_file(file)
            if m[:3] == 'PNG':
                view = PngView()
            elif m[:3] == 'SVG':
                view = SvgView()

            self.tabs.addTab(view, tab_name)

        view.open_file(file)
コード例 #28
0
class DiffWindows(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Diffs")
        self.app = QCoreApplication.instance()
        self.git = self.app.findChild(Git)

        self.init_tab()
        self.grid = QGridLayout()
        self.grid.setSpacing(5)
        self.grid.setContentsMargins(5, 5, 5, 5)
        self.grid.addWidget(self.tabw, 0, 0, 1, -1)

        self.setLayout(self.grid)
        self.grid.addWidget(QPushButton("Refresh"), 1, 0)
        self.grid.itemAt(1).widget().clicked.connect(
            self.git.refresh)  # the function refresh_tab after refresh git

    def init_tab(self):
        self.tabw = QTabWidget()
        tab_lst = copy(VULNS_INITIAL), DBHandler.vulns(), DBHandler.vulns_git(
        ), add_vuln_initial
        obj = ObjectsGit("vulns", tab_lst, self)
        self.tabw.addTab(obj, "Vulns")

        tab_lst = copy(AUDITORS_INITIAL), DBHandler.auditors(
        ), DBHandler.auditors_git(), add_auditor_initial
        obj = ObjectsGit("auditors", tab_lst, self)
        self.tabw.addTab(obj, "Auditors")

        tab_lst = copy(AUDITORS_INITIAL), DBHandler.clients(
        ), DBHandler.clients_git(), add_auditor_initial
        obj = ObjectsGit("clients", tab_lst, self)
        self.tabw.addTab(obj, "Clients")

    def refresh_tab_widget(self):
        """Refresh all the ObjectGit in the window"""
        for i in range(self.tabw.count()):
            self.tabw.widget(i).refresh_tab_widget()
コード例 #29
0
class PluginPreferences(QWidget):
    """
    Plugins section widget in NINJA-IDE Preferences
    """
    def __init__(self):
        super(PluginPreferences, self).__init__()
        self.plugin_manager = plugin_manager.PluginManager()
        vbox = QVBoxLayout(self)
        self._tabs = QTabWidget()
        vbox.addWidget(self._tabs)
        #load widgets
        self._load_widgets()

    def _load_widgets(self):
        logger.info("Loading plugins preferences widgets")
        #Collect the preferences widget for each active plugin
        for plugin in self.plugin_manager.get_active_plugins():
            plugin_name = plugin.metadata.get('name')
            try:
                preferences_widget = plugin.get_preferences_widget()
                if preferences_widget:
                    self._tabs.addTab(preferences_widget, plugin_name)
            except Exception as reason:
                logger.error("Unable to add the preferences widget (%s): %s",
                             plugin_name, reason)
                continue

    def save(self):
        logger.info("Saving plugins preferences")
        for i in range(self._tabs.count()):
            try:
                self._tabs.widget(i).save()
            except Exception as reason:
                logger.error("Unable to save preferences (%s): %s",
                             self._tabs.tabText(i), reason)
                continue
コード例 #30
0
class ProtocolViewerDialog(QDialog):

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        self.setWindowTitle('Protocol Viewer')
        self.setMinimumSize(600, 800)

        self.setLayout(QVBoxLayout())

        self.tab_widget = QTabWidget(parent=self)
        self.tab_widget.tabBar().setDrawBase(False)

        for tab in protocols.Tabs:
            self.tab_widget.addTab(tab(parent=self.tab_widget), tab.tabname)
        self.layout().addWidget(self.tab_widget)

    def done(self, *args, **kwargs):
        super().done(*args, **kwargs)
        for idx in range(self.tab_widget.count()):
            self.tab_widget.widget(idx).on_close()

    def view(self):
        return self.tab_widget
コード例 #31
0
class PluginPreferences(QWidget):
    """
    Plugins section widget in NINJA-IDE Preferences
    """
    def __init__(self):
        super(PluginPreferences, self).__init__()
        self.plugin_manager = plugin_manager.PluginManager()
        vbox = QVBoxLayout(self)
        self._tabs = QTabWidget()
        vbox.addWidget(self._tabs)
        #load widgets
        self._load_widgets()

    def _load_widgets(self):
        logger.info("Loading plugins preferences widgets")
        #Collect the preferences widget for each active plugin
        for plugin in self.plugin_manager.get_active_plugins():
            plugin_name = plugin.metadata.get('name')
            try:
                preferences_widget = plugin.get_preferences_widget()
                if preferences_widget:
                    self._tabs.addTab(preferences_widget, plugin_name)
            except Exception as reason:
                logger.error("Unable to add the preferences widget (%s): %s",
                    plugin_name, reason)
                continue

    def save(self):
        logger.info("Saving plugins preferences")
        for i in range(self._tabs.count()):
            try:
                self._tabs.widget(i).save()
            except Exception as reason:
                logger.error("Unable to save preferences (%s): %s",
                    self._tabs.tabText(i), reason)
                continue
コード例 #32
0
ファイル: window.py プロジェクト: daffodil/retext
class ReTextWindow(QMainWindow):
	def __init__(self, parent=None):
		QMainWindow.__init__(self, parent)
		self.resize(950, 700)
		screenRect = QDesktopWidget().screenGeometry()
		if globalSettings.windowGeometry:
			self.restoreGeometry(globalSettings.windowGeometry)
		else:
			self.move((screenRect.width()-self.width())/2, (screenRect.height()-self.height())/2)
		if not screenRect.contains(self.geometry()):
			self.showMaximized()
		if globalSettings.iconTheme:
			QIcon.setThemeName(globalSettings.iconTheme)
		if QIcon.themeName() in ('hicolor', ''):
			if not QFile.exists(icon_path + 'document-new.png'):
				QIcon.setThemeName(get_icon_theme())
		if QFile.exists(icon_path+'retext.png'):
			self.setWindowIcon(QIcon(icon_path+'retext.png'))
		elif QFile.exists('/usr/share/pixmaps/retext.png'):
			self.setWindowIcon(QIcon('/usr/share/pixmaps/retext.png'))
		else:
			self.setWindowIcon(QIcon.fromTheme('retext',
				QIcon.fromTheme('accessories-text-editor')))
		self.tabWidget = QTabWidget(self)
		self.initTabWidget()
		self.setCentralWidget(self.tabWidget)
		self.tabWidget.currentChanged.connect(self.changeIndex)
		self.tabWidget.tabCloseRequested.connect(self.closeTab)
		toolBar = QToolBar(self.tr('File toolbar'), self)
		self.addToolBar(Qt.TopToolBarArea, toolBar)
		self.editBar = QToolBar(self.tr('Edit toolbar'), self)
		self.addToolBar(Qt.TopToolBarArea, self.editBar)
		self.searchBar = QToolBar(self.tr('Search toolbar'), self)
		self.addToolBar(Qt.BottomToolBarArea, self.searchBar)
		toolBar.setVisible(not globalSettings.hideToolBar)
		self.editBar.setVisible(not globalSettings.hideToolBar)
		self.actionNew = self.act(self.tr('New'), 'document-new',
			self.createNew, shct=QKeySequence.New)
		self.actionNew.setPriority(QAction.LowPriority)
		self.actionOpen = self.act(self.tr('Open'), 'document-open',
			self.openFile, shct=QKeySequence.Open)
		self.actionOpen.setPriority(QAction.LowPriority)
		self.actionSetEncoding = self.act(self.tr('Set encoding'),
			trig=self.showEncodingDialog)
		self.actionSetEncoding.setEnabled(False)
		self.actionReload = self.act(self.tr('Reload'), 'view-refresh',
			lambda: self.currentTab.readTextFromFile())
		self.actionReload.setEnabled(False)
		self.actionSave = self.act(self.tr('Save'), 'document-save',
			self.saveFile, shct=QKeySequence.Save)
		self.actionSave.setEnabled(False)
		self.actionSave.setPriority(QAction.LowPriority)
		self.actionSaveAs = self.act(self.tr('Save as'), 'document-save-as',
			self.saveFileAs, shct=QKeySequence.SaveAs)
		self.actionNextTab = self.act(self.tr('Next tab'), 'go-next',
			lambda: self.switchTab(1), shct=Qt.CTRL+Qt.Key_PageDown)
		self.actionPrevTab = self.act(self.tr('Previous tab'), 'go-previous',
			lambda: self.switchTab(-1), shct=Qt.CTRL+Qt.Key_PageUp)
		self.actionPrint = self.act(self.tr('Print'), 'document-print',
			self.printFile, shct=QKeySequence.Print)
		self.actionPrint.setPriority(QAction.LowPriority)
		self.actionPrintPreview = self.act(self.tr('Print preview'), 'document-print-preview',
			self.printPreview)
		self.actionViewHtml = self.act(self.tr('View HTML code'), 'text-html', self.viewHtml)
		self.actionChangeEditorFont = self.act(self.tr('Change editor font'),
			trig=self.changeEditorFont)
		self.actionChangePreviewFont = self.act(self.tr('Change preview font'),
			trig=self.changePreviewFont)
		self.actionSearch = self.act(self.tr('Find text'), 'edit-find', shct=QKeySequence.Find)
		self.actionSearch.setCheckable(True)
		self.actionSearch.triggered[bool].connect(self.searchBar.setVisible)
		self.searchBar.visibilityChanged.connect(self.searchBarVisibilityChanged)
		self.actionPreview = self.act(self.tr('Preview'), shct=Qt.CTRL+Qt.Key_E,
			trigbool=self.preview)
		if QIcon.hasThemeIcon('document-preview'):
			self.actionPreview.setIcon(QIcon.fromTheme('document-preview'))
		elif QIcon.hasThemeIcon('preview-file'):
			self.actionPreview.setIcon(QIcon.fromTheme('preview-file'))
		elif QIcon.hasThemeIcon('x-office-document'):
			self.actionPreview.setIcon(QIcon.fromTheme('x-office-document'))
		else:
			self.actionPreview.setIcon(QIcon(icon_path+'document-preview.png'))
		self.actionLivePreview = self.act(self.tr('Live preview'), shct=Qt.CTRL+Qt.Key_L,
		trigbool=self.enableLivePreview)
		menuPreview = QMenu()
		menuPreview.addAction(self.actionLivePreview)
		self.actionPreview.setMenu(menuPreview)
		self.actionTableMode = self.act(self.tr('Table mode'), shct=Qt.CTRL+Qt.Key_T,
			trigbool=lambda x: self.currentTab.editBox.enableTableMode(x))
		if ReTextFakeVimHandler:
			self.actionFakeVimMode = self.act(self.tr('FakeVim mode'),
				shct=Qt.CTRL+Qt.ALT+Qt.Key_V, trigbool=self.enableFakeVimMode)
			if globalSettings.useFakeVim:
				self.actionFakeVimMode.setChecked(True)
				self.enableFakeVimMode(True)
		self.actionFullScreen = self.act(self.tr('Fullscreen mode'), 'view-fullscreen',
			shct=Qt.Key_F11, trigbool=self.enableFullScreen)
		self.actionFullScreen.setPriority(QAction.LowPriority)
		self.actionConfig = self.act(self.tr('Preferences'), icon='preferences-system',
			trig=self.openConfigDialog)
		self.actionConfig.setMenuRole(QAction.PreferencesRole)
		self.actionSaveHtml = self.act('HTML', 'text-html', self.saveFileHtml)
		self.actionPdf = self.act('PDF', 'application-pdf', self.savePdf)
		self.actionOdf = self.act('ODT', 'x-office-document', self.saveOdf)
		self.getExportExtensionsList()
		self.actionQuit = self.act(self.tr('Quit'), 'application-exit', shct=QKeySequence.Quit)
		self.actionQuit.setMenuRole(QAction.QuitRole)
		self.actionQuit.triggered.connect(self.close)
		self.actionUndo = self.act(self.tr('Undo'), 'edit-undo',
			lambda: self.currentTab.editBox.undo(), shct=QKeySequence.Undo)
		self.actionRedo = self.act(self.tr('Redo'), 'edit-redo',
			lambda: self.currentTab.editBox.redo(), shct=QKeySequence.Redo)
		self.actionCopy = self.act(self.tr('Copy'), 'edit-copy',
			lambda: self.currentTab.editBox.copy(), shct=QKeySequence.Copy)
		self.actionCut = self.act(self.tr('Cut'), 'edit-cut',
			lambda: self.currentTab.editBox.cut(), shct=QKeySequence.Cut)
		self.actionPaste = self.act(self.tr('Paste'), 'edit-paste',
			lambda: self.currentTab.editBox.paste(), shct=QKeySequence.Paste)
		self.actionUndo.setEnabled(False)
		self.actionRedo.setEnabled(False)
		self.actionCopy.setEnabled(False)
		self.actionCut.setEnabled(False)
		qApp = QApplication.instance()
		qApp.clipboard().dataChanged.connect(self.clipboardDataChanged)
		self.clipboardDataChanged()
		if enchant_available:
			self.actionEnableSC = self.act(self.tr('Enable'), trigbool=self.enableSpellCheck)
			self.actionSetLocale = self.act(self.tr('Set locale'), trig=self.changeLocale)
		self.actionWebKit = self.act(self.tr('Use WebKit renderer'), trigbool=self.enableWebKit)
		self.actionWebKit.setChecked(globalSettings.useWebKit)
		self.actionShow = self.act(self.tr('Show directory'), 'system-file-manager', self.showInDir)
		self.actionFind = self.act(self.tr('Next'), 'go-next', self.find,
			shct=QKeySequence.FindNext)
		self.actionFindPrev = self.act(self.tr('Previous'), 'go-previous',
			lambda: self.find(back=True), shct=QKeySequence.FindPrevious)
		self.actionCloseSearch = self.act(self.tr('Close'), 'window-close',
			lambda: self.searchBar.setVisible(False))
		self.actionCloseSearch.setPriority(QAction.LowPriority)
		self.actionHelp = self.act(self.tr('Get help online'), 'help-contents', self.openHelp)
		self.aboutWindowTitle = self.tr('About ReText')
		self.actionAbout = self.act(self.aboutWindowTitle, 'help-about', self.aboutDialog)
		self.actionAbout.setMenuRole(QAction.AboutRole)
		self.actionAboutQt = self.act(self.tr('About Qt'))
		self.actionAboutQt.setMenuRole(QAction.AboutQtRole)
		self.actionAboutQt.triggered.connect(qApp.aboutQt)
		availableMarkups = markups.get_available_markups()
		if not availableMarkups:
			print('Warning: no markups are available!')
		self.defaultMarkup = availableMarkups[0] if availableMarkups else None
		if globalSettings.defaultMarkup:
			mc = markups.find_markup_class_by_name(globalSettings.defaultMarkup)
			if mc and mc.available():
				self.defaultMarkup = mc
		if len(availableMarkups) > 1:
			self.chooseGroup = QActionGroup(self)
			markupActions = []
			for markup in availableMarkups:
				markupAction = self.act(markup.name, trigbool=self.markupFunction(markup))
				if markup == self.defaultMarkup:
					markupAction.setChecked(True)
				self.chooseGroup.addAction(markupAction)
				markupActions.append(markupAction)
		self.actionBold = self.act(self.tr('Bold'), shct=QKeySequence.Bold,
			trig=lambda: self.insertFormatting('bold'))
		self.actionItalic = self.act(self.tr('Italic'), shct=QKeySequence.Italic,
			trig=lambda: self.insertFormatting('italic'))
		self.actionUnderline = self.act(self.tr('Underline'), shct=QKeySequence.Underline,
			trig=lambda: self.insertFormatting('underline'))
		self.usefulTags = ('header', 'italic', 'bold', 'underline', 'numbering',
			'bullets', 'image', 'link', 'inline code', 'code block', 'blockquote')
		self.usefulChars = ('deg', 'divide', 'dollar', 'hellip', 'laquo', 'larr',
			'lsquo', 'mdash', 'middot', 'minus', 'nbsp', 'ndash', 'raquo',
			'rarr', 'rsquo', 'times')
		self.formattingBox = QComboBox(self.editBar)
		self.formattingBox.addItem(self.tr('Formatting'))
		self.formattingBox.addItems(self.usefulTags)
		self.formattingBox.activated[str].connect(self.insertFormatting)
		self.symbolBox = QComboBox(self.editBar)
		self.symbolBox.addItem(self.tr('Symbols'))
		self.symbolBox.addItems(self.usefulChars)
		self.symbolBox.activated.connect(self.insertSymbol)
		self.updateStyleSheet()
		menubar = self.menuBar()
		menuFile = menubar.addMenu(self.tr('File'))
		menuEdit = menubar.addMenu(self.tr('Edit'))
		menuHelp = menubar.addMenu(self.tr('Help'))
		menuFile.addAction(self.actionNew)
		menuFile.addAction(self.actionOpen)
		self.menuRecentFiles = menuFile.addMenu(self.tr('Open recent'))
		self.menuRecentFiles.aboutToShow.connect(self.updateRecentFiles)
		menuFile.addAction(self.actionShow)
		menuFile.addAction(self.actionSetEncoding)
		menuFile.addAction(self.actionReload)
		menuFile.addSeparator()
		menuFile.addAction(self.actionSave)
		menuFile.addAction(self.actionSaveAs)
		menuFile.addSeparator()
		menuFile.addAction(self.actionNextTab)
		menuFile.addAction(self.actionPrevTab)
		menuFile.addSeparator()
		menuExport = menuFile.addMenu(self.tr('Export'))
		menuExport.addAction(self.actionSaveHtml)
		menuExport.addAction(self.actionOdf)
		menuExport.addAction(self.actionPdf)
		if self.extensionActions:
			menuExport.addSeparator()
			for action, mimetype in self.extensionActions:
				menuExport.addAction(action)
			menuExport.aboutToShow.connect(self.updateExtensionsVisibility)
		menuFile.addAction(self.actionPrint)
		menuFile.addAction(self.actionPrintPreview)
		menuFile.addSeparator()
		menuFile.addAction(self.actionQuit)
		menuEdit.addAction(self.actionUndo)
		menuEdit.addAction(self.actionRedo)
		menuEdit.addSeparator()
		menuEdit.addAction(self.actionCut)
		menuEdit.addAction(self.actionCopy)
		menuEdit.addAction(self.actionPaste)
		menuEdit.addSeparator()
		if enchant_available:
			menuSC = menuEdit.addMenu(self.tr('Spell check'))
			menuSC.addAction(self.actionEnableSC)
			menuSC.addAction(self.actionSetLocale)
		menuEdit.addAction(self.actionSearch)
		menuEdit.addAction(self.actionChangeEditorFont)
		menuEdit.addAction(self.actionChangePreviewFont)
		menuEdit.addSeparator()
		if len(availableMarkups) > 1:
			self.menuMode = menuEdit.addMenu(self.tr('Default markup'))
			for markupAction in markupActions:
				self.menuMode.addAction(markupAction)
		menuFormat = menuEdit.addMenu(self.tr('Formatting'))
		menuFormat.addAction(self.actionBold)
		menuFormat.addAction(self.actionItalic)
		menuFormat.addAction(self.actionUnderline)
		menuEdit.addAction(self.actionWebKit)
		menuEdit.addSeparator()
		menuEdit.addAction(self.actionViewHtml)
		menuEdit.addAction(self.actionPreview)
		menuEdit.addAction(self.actionTableMode)
		if ReTextFakeVimHandler:
			menuEdit.addAction(self.actionFakeVimMode)
		menuEdit.addSeparator()
		menuEdit.addAction(self.actionFullScreen)
		menuEdit.addAction(self.actionConfig)
		menuHelp.addAction(self.actionHelp)
		menuHelp.addSeparator()
		menuHelp.addAction(self.actionAbout)
		menuHelp.addAction(self.actionAboutQt)
		toolBar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
		toolBar.addAction(self.actionNew)
		toolBar.addSeparator()
		toolBar.addAction(self.actionOpen)
		toolBar.addAction(self.actionSave)
		toolBar.addAction(self.actionPrint)
		toolBar.addSeparator()
		toolBar.addAction(self.actionPreview)
		toolBar.addAction(self.actionFullScreen)
		self.editBar.addAction(self.actionUndo)
		self.editBar.addAction(self.actionRedo)
		self.editBar.addSeparator()
		self.editBar.addAction(self.actionCut)
		self.editBar.addAction(self.actionCopy)
		self.editBar.addAction(self.actionPaste)
		self.editBar.addSeparator()
		self.editBar.addWidget(self.formattingBox)
		self.editBar.addWidget(self.symbolBox)
		self.searchEdit = QLineEdit(self.searchBar)
		self.searchEdit.setPlaceholderText(self.tr('Search'))
		self.searchEdit.returnPressed.connect(self.find)
		self.csBox = QCheckBox(self.tr('Case sensitively'), self.searchBar)
		self.searchBar.addWidget(self.searchEdit)
		self.searchBar.addSeparator()
		self.searchBar.addWidget(self.csBox)
		self.searchBar.addAction(self.actionFindPrev)
		self.searchBar.addAction(self.actionFind)
		self.searchBar.addAction(self.actionCloseSearch)
		self.searchBar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
		self.searchBar.setVisible(False)
		self.autoSaveEnabled = globalSettings.autoSave
		if self.autoSaveEnabled:
			timer = QTimer(self)
			timer.start(60000)
			timer.timeout.connect(self.saveAll)
		self.ind = None
		if enchant_available:
			self.sl = globalSettings.spellCheckLocale
			if self.sl:
				try:
					enchant.Dict(self.sl)
				except Exception as e:
					print(e, file=sys.stderr)
					self.sl = None
			if globalSettings.spellCheck:
				self.actionEnableSC.setChecked(True)
		self.fileSystemWatcher = QFileSystemWatcher()
		self.fileSystemWatcher.fileChanged.connect(self.fileChanged)

	def iterateTabs(self):
		for i in range(self.tabWidget.count()):
			yield self.tabWidget.widget(i).tab

	def updateStyleSheet(self):
		if globalSettings.styleSheet:
			sheetfile = QFile(globalSettings.styleSheet)
			sheetfile.open(QIODevice.ReadOnly)
			self.ss = QTextStream(sheetfile).readAll()
			sheetfile.close()
		else:
			palette = QApplication.palette()
			self.ss = 'html { color: %s; }\n' % palette.color(QPalette.WindowText).name()
			self.ss += 'td, th { border: 1px solid #c3c3c3; padding: 0 3px 0 3px; }\n'
			self.ss += 'table { border-collapse: collapse; }\n'

	def initTabWidget(self):
		def dragEnterEvent(e):
			e.acceptProposedAction()
		def dropEvent(e):
			fn = bytes(e.mimeData().data('text/plain')).decode().rstrip()
			if fn.startswith('file:'):
				fn = QUrl(fn).toLocalFile()
			self.openFileWrapper(fn)
		self.tabWidget.setTabsClosable(True)
		self.tabWidget.setAcceptDrops(True)
		self.tabWidget.setMovable(True)
		self.tabWidget.dragEnterEvent = dragEnterEvent
		self.tabWidget.dropEvent = dropEvent

	def act(self, name, icon=None, trig=None, trigbool=None, shct=None):
		if not isinstance(shct, QKeySequence):
			shct = QKeySequence(shct)
		if icon:
			action = QAction(self.actIcon(icon), name, self)
		else:
			action = QAction(name, self)
		if trig:
			action.triggered.connect(trig)
		elif trigbool:
			action.setCheckable(True)
			action.triggered[bool].connect(trigbool)
		if shct:
			action.setShortcut(shct)
		return action

	def actIcon(self, name):
		return QIcon.fromTheme(name, QIcon(icon_path+name+'.png'))

	def printError(self):
		import traceback
		print('Exception occured while parsing document:', file=sys.stderr)
		traceback.print_exc()

	def createTab(self, fileName):
		self.currentTab = ReTextTab(self, fileName,
			previewState=int(globalSettings.livePreviewByDefault))
		self.tabWidget.addTab(self.currentTab.getSplitter(), self.tr("New document"))

	def closeTab(self, ind):
		if self.maybeSave(ind):
			if self.tabWidget.count() == 1:
				self.createTab("")
			currentWidget = self.tabWidget.widget(ind)
			if currentWidget.tab.fileName:
				self.fileSystemWatcher.removePath(currentWidget.tab.fileName)
			del currentWidget.tab
			self.tabWidget.removeTab(ind)

	def docTypeChanged(self):
		markupClass = self.currentTab.getMarkupClass()
		if type(self.currentTab.markup) != markupClass:
			self.currentTab.setMarkupClass(markupClass)
			self.currentTab.updatePreviewBox()
		dtMarkdown = (markupClass == markups.MarkdownMarkup)
		dtMkdOrReST = dtMarkdown or (markupClass == markups.ReStructuredTextMarkup)
		self.formattingBox.setEnabled(dtMarkdown)
		self.symbolBox.setEnabled(dtMarkdown)
		self.actionUnderline.setEnabled(dtMarkdown)
		self.actionBold.setEnabled(dtMkdOrReST)
		self.actionItalic.setEnabled(dtMkdOrReST)
		canReload = bool(self.currentTab.fileName) and not self.autoSaveActive()
		self.actionSetEncoding.setEnabled(canReload)
		self.actionReload.setEnabled(canReload)

	def changeIndex(self, ind):
		self.currentTab = self.tabWidget.currentWidget().tab
		editBox = self.currentTab.editBox
		previewState = self.currentTab.previewState
		self.actionUndo.setEnabled(editBox.document().isUndoAvailable())
		self.actionRedo.setEnabled(editBox.document().isRedoAvailable())
		self.actionCopy.setEnabled(editBox.textCursor().hasSelection())
		self.actionCut.setEnabled(editBox.textCursor().hasSelection())
		self.actionPreview.setChecked(previewState >= PreviewLive)
		self.actionLivePreview.setChecked(previewState == PreviewLive)
		self.actionTableMode.setChecked(editBox.tableModeEnabled)
		self.editBar.setEnabled(previewState < PreviewNormal)
		self.ind = ind
		if self.currentTab.fileName:
			self.setCurrentFile()
		else:
			self.setWindowTitle(self.tr('New document') + '[*]')
			self.docTypeChanged()
		self.modificationChanged(editBox.document().isModified())
		editBox.setFocus(Qt.OtherFocusReason)

	def changeEditorFont(self):
		font, ok = QFontDialog.getFont(globalSettings.editorFont, self)
		if ok:
			globalSettings.editorFont = font
			for tab in self.iterateTabs():
				tab.editBox.updateFont()

	def changePreviewFont(self):
		font, ok = QFontDialog.getFont(globalSettings.font, self)
		if ok:
			globalSettings.font = font
			for tab in self.iterateTabs():
				tab.updatePreviewBox()

	def preview(self, viewmode):
		self.currentTab.previewState = viewmode * 2
		self.actionLivePreview.setChecked(False)
		self.editBar.setDisabled(viewmode)
		self.currentTab.updateBoxesVisibility()
		if viewmode:
			self.currentTab.updatePreviewBox()

	def enableLivePreview(self, livemode):
		self.currentTab.previewState = int(livemode)
		self.actionPreview.setChecked(livemode)
		self.editBar.setEnabled(True)
		self.currentTab.updateBoxesVisibility()
		if livemode:
			self.currentTab.updatePreviewBox()

	def enableWebKit(self, enable):
		globalSettings.useWebKit = enable
		for i in range(self.tabWidget.count()):
			splitter = self.tabWidget.widget(i)
			tab = splitter.tab
			tab.previewBox.disconnectExternalSignals()
			tab.previewBox.setParent(None)
			tab.previewBox.deleteLater()
			tab.previewBox = tab.createPreviewBox(tab.editBox)
			tab.previewBox.setMinimumWidth(125)
			splitter.addWidget(tab.previewBox)
			splitter.setSizes((50, 50))
			tab.updatePreviewBox()
			tab.updateBoxesVisibility()

	def enableCopy(self, copymode):
		self.actionCopy.setEnabled(copymode)
		self.actionCut.setEnabled(copymode)

	def enableFullScreen(self, yes):
		if yes:
			self.showFullScreen()
		else:
			self.showNormal()

	def openConfigDialog(self):
		dlg = ConfigDialog(self)
		dlg.setWindowTitle(self.tr('Preferences'))
		dlg.show()

	def enableFakeVimMode(self, yes):
		globalSettings.useFakeVim = yes
		if yes:
			FakeVimMode.init(self)
			for tab in self.iterateTabs():
				tab.installFakeVimHandler()
		else:
			FakeVimMode.exit(self)

	def enableSpellCheck(self, yes):
		if yes:
			self.setAllDictionaries(enchant.Dict(self.sl or None))
		else:
			self.setAllDictionaries(None)
		globalSettings.spellCheck = yes

	def setAllDictionaries(self, dictionary):
		for tab in self.iterateTabs():
			hl = tab.highlighter
			hl.dictionary = dictionary
			hl.rehighlight()

	def changeLocale(self):
		if self.sl:
			localedlg = LocaleDialog(self, defaultText=self.sl)
		else:
			localedlg = LocaleDialog(self)
		if localedlg.exec() != QDialog.Accepted:
			return
		sl = localedlg.localeEdit.text()
		setdefault = localedlg.checkBox.isChecked()
		if sl:
			try:
				sl = str(sl)
				enchant.Dict(sl)
			except Exception as e:
				QMessageBox.warning(self, '', str(e))
			else:
				self.sl = sl
				self.enableSpellCheck(self.actionEnableSC.isChecked())
		else:
			self.sl = None
			self.enableSpellCheck(self.actionEnableSC.isChecked())
		if setdefault:
			globalSettings.spellCheckLocale = sl

	def searchBarVisibilityChanged(self, visible):
		self.actionSearch.setChecked(visible)
		if visible:
			self.searchEdit.setFocus(Qt.ShortcutFocusReason)

	def find(self, back=False):
		flags = QTextDocument.FindFlags()
		if back:
			flags |= QTextDocument.FindBackward
		if self.csBox.isChecked():
			flags |= QTextDocument.FindCaseSensitively
		text = self.searchEdit.text()
		editBox = self.currentTab.editBox
		cursor = editBox.textCursor()
		newCursor = editBox.document().find(text, cursor, flags)
		if not newCursor.isNull():
			editBox.setTextCursor(newCursor)
			return self.setSearchEditColor(True)
		cursor.movePosition(QTextCursor.End if back else QTextCursor.Start)
		newCursor = editBox.document().find(text, cursor, flags)
		if not newCursor.isNull():
			editBox.setTextCursor(newCursor)
			return self.setSearchEditColor(True)
		self.setSearchEditColor(False)

	def setSearchEditColor(self, found):
		palette = self.searchEdit.palette()
		palette.setColor(QPalette.Active, QPalette.Base,
		                 Qt.white if found else QColor(255, 102, 102))
		self.searchEdit.setPalette(palette)

	def showInDir(self):
		if self.currentTab.fileName:
			path = QFileInfo(self.currentTab.fileName).path()
			QDesktopServices.openUrl(QUrl.fromLocalFile(path))
		else:
			QMessageBox.warning(self, '', self.tr("Please, save the file somewhere."))

	def setCurrentFile(self):
		self.setWindowTitle("")
		self.tabWidget.setTabText(self.ind, self.currentTab.getDocumentTitle(baseName=True))
		self.tabWidget.setTabToolTip(self.ind, self.currentTab.fileName or '')
		self.setWindowFilePath(self.currentTab.fileName)
		files = readListFromSettings("recentFileList")
		while self.currentTab.fileName in files:
			files.remove(self.currentTab.fileName)
		files.insert(0, self.currentTab.fileName)
		if len(files) > 10:
			del files[10:]
		writeListToSettings("recentFileList", files)
		QDir.setCurrent(QFileInfo(self.currentTab.fileName).dir().path())
		self.docTypeChanged()

	def createNew(self, text=None):
		self.createTab("")
		self.ind = self.tabWidget.count()-1
		self.tabWidget.setCurrentIndex(self.ind)
		if text:
			self.currentTab.editBox.textCursor().insertText(text)

	def switchTab(self, shift=1):
		self.tabWidget.setCurrentIndex((self.ind + shift) % self.tabWidget.count())

	def updateRecentFiles(self):
		self.menuRecentFiles.clear()
		self.recentFilesActions = []
		filesOld = readListFromSettings("recentFileList")
		files = []
		for f in filesOld:
			if QFile.exists(f):
				files.append(f)
				self.recentFilesActions.append(self.act(f, trig=self.openFunction(f)))
		writeListToSettings("recentFileList", files)
		for action in self.recentFilesActions:
			self.menuRecentFiles.addAction(action)

	def markupFunction(self, markup):
		return lambda: self.setDefaultMarkup(markup)

	def openFunction(self, fileName):
		return lambda: self.openFileWrapper(fileName)

	def extensionFunction(self, data):
		return lambda: \
		self.runExtensionCommand(data['Exec'], data['FileFilter'], data['DefaultExtension'])

	def getExportExtensionsList(self):
		extensions = []
		for extsprefix in datadirs:
			extsdir = QDir(extsprefix+'/export-extensions/')
			if extsdir.exists():
				for fileInfo in extsdir.entryInfoList(['*.desktop', '*.ini'],
				QDir.Files | QDir.Readable):
					extensions.append(self.readExtension(fileInfo.filePath()))
		locale = QLocale.system().name()
		self.extensionActions = []
		for extension in extensions:
			try:
				if ('Name[%s]' % locale) in extension:
					name = extension['Name[%s]' % locale]
				elif ('Name[%s]' % locale.split('_')[0]) in extension:
					name = extension['Name[%s]' % locale.split('_')[0]]
				else:
					name = extension['Name']
				data = {}
				for prop in ('FileFilter', 'DefaultExtension', 'Exec'):
					if 'X-ReText-'+prop in extension:
						data[prop] = extension['X-ReText-'+prop]
					elif prop in extension:
						data[prop] = extension[prop]
					else:
						data[prop] = ''
				action = self.act(name, trig=self.extensionFunction(data))
				if 'Icon' in extension:
					action.setIcon(self.actIcon(extension['Icon']))
				mimetype = extension['MimeType'] if 'MimeType' in extension else None
			except KeyError:
				print('Failed to parse extension: Name is required', file=sys.stderr)
			else:
				self.extensionActions.append((action, mimetype))

	def updateExtensionsVisibility(self):
		markupClass = self.currentTab.getMarkupClass()
		for action in self.extensionActions:
			if markupClass is None:
				action[0].setEnabled(False)
				continue
			mimetype = action[1]
			if mimetype == None:
				enabled = True
			elif markupClass == markups.MarkdownMarkup:
				enabled = (mimetype in ("text/x-retext-markdown", "text/x-markdown"))
			elif markupClass == markups.ReStructuredTextMarkup:
				enabled = (mimetype in ("text/x-retext-rst", "text/x-rst"))
			else:
				enabled = False
			action[0].setEnabled(enabled)

	def readExtension(self, fileName):
		extFile = QFile(fileName)
		extFile.open(QIODevice.ReadOnly)
		extension = {}
		stream = QTextStream(extFile)
		while not stream.atEnd():
			line = stream.readLine()
			if '=' in line:
				index = line.index('=')
				extension[line[:index].rstrip()] = line[index+1:].lstrip()
		extFile.close()
		return extension

	def openFile(self):
		supportedExtensions = ['.txt']
		for markup in markups.get_all_markups():
			supportedExtensions += markup.file_extensions
		fileFilter = ' (' + str.join(' ', ['*'+ext for ext in supportedExtensions]) + ');;'
		fileNames = QFileDialog.getOpenFileNames(self,
			self.tr("Select one or several files to open"), "",
			self.tr("Supported files") + fileFilter + self.tr("All files (*)"))
		for fileName in fileNames[0]:
			self.openFileWrapper(fileName)

	def openFileWrapper(self, fileName):
		if not fileName:
			return
		fileName = QFileInfo(fileName).canonicalFilePath()
		exists = False
		for i, tab in enumerate(self.iterateTabs()):
			if tab.fileName == fileName:
				exists = True
				ex = i
		if exists:
			self.tabWidget.setCurrentIndex(ex)
		elif QFile.exists(fileName):
			noEmptyTab = (
				(self.ind is None) or
				self.currentTab.fileName or
				self.currentTab.editBox.toPlainText() or
				self.currentTab.editBox.document().isModified()
			)
			if noEmptyTab:
				self.createTab(fileName)
				self.ind = self.tabWidget.count()-1
				self.tabWidget.setCurrentIndex(self.ind)
			if fileName:
				self.fileSystemWatcher.addPath(fileName)
			self.currentTab.fileName = fileName
			self.currentTab.readTextFromFile()
			editBox = self.currentTab.editBox
			self.setCurrentFile()
			self.setWindowModified(editBox.document().isModified())

	def showEncodingDialog(self):
		if not self.maybeSave(self.ind):
			return
		encoding, ok = QInputDialog.getItem(self, '',
			self.tr('Select file encoding from the list:'),
			[bytes(b).decode() for b in QTextCodec.availableCodecs()],
			0, False)
		if ok:
			self.currentTab.readTextFromFile(encoding)

	def saveFile(self):
		self.saveFileMain(dlg=False)

	def saveFileAs(self):
		self.saveFileMain(dlg=True)

	def saveAll(self):
		for tab in self.iterateTabs():
			if tab.fileName and QFileInfo(tab.fileName).isWritable():
				tab.saveTextToFile()
				tab.editBox.document().setModified(False)

	def saveFileMain(self, dlg):
		if (not self.currentTab.fileName) or dlg:
			markupClass = self.currentTab.getMarkupClass()
			if (markupClass is None) or not hasattr(markupClass, 'default_extension'):
				defaultExt = self.tr("Plain text (*.txt)")
				ext = ".txt"
			else:
				defaultExt = self.tr('%s files',
					'Example of final string: Markdown files') \
					% markupClass.name + ' (' + str.join(' ',
					('*'+extension for extension in markupClass.file_extensions)) + ')'
				if markupClass == markups.MarkdownMarkup:
					ext = globalSettings.markdownDefaultFileExtension
				elif markupClass == markups.ReStructuredTextMarkup:
					ext = globalSettings.restDefaultFileExtension
				else:
					ext = markupClass.default_extension
			newFileName = QFileDialog.getSaveFileName(self,
				self.tr("Save file"), "", defaultExt)[0]
			if newFileName:
				if not QFileInfo(newFileName).suffix():
					newFileName += ext
				if self.currentTab.fileName:
					self.fileSystemWatcher.removePath(self.currentTab.fileName)
				self.currentTab.fileName = newFileName
				self.actionSetEncoding.setDisabled(self.autoSaveActive())
		if self.currentTab.fileName:
			if self.currentTab.saveTextToFile():
				self.setCurrentFile()
				self.currentTab.editBox.document().setModified(False)
				self.setWindowModified(False)
				return True
			else:
				QMessageBox.warning(self, '',
				self.tr("Cannot save to file because it is read-only!"))
		return False

	def saveHtml(self, fileName):
		if not QFileInfo(fileName).suffix():
			fileName += ".html"
		try:
			htmltext = self.currentTab.getHtml(includeStyleSheet=False,
				webenv=True)
		except Exception:
			return self.printError()
		htmlFile = QFile(fileName)
		htmlFile.open(QIODevice.WriteOnly)
		html = QTextStream(htmlFile)
		if globalSettings.defaultCodec:
			html.setCodec(globalSettings.defaultCodec)
		html << htmltext
		htmlFile.close()

	def textDocument(self):
		td = QTextDocument()
		td.setMetaInformation(QTextDocument.DocumentTitle,
		                      self.currentTab.getDocumentTitle())
		if self.ss:
			td.setDefaultStyleSheet(self.ss)
		td.setHtml(self.currentTab.getHtml())
		td.setDefaultFont(globalSettings.font)
		return td

	def saveOdf(self):
		try:
			document = self.textDocument()
		except Exception:
			return self.printError()
		fileName = QFileDialog.getSaveFileName(self,
			self.tr("Export document to ODT"), "",
			self.tr("OpenDocument text files (*.odt)"))[0]
		if not QFileInfo(fileName).suffix():
			fileName += ".odt"
		writer = QTextDocumentWriter(fileName)
		writer.setFormat(b"odf")
		writer.write(document)

	def saveFileHtml(self):
		fileName = QFileDialog.getSaveFileName(self,
			self.tr("Save file"), "",
			self.tr("HTML files (*.html *.htm)"))[0]
		if fileName:
			self.saveHtml(fileName)

	def getDocumentForPrint(self):
		if globalSettings.useWebKit:
			return self.currentTab.previewBox
		try:
			return self.textDocument()
		except Exception:
			self.printError()

	def standardPrinter(self):
		printer = QPrinter(QPrinter.HighResolution)
		printer.setDocName(self.currentTab.getDocumentTitle())
		printer.setCreator('ReText %s' % app_version)
		return printer

	def savePdf(self):
		self.currentTab.updatePreviewBox()
		fileName = QFileDialog.getSaveFileName(self,
			self.tr("Export document to PDF"),
			"", self.tr("PDF files (*.pdf)"))[0]
		if fileName:
			if not QFileInfo(fileName).suffix():
				fileName += ".pdf"
			printer = self.standardPrinter()
			printer.setOutputFormat(QPrinter.PdfFormat)
			printer.setOutputFileName(fileName)
			document = self.getDocumentForPrint()
			if document != None:
				document.print(printer)

	def printFile(self):
		self.currentTab.updatePreviewBox()
		printer = self.standardPrinter()
		dlg = QPrintDialog(printer, self)
		dlg.setWindowTitle(self.tr("Print document"))
		if (dlg.exec() == QDialog.Accepted):
			document = self.getDocumentForPrint()
			if document != None:
				document.print(printer)

	def printPreview(self):
		document = self.getDocumentForPrint()
		if document == None:
			return
		printer = self.standardPrinter()
		preview = QPrintPreviewDialog(printer, self)
		preview.paintRequested.connect(document.print)
		preview.exec()

	def runExtensionCommand(self, command, filefilter, defaultext):
		of = ('%of' in command)
		html = ('%html' in command)
		if of:
			if defaultext and not filefilter:
				filefilter = '*'+defaultext
			fileName = QFileDialog.getSaveFileName(self,
				self.tr('Export document'), '', filefilter)[0]
			if not fileName:
				return
			if defaultext and not QFileInfo(fileName).suffix():
				fileName += defaultext
		basename = '.%s.retext-temp' % self.currentTab.getDocumentTitle(baseName=True)
		if html:
			tmpname = basename+'.html'
			self.saveHtml(tmpname)
		else:
			tmpname = basename + self.currentTab.getMarkupClass().default_extension
			self.currentTab.saveTextToFile(fileName=tmpname, addToWatcher=False)
		command = command.replace('%of', '"out'+defaultext+'"')
		command = command.replace('%html' if html else '%if', '"'+tmpname+'"')
		try:
			Popen(str(command), shell=True).wait()
		except Exception as error:
			errorstr = str(error)
			QMessageBox.warning(self, '', self.tr('Failed to execute the command:')
			+ '\n' + errorstr)
		QFile(tmpname).remove()
		if of:
			QFile('out'+defaultext).rename(fileName)

	def autoSaveActive(self, ind=None):
		tab = self.currentTab if ind is None else self.tabWidget.widget(ind).tab
		return (self.autoSaveEnabled and tab.fileName and
			QFileInfo(tab.fileName).isWritable())

	def modificationChanged(self, changed):
		if self.autoSaveActive():
			changed = False
		self.actionSave.setEnabled(changed)
		self.setWindowModified(changed)

	def clipboardDataChanged(self):
		mimeData = QApplication.instance().clipboard().mimeData()
		if mimeData is not None:
			self.actionPaste.setEnabled(mimeData.hasText())

	def insertFormatting(self, formatting):
		cursor = self.currentTab.editBox.textCursor()
		text = cursor.selectedText()
		moveCursorTo = None

		def c(cursor):
			nonlocal moveCursorTo
			moveCursorTo = cursor.position()

		def ensurenl(cursor):
			if not cursor.atBlockStart():
				cursor.insertText('\n\n')

		toinsert = {
			'header': (ensurenl, '# ', text),
			'italic': ('*', text, c, '*'),
			'bold': ('**', text, c, '**'),
			'underline': ('<u>', text, c, '</u>'),
			'numbering': (ensurenl, ' 1. ', text),
			'bullets': (ensurenl, '  * ', text),
			'image': ('![', text or self.tr('Alt text'), c, '](', self.tr('URL'), ')'),
			'link': ('[', text or self.tr('Link text'), c, '](', self.tr('URL'), ')'),
			'inline code': ('`', text, c, '`'),
			'code block': (ensurenl, '    ', text),
			'blockquote': (ensurenl, '> ', text),
		}

		if formatting not in toinsert:
			return

		cursor.beginEditBlock()
		for token in toinsert[formatting]:
			if callable(token):
				token(cursor)
			else:
				cursor.insertText(token)
		cursor.endEditBlock()

		self.formattingBox.setCurrentIndex(0)
		# Bring back the focus on the editor
		self.currentTab.editBox.setFocus(Qt.OtherFocusReason)

		if moveCursorTo:
			cursor.setPosition(moveCursorTo)
			self.currentTab.editBox.setTextCursor(cursor)

	def insertSymbol(self, num):
		if num:
			self.currentTab.editBox.insertPlainText('&'+self.usefulChars[num-1]+';')
		self.symbolBox.setCurrentIndex(0)

	def fileChanged(self, fileName):
		ind = None
		for testind, tab in enumerate(self.iterateTabs()):
			if tab.fileName == fileName:
				ind = testind
		if ind is None:
			self.fileSystemWatcher.removePath(fileName)
		self.tabWidget.setCurrentIndex(ind)
		if not QFile.exists(fileName):
			self.currentTab.editBox.document().setModified(True)
			QMessageBox.warning(self, '', self.tr(
				'This file has been deleted by other application.\n'
				'Please make sure you save the file before exit.'))
		elif not self.currentTab.editBox.document().isModified():
			# File was not modified in ReText, reload silently
			self.currentTab.readTextFromFile()
			self.currentTab.updatePreviewBox()
		else:
			text = self.tr(
				'This document has been modified by other application.\n'
				'Do you want to reload the file (this will discard all '
				'your changes)?\n')
			if self.autoSaveEnabled:
				text += self.tr(
					'If you choose to not reload the file, auto save mode will '
					'be disabled for this session to prevent data loss.')
			messageBox = QMessageBox(QMessageBox.Warning, '', text)
			reloadButton = messageBox.addButton(self.tr('Reload'), QMessageBox.YesRole)
			messageBox.addButton(QMessageBox.Cancel)
			messageBox.exec()
			if messageBox.clickedButton() is reloadButton:
				self.currentTab.readTextFromFile()
				self.currentTab.updatePreviewBox()
			else:
				self.autoSaveEnabled = False
				self.currentTab.editBox.document().setModified(True)
		if fileName not in self.fileSystemWatcher.files():
			# https://github.com/retext-project/retext/issues/137
			self.fileSystemWatcher.addPath(fileName)

	def maybeSave(self, ind):
		tab = self.tabWidget.widget(ind).tab
		if self.autoSaveActive(ind):
			tab.saveTextToFile()
			return True
		if not tab.editBox.document().isModified():
			return True
		self.tabWidget.setCurrentIndex(ind)
		ret = QMessageBox.warning(self, '',
			self.tr("The document has been modified.\nDo you want to save your changes?"),
			QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel)
		if ret == QMessageBox.Save:
			return self.saveFileMain(False)
		elif ret == QMessageBox.Cancel:
			return False
		return True

	def closeEvent(self, closeevent):
		for ind in range(self.tabWidget.count()):
			if not self.maybeSave(ind):
				return closeevent.ignore()
		if globalSettings.saveWindowGeometry and not self.isMaximized():
			globalSettings.windowGeometry = self.saveGeometry()
		closeevent.accept()

	def viewHtml(self):
		htmlDlg = HtmlDialog(self)
		try:
			htmltext = self.currentTab.getHtml(includeStyleSheet=False)
		except Exception:
			return self.printError()
		winTitle = self.currentTab.getDocumentTitle(baseName=True)
		htmlDlg.setWindowTitle(winTitle+" ("+self.tr("HTML code")+")")
		htmlDlg.textEdit.setPlainText(htmltext.rstrip())
		htmlDlg.hl.rehighlight()
		htmlDlg.show()
		htmlDlg.raise_()
		htmlDlg.activateWindow()

	def openHelp(self):
		QDesktopServices.openUrl(QUrl('https://github.com/retext-project/retext/wiki'))

	def aboutDialog(self):
		QMessageBox.about(self, self.aboutWindowTitle,
		'<p><b>' + (self.tr('ReText %s (using PyMarkups %s)') % (app_version, markups.__version__))
		+'</b></p>' + self.tr('Simple but powerful editor'
		' for Markdown and reStructuredText')
		+'</p><p>'+self.tr('Author: Dmitry Shachnev, 2011').replace('2011', '2011–2016')
		+'<br><a href="https://github.com/retext-project/retext">'+self.tr('Website')
		+'</a> | <a href="http://daringfireball.net/projects/markdown/syntax">'
		+self.tr('Markdown syntax')
		+'</a> | <a href="http://docutils.sourceforge.net/docs/user/rst/quickref.html">'
		+self.tr('reStructuredText syntax')+'</a></p>')

	def setDefaultMarkup(self, markupClass):
		self.defaultMarkup = markupClass
		defaultName = markups.get_available_markups()[0].name
		writeToSettings('defaultMarkup', markupClass.name, defaultName)
		for tab in self.iterateTabs():
			if not tab.fileName:
				tab.setMarkupClass(markupClass)
				tab.updatePreviewBox()
		self.docTypeChanged()
コード例 #33
0
class SimulatorWindow(QMainWindow):
    def __init__(self, argv):
        QMainWindow.__init__(self)
        self.setWindowTitle("SimSo: Real-Time Scheduling Simulator")

        # Possible actions:
        style = QApplication.style()

        # New
        self._newAction = QAction(
            style.standardIcon(QStyle.SP_FileDialogNewFolder), '&New', None)
        self._newAction.setShortcut(Qt.CTRL + Qt.Key_N)
        self._newAction.triggered.connect(self.fileNew)

        # Open
        self._openAction = QAction(
            style.standardIcon(QStyle.SP_DialogOpenButton), '&Open', None)
        self._openAction.setShortcut(Qt.CTRL + Qt.Key_O)
        self._openAction.triggered.connect(self.fileOpen)

        # Save
        self._saveAction = QAction(
            style.standardIcon(QStyle.SP_DialogSaveButton), '&Save', None)
        self._saveAction.setShortcut(Qt.CTRL + Qt.Key_S)
        self._saveAction.triggered.connect(self.fileSave)

        # Save As
        self._saveAsAction = QAction(
            style.standardIcon(QStyle.SP_DialogSaveButton), 'Save &As', None)
        self._saveAsAction.setShortcut(Qt.CTRL + Qt.SHIFT + Qt.Key_S)
        self._saveAsAction.triggered.connect(self.fileSaveAs)

        # Run
        self._runAction = QAction(
            style.standardIcon(QStyle.SP_MediaPlay), '&Run', None)
        self._runAction.setShortcut(Qt.CTRL + Qt.Key_R)
        self._runAction.triggered.connect(self.fileRun)

        # Show Model data
        self._modelAction = QAction('&Model data', None)
        self._modelAction.setShortcut(Qt.CTRL + Qt.Key_M)
        #self._ganttAction.setCheckable(True)
        self._modelAction.triggered.connect(self.showModelWindow)

        # Show Gantt
        self._ganttAction = QAction('&Gantt', None)
        self._ganttAction.setShortcut(Qt.CTRL + Qt.Key_G)
        self._ganttAction.setEnabled(False)
        #self._ganttAction.setCheckable(True)
        self._ganttAction.triggered.connect(self.showGantt)

        # Show Results
        self._metricsAction = QAction('&Results', None)
        self._metricsAction.setShortcut(Qt.CTRL + Qt.Key_I)
        self._metricsAction.setEnabled(False)
        #self._metricsAction.setCheckable(True)
        self._metricsAction.triggered.connect(self.showResults)

        # Show Doc
        self._docAction = QAction('&Documentation', None)
        self._docAction.triggered.connect(self.showDocumentation)

        self._aboutAction = QAction('&About SimSo', None)
        self._aboutAction.triggered.connect(self.showAbout)

        # Recent files
        self._recentFileActions = []
        for i in range(5):
            act = QAction(self)
            act.setVisible(False)
            act.triggered.connect(self.openRecentFile)
            self._recentFileActions.append(act)

        # File Menu:
        file_menu = QMenu('&File', self)
        file_menu.addAction(self._newAction)
        file_menu.addAction(self._openAction)
        file_menu.addAction(self._saveAction)
        file_menu.addAction(self._saveAsAction)
        file_menu.addAction(self._runAction)
        file_menu.addSeparator()
        for act in self._recentFileActions:
            file_menu.addAction(act)
        file_menu.addSeparator()
        file_menu.addAction('&Quit', self.fileQuit, Qt.CTRL + Qt.Key_Q)
        self.updateRecentFileActions()

        # View Menu:
        view_menu = QMenu('&View', self)
        view_menu.addAction(self._modelAction)
        view_menu.addAction(self._ganttAction)
        view_menu.addAction(self._metricsAction)

        # Help Menu:
        help_menu = QMenu('&Help', self)
        help_menu.addAction(self._docAction)
        help_menu.addAction(self._aboutAction)

        # Add menus to menuBar:
        self.menuBar().addMenu(file_menu)
        self.menuBar().addMenu(view_menu)
        self.menuBar().addMenu(help_menu)

        # ToolBar:
        self.toolBar = QToolBar("Main ToolBar")
        self.addToolBar(self.toolBar)
        self.toolBar.addAction(self._newAction)
        self.toolBar.addAction(self._openAction)
        self.toolBar.addAction(self._saveAction)
        self.toolBar.addAction(self._runAction)
        self.toolBar.addAction(self._ganttAction)
        self.toolBar.addAction(self._metricsAction)

        # Tab:
        self.main_tab = QTabWidget()
        self.main_tab.setTabsClosable(True)
        self.main_tab.setMovable(True)
        self.main_tab.tabCloseRequested.connect(self.tabCloseRequested)
        self.main_tab.currentChanged.connect(self.tabChanged)
        self.setCentralWidget(self.main_tab)

        # Init statusBar:
        self.statusBar().showMessage("", 2000)

        self._documentation = None

        if argv:
            for arg in argv:
                try:
                    self.open_file(arg)
                except Exception as e:
                    print(e)
        else:
            self.fileNew()

    def openRecentFile(self):
        try:
            self.open_file(self.sender().data().toString())
        except AttributeError:
            self.open_file(self.sender().data())

    def updateRecentFileActions(self):
        settings = QSettings()
        files = settings.value("recentFileList", defaultValue=[],
                               type='QString')
        for i in range(5):
            if i < len(files):
                text = "&{} {}".format(i + 1, QFileInfo(files[i]).fileName())
                self._recentFileActions[i].setText(text)
                self._recentFileActions[i].setData(files[i])
                self._recentFileActions[i].setVisible(True)
            else:
                self._recentFileActions[i].setVisible(False)

    def setCurrentFile(self, filename):
        filename = QFileInfo(filename).absoluteFilePath()
        settings = QSettings()
        files = settings.value("recentFileList", defaultValue=[],
                               type='QString')

        if filename in files:
            files.remove(filename)
        files.insert(0, filename)
        while len(files) > 5:
            del files[-1]

        settings.setValue("recentFileList", files)
        self.updateRecentFileActions()

    def showAbout(self):
        QMessageBox.about(
            self, "About SimSo",
            "<b>SimSo - Simulation of Multiprocessor Scheduling with Overheads</b><br/><br/>"
            "Version: SimSo {}, Graphical User Interface {}<br/><br/>"
            "SimSo is a free software developed by Maxime Cheramy (LAAS-CNRS).<br/>"
            "This software is distributed under the <a href='http://www.cecill.info'>CECILL license</a>, "
            "compatible with the GNU GPL.<br/><br/>"
            "Contact: <a href='mailto:[email protected]'>[email protected]</a>".format(simso.__version__, simsogui.__version__)
        )

    def showDocumentation(self):
        if self._documentation is None:
            doc = QWebView(self)
            doc.load(QUrl("doc/html/index.html"))
            self._documentation = QDockWidget("Documentation", self)
            self._documentation.setWidget(doc)
            self._documentation.closeEvent = lambda _: self.hide_documentation()

        self.addDockWidget(Qt.LeftDockWidgetArea, self._documentation)

    def showGantt(self):
        self.main_tab.currentWidget().showGantt()

    def showModelWindow(self):
        self.main_tab.currentWidget().showModelWindow()

    def showResults(self):
        self.main_tab.currentWidget().showResults()

    def hide_documentation(self):
        self._documentation = None

    def fileNew(self):
        self.main_tab.addTab(SimulationTab(self), 'Unsaved')

    def fileOpen(self):
        simulation_file = QFileDialog.getOpenFileName(
            filter="*.xml", caption="Open XML simulation file.")[0]
        if simulation_file:
            self.open_file(simulation_file)

    def open_file(self, simulation_file):
        try:
            simulation_file = unicode(simulation_file)
        except NameError:
            pass

        try:
            self.setCurrentFile(simulation_file)
            sim = SimulationTab(self, simulation_file)
            if (self.main_tab.currentWidget()
                    and not self.main_tab.currentWidget().simulation_file
                    and self.main_tab.currentWidget().configuration.is_saved()
                    and self.main_tab.count() == 1):
                self.main_tab.removeTab(0)
            self.main_tab.addTab(sim, os.path.split(simulation_file)[1])
            self.main_tab.setCurrentWidget(sim)
            self.updateMenus()
        except Exception:
            QMessageBox.critical(
                self, "Could not open file",
                "The file {} could not be opened.".format(simulation_file))
            print(traceback.format_exc())

    def fileSave(self):
        try:
            self.main_tab.currentWidget().save()
        except:
            self.fileSaveAs()

    def fileSaveAs(self):
        simulation_file = QFileDialog.getSaveFileName(
            filter="*.xml", caption="Save XML simulation file.")[0]
        try:
            simulation_file = unicode(simulation_file)
        except NameError:
            pass
        if simulation_file:
            if simulation_file[-4:] != '.xml':
                simulation_file += '.xml'
            self.main_tab.currentWidget().save_as(simulation_file)
            self.setCurrentFile(simulation_file)

    def fileRun(self):
        self._runAction.setEnabled(False)
        self.main_tab.currentWidget().run()

    def fileQuit(self):
        self.close()

    def setTabText(self, tab, text):
        self.main_tab.setTabText(self.main_tab.indexOf(tab), text)

    def tabChanged(self, index):
        self.updateMenus()

    def tabCloseRequested(self, index):
        if self.main_tab.widget(index).close():
            self.main_tab.removeTab(index)
            self.updateMenus()

    def closeEvent(self, event):
        while self.main_tab.count() > 0:
            if self.main_tab.widget(0).close():
                self.main_tab.removeTab(0)
            else:
                event.ignore()
                return

    def updateMenus(self):
        if self.main_tab.count() > 0:
            widget = self.main_tab.currentWidget()
            self._runAction.setEnabled(True)
            self._modelAction.setEnabled(True)
            self._ganttAction.setEnabled(widget._model is not None)
            self._metricsAction.setEnabled(widget._model is not None)
        else:
            self._runAction.setEnabled(False)
            self._modelAction.setEnabled(False)
            self._ganttAction.setEnabled(False)
            self._metricsAction.setEnabled(False)
コード例 #34
0
ファイル: students.py プロジェクト: jfisteus/eyegrade
class StudentGroupsTabs(QWidget):
    def __init__(self, parent, student_listings=None):
        super().__init__(parent)
        if student_listings is None:
            self.student_listings = students.StudentListings()
            inserted_group = students.StudentGroup(0, 'INSERTED')
            self.student_listings.create_listing(inserted_group)
        else:
            self.student_listings = student_listings
        layout = QVBoxLayout(self)
        self.setLayout(layout)
        self.tabs = QTabWidget(self)
        # Special tab for creating a new group:
        self.tabs.addTab(QWidget(), '  +  ')
        # Group 0 is special: don't show it
        for listing in self.student_listings[1:]:
            self._add_group_tab(listing)
        # At least one normal group needs to be present:
        if len(self.student_listings) == 1:
            self._create_default_group()
        button_load = QPushButton(_('Add students from file'), parent=self)
        button_new_student = QPushButton(
            QIcon(utils.resource_path('new_id.svg')),
            _('New student'),
            parent=self)
        button_remove = QPushButton(
            QIcon(utils.resource_path('discard.svg')),
            _('Remove group'),
            parent=self)
        layout.addWidget(self.tabs)
        layout.addWidget(button_load)
        layout.addWidget(button_new_student)
        layout.addWidget(button_remove)
        layout.setAlignment(button_load, Qt.AlignHCenter)
        layout.setAlignment(button_new_student, Qt.AlignHCenter)
        layout.setAlignment(button_remove, Qt.AlignHCenter)
        self.tabs.setCurrentIndex(0)
        self._active_tab = 0
        self.tabs.currentChanged.connect(self._tab_changed)
        self.tabs.tabBarDoubleClicked.connect(self._rename_group)
        button_load.clicked.connect(self._load_students)
        button_new_student.clicked.connect(self._new_student)
        button_remove.clicked.connect(self._remove_group)

    def _load_students(self):
        index = self.tabs.currentIndex()
        file_name, __ = QFileDialog.getOpenFileName(
            self,
            _('Select the student list file'),
            '',
            FileNameFilters.student_list,
            None,
            QFileDialog.DontUseNativeDialog)
        try:
            if file_name:
                with students.StudentReader.create(file_name) as reader:
                    student_list = list(reader.students())
                # Flag duplicate student ids:
                warn_duplicates = False
                for s in self.student_listings.find_duplicates(student_list):
                    s.is_duplicate = True
                    warn_duplicates = True
                if warn_duplicates:
                    QMessageBox.warning(
                        self,
                        _('Importing a student list'),
                        _('Some student ids are already in the list. '
                          'Remove them or cancel the import operation.'))
                column_map = reader.column_map.normalize()
                preview_dialog = DialogPreviewStudents(
                    self, student_list, column_map)
                result = preview_dialog.exec_()
                if result == QMessageBox.Accepted:
                    self.tabs.widget(index).add_students(student_list)
        except Exception as e:
            QMessageBox.critical(
                self,
                _('Error in student list'),
                file_name + '\n\n' + str(e))

    def _new_student(self):
        index = self.tabs.currentIndex()
        dialog = NewStudentDialog(
            self.student_listings,
            group_index=index,
            parent=self)
        student = dialog.exec_()
        if student is not None:
            self.tabs.widget(index).listing_updated()

    def _remove_group(self):
        index = self.tabs.currentIndex()
        if len(self.student_listings[index + 1]) > 0:
            result = QMessageBox.warning(
                self,
                _('Warning'),
                _('This group and its students will be removed. '
                  'Are you sure you want to continue?'),
                QMessageBox.Yes | QMessageBox.No,
                QMessageBox.No)
            remove = (result == QMessageBox.Yes)
        else:
            remove = True
        if remove:
            try:
                self.student_listings.remove_at(index + 1)
                if len(self.student_listings) > 1:
                    if index == self.tabs.count() - 2:
                        self.tabs.setCurrentIndex(index - 1)
                    else:
                        self.tabs.setCurrentIndex(index + 1)
                else:
                    self._create_default_group()
                    self.tabs.setCurrentIndex(1)
                self.tabs.removeTab(index)
            except students.CantRemoveGroupException:
                QMessageBox.critical(
                    self,
                    _('Error'),
                    _('This group cannot be removed because '
                      'exams have been graded for some of its students.'))

    def _add_group_tab(self, listing, show=False):
        self.tabs.insertTab(
            self.tabs.count() - 1,
            GroupWidget(listing, self),
            listing.group.name
        )
        if show:
            self.tabs.setCurrentIndex(self.tabs.count() - 2)

    def _new_group(self):
        group_name = GroupNameDialog(parent=self).exec_()
        if group_name is not None:
            group = students.StudentGroup(None, group_name)
            listing = self.student_listings.create_listing(group)
            self._add_group_tab(listing, show=True)
        else:
            self.tabs.setCurrentIndex(self._active_tab)

    def _create_default_group(self):
        group = students.StudentGroup(None, _('Students'))
        listing = self.student_listings.create_listing(group)
        self._add_group_tab(listing, show=True)

    def _rename_group(self, index):
        name = self.student_listings[index + 1].group.name
        new_name = GroupNameDialog(group_name=name, parent=self).exec_()
        if new_name is not None and new_name != name:
            self.student_listings[index + 1].rename(new_name)
            self.tabs.setTabText(index, new_name)

    def _tab_changed(self, index):
        if index == self.tabs.count() - 1:
            # The last (special) tab has been activated: create a new group
            self._new_group()
        self._active_tab = self.tabs.currentIndex()
コード例 #35
0
ファイル: window.py プロジェクト: zisecheng/retext
class ReTextWindow(QMainWindow):
	def __init__(self, parent=None):
		QMainWindow.__init__(self, parent)
		self.resize(950, 700)
		screenRect = QDesktopWidget().screenGeometry()
		if globalSettings.windowGeometry:
			self.restoreGeometry(globalSettings.windowGeometry)
		else:
			self.move((screenRect.width()-self.width())/2, (screenRect.height()-self.height())/2)
		if not screenRect.contains(self.geometry()):
			self.showMaximized()
		if globalSettings.iconTheme:
			QIcon.setThemeName(globalSettings.iconTheme)
		if QIcon.themeName() in ('hicolor', ''):
			if not QFile.exists(icon_path + 'document-new.png'):
				QIcon.setThemeName(get_icon_theme())
		if QFile.exists(icon_path+'retext.png'):
			self.setWindowIcon(QIcon(icon_path+'retext.png'))
		elif QFile.exists('/usr/share/pixmaps/retext.png'):
			self.setWindowIcon(QIcon('/usr/share/pixmaps/retext.png'))
		else:
			self.setWindowIcon(QIcon.fromTheme('retext',
				QIcon.fromTheme('accessories-text-editor')))
		self.editBoxes = []
		self.previewBoxes = []
		self.highlighters = []
		self.markups = []
		self.fileNames = []
		self.actionPreviewChecked = []
		self.actionLivePreviewChecked = []
		self.tabWidget = QTabWidget(self)
		self.initTabWidget()
		self.setCentralWidget(self.tabWidget)
		self.tabWidget.currentChanged.connect(self.changeIndex)
		self.tabWidget.tabCloseRequested.connect(self.closeTab)
		toolBar = QToolBar(self.tr('File toolbar'), self)
		self.addToolBar(Qt.TopToolBarArea, toolBar)
		self.editBar = QToolBar(self.tr('Edit toolbar'), self)
		self.addToolBar(Qt.TopToolBarArea, self.editBar)
		self.searchBar = QToolBar(self.tr('Search toolbar'), self)
		self.addToolBar(Qt.BottomToolBarArea, self.searchBar)
		toolBar.setVisible(not globalSettings.hideToolBar)
		self.editBar.setVisible(not globalSettings.hideToolBar)
		self.actionNew = self.act(self.tr('New'), 'document-new',
			self.createNew, shct=QKeySequence.New)
		self.actionNew.setPriority(QAction.LowPriority)
		self.actionOpen = self.act(self.tr('Open'), 'document-open',
			self.openFile, shct=QKeySequence.Open)
		self.actionOpen.setPriority(QAction.LowPriority)
		self.actionSetEncoding = self.act(self.tr('Set encoding'),
			trig=self.showEncodingDialog)
		self.actionSetEncoding.setEnabled(False)
		self.actionReload = self.act(self.tr('Reload'), 'view-refresh', trig=self.openFileMain)
		self.actionReload.setEnabled(False)
		self.actionSave = self.act(self.tr('Save'), 'document-save',
			self.saveFile, shct=QKeySequence.Save)
		self.actionSave.setEnabled(False)
		self.actionSave.setPriority(QAction.LowPriority)
		self.actionSaveAs = self.act(self.tr('Save as'), 'document-save-as',
			self.saveFileAs, shct=QKeySequence.SaveAs)
		self.actionNextTab = self.act(self.tr('Next tab'), 'go-next',
			lambda: self.switchTab(1), shct=Qt.CTRL+Qt.Key_PageDown)
		self.actionPrevTab = self.act(self.tr('Previous tab'), 'go-previous',
			lambda: self.switchTab(-1), shct=Qt.CTRL+Qt.Key_PageUp)
		self.actionPrint = self.act(self.tr('Print'), 'document-print',
			self.printFile, shct=QKeySequence.Print)
		self.actionPrint.setPriority(QAction.LowPriority)
		self.actionPrintPreview = self.act(self.tr('Print preview'), 'document-print-preview',
			self.printPreview)
		self.actionViewHtml = self.act(self.tr('View HTML code'), 'text-html', self.viewHtml)
		self.actionChangeEditorFont = self.act(self.tr('Change editor font'),
			trig=self.changeEditorFont)
		self.actionChangePreviewFont = self.act(self.tr('Change preview font'),
			trig=self.changePreviewFont)
		self.actionSearch = self.act(self.tr('Find text'), 'edit-find', shct=QKeySequence.Find)
		self.actionSearch.setCheckable(True)
		self.actionSearch.triggered[bool].connect(self.searchBar.setVisible)
		self.searchBar.visibilityChanged.connect(self.searchBarVisibilityChanged)
		self.actionPreview = self.act(self.tr('Preview'), shct=Qt.CTRL+Qt.Key_E,
			trigbool=self.preview)
		if QIcon.hasThemeIcon('document-preview'):
			self.actionPreview.setIcon(QIcon.fromTheme('document-preview'))
		elif QIcon.hasThemeIcon('preview-file'):
			self.actionPreview.setIcon(QIcon.fromTheme('preview-file'))
		elif QIcon.hasThemeIcon('x-office-document'):
			self.actionPreview.setIcon(QIcon.fromTheme('x-office-document'))
		else:
			self.actionPreview.setIcon(QIcon(icon_path+'document-preview.png'))
		self.actionLivePreview = self.act(self.tr('Live preview'), shct=Qt.CTRL+Qt.Key_L,
		trigbool=self.enableLivePreview)
		self.actionTableMode = self.act(self.tr('Table mode'), shct=Qt.CTRL+Qt.Key_T,
			trigbool=lambda x: self.editBoxes[self.ind].enableTableMode(x))
		if ReTextFakeVimHandler:
			self.actionFakeVimMode = self.act(self.tr('FakeVim mode'),
				shct=Qt.CTRL+Qt.ALT+Qt.Key_V, trigbool=self.enableFakeVimMode)
			if globalSettings.useFakeVim:
				self.actionFakeVimMode.setChecked(True)
				self.enableFakeVimMode(True)
		self.actionFullScreen = self.act(self.tr('Fullscreen mode'), 'view-fullscreen',
			shct=Qt.Key_F11, trigbool=self.enableFullScreen)
		self.actionFullScreen.setPriority(QAction.LowPriority)
		self.actionConfig = self.act(self.tr('Preferences'), icon='preferences-system',
			trig=self.openConfigDialog)
		self.actionConfig.setMenuRole(QAction.PreferencesRole)
		self.actionSaveHtml = self.act('HTML', 'text-html', self.saveFileHtml)
		self.actionPdf = self.act('PDF', 'application-pdf', self.savePdf)
		self.actionOdf = self.act('ODT', 'x-office-document', self.saveOdf)
		self.getExportExtensionsList()
		self.actionQuit = self.act(self.tr('Quit'), 'application-exit', shct=QKeySequence.Quit)
		self.actionQuit.setMenuRole(QAction.QuitRole)
		self.actionQuit.triggered.connect(self.close)
		self.actionUndo = self.act(self.tr('Undo'), 'edit-undo',
			lambda: self.editBoxes[self.ind].undo(), shct=QKeySequence.Undo)
		self.actionRedo = self.act(self.tr('Redo'), 'edit-redo',
			lambda: self.editBoxes[self.ind].redo(), shct=QKeySequence.Redo)
		self.actionCopy = self.act(self.tr('Copy'), 'edit-copy',
			lambda: self.editBoxes[self.ind].copy(), shct=QKeySequence.Copy)
		self.actionCut = self.act(self.tr('Cut'), 'edit-cut',
			lambda: self.editBoxes[self.ind].cut(), shct=QKeySequence.Cut)
		self.actionPaste = self.act(self.tr('Paste'), 'edit-paste',
			lambda: self.editBoxes[self.ind].paste(), shct=QKeySequence.Paste)
		self.actionUndo.setEnabled(False)
		self.actionRedo.setEnabled(False)
		self.actionCopy.setEnabled(False)
		self.actionCut.setEnabled(False)
		qApp = QApplication.instance()
		qApp.clipboard().dataChanged.connect(self.clipboardDataChanged)
		self.clipboardDataChanged()
		if enchant_available:
			self.actionEnableSC = self.act(self.tr('Enable'), trigbool=self.enableSpellCheck)
			self.actionSetLocale = self.act(self.tr('Set locale'), trig=self.changeLocale)
		self.actionWebKit = self.act(self.tr('Use WebKit renderer'), trigbool=self.enableWebKit)
		self.actionWebKit.setChecked(globalSettings.useWebKit)
		self.actionShow = self.act(self.tr('Show directory'), 'system-file-manager', self.showInDir)
		self.actionFind = self.act(self.tr('Next'), 'go-next', self.find,
			shct=QKeySequence.FindNext)
		self.actionFindPrev = self.act(self.tr('Previous'), 'go-previous',
			lambda: self.find(back=True), shct=QKeySequence.FindPrevious)
		self.actionHelp = self.act(self.tr('Get help online'), 'help-contents', self.openHelp)
		self.aboutWindowTitle = self.tr('About ReText')
		self.actionAbout = self.act(self.aboutWindowTitle, 'help-about', self.aboutDialog)
		self.actionAbout.setMenuRole(QAction.AboutRole)
		self.actionAboutQt = self.act(self.tr('About Qt'))
		self.actionAboutQt.setMenuRole(QAction.AboutQtRole)
		self.actionAboutQt.triggered.connect(qApp.aboutQt)
		availableMarkups = markups.get_available_markups()
		if not availableMarkups:
			print('Warning: no markups are available!')
		self.defaultMarkup = availableMarkups[0] if availableMarkups else None
		if globalSettings.defaultMarkup:
			mc = markups.find_markup_class_by_name(globalSettings.defaultMarkup)
			if mc and mc.available():
				self.defaultMarkup = mc
		if len(availableMarkups) > 1:
			self.chooseGroup = QActionGroup(self)
			markupActions = []
			for markup in availableMarkups:
				markupAction = self.act(markup.name, trigbool=self.markupFunction(markup))
				if markup == self.defaultMarkup:
					markupAction.setChecked(True)
				self.chooseGroup.addAction(markupAction)
				markupActions.append(markupAction)
		self.actionBold = self.act(self.tr('Bold'), shct=QKeySequence.Bold,
			trig=lambda: self.insertChars('**'))
		self.actionItalic = self.act(self.tr('Italic'), shct=QKeySequence.Italic,
			trig=lambda: self.insertChars('*'))
		self.actionUnderline = self.act(self.tr('Underline'), shct=QKeySequence.Underline,
			trig=lambda: self.insertTag('u'))
		self.usefulTags = ('a', 'big', 'center', 'img', 's', 'small', 'span',
			'table', 'td', 'tr', 'u')
		self.usefulChars = ('deg', 'divide', 'dollar', 'hellip', 'laquo', 'larr',
			'lsquo', 'mdash', 'middot', 'minus', 'nbsp', 'ndash', 'raquo',
			'rarr', 'rsquo', 'times')
		self.tagsBox = QComboBox(self.editBar)
		self.tagsBox.addItem(self.tr('Tags'))
		self.tagsBox.addItems(self.usefulTags)
		self.tagsBox.activated.connect(self.insertTag)
		self.symbolBox = QComboBox(self.editBar)
		self.symbolBox.addItem(self.tr('Symbols'))
		self.symbolBox.addItems(self.usefulChars)
		self.symbolBox.activated.connect(self.insertSymbol)
		self.updateStyleSheet()
		menubar = QMenuBar(self)
		menubar.setGeometry(QRect(0, 0, 800, 25))
		self.setMenuBar(menubar)
		menuFile = menubar.addMenu(self.tr('File'))
		menuEdit = menubar.addMenu(self.tr('Edit'))
		menuHelp = menubar.addMenu(self.tr('Help'))
		menuFile.addAction(self.actionNew)
		menuFile.addAction(self.actionOpen)
		self.menuRecentFiles = menuFile.addMenu(self.tr('Open recent'))
		self.menuRecentFiles.aboutToShow.connect(self.updateRecentFiles)
		menuFile.addMenu(self.menuRecentFiles)
		menuFile.addAction(self.actionShow)
		menuFile.addAction(self.actionSetEncoding)
		menuFile.addAction(self.actionReload)
		menuFile.addSeparator()
		menuFile.addAction(self.actionSave)
		menuFile.addAction(self.actionSaveAs)
		menuFile.addSeparator()
		menuFile.addAction(self.actionNextTab)
		menuFile.addAction(self.actionPrevTab)
		menuFile.addSeparator()
		menuExport = menuFile.addMenu(self.tr('Export'))
		menuExport.addAction(self.actionSaveHtml)
		menuExport.addAction(self.actionOdf)
		menuExport.addAction(self.actionPdf)
		if self.extensionActions:
			menuExport.addSeparator()
			for action, mimetype in self.extensionActions:
				menuExport.addAction(action)
			menuExport.aboutToShow.connect(self.updateExtensionsVisibility)
		menuFile.addAction(self.actionPrint)
		menuFile.addAction(self.actionPrintPreview)
		menuFile.addSeparator()
		menuFile.addAction(self.actionQuit)
		menuEdit.addAction(self.actionUndo)
		menuEdit.addAction(self.actionRedo)
		menuEdit.addSeparator()
		menuEdit.addAction(self.actionCut)
		menuEdit.addAction(self.actionCopy)
		menuEdit.addAction(self.actionPaste)
		menuEdit.addSeparator()
		if enchant_available:
			menuSC = menuEdit.addMenu(self.tr('Spell check'))
			menuSC.addAction(self.actionEnableSC)
			menuSC.addAction(self.actionSetLocale)
		menuEdit.addAction(self.actionSearch)
		menuEdit.addAction(self.actionChangeEditorFont)
		menuEdit.addAction(self.actionChangePreviewFont)
		menuEdit.addSeparator()
		if len(availableMarkups) > 1:
			self.menuMode = menuEdit.addMenu(self.tr('Default markup'))
			for markupAction in markupActions:
				self.menuMode.addAction(markupAction)
		menuFormat = menuEdit.addMenu(self.tr('Formatting'))
		menuFormat.addAction(self.actionBold)
		menuFormat.addAction(self.actionItalic)
		menuFormat.addAction(self.actionUnderline)
		menuEdit.addAction(self.actionWebKit)
		menuEdit.addSeparator()
		menuEdit.addAction(self.actionViewHtml)
		menuEdit.addAction(self.actionLivePreview)
		menuEdit.addAction(self.actionPreview)
		menuEdit.addAction(self.actionTableMode)
		if ReTextFakeVimHandler:
			menuEdit.addAction(self.actionFakeVimMode)
		menuEdit.addSeparator()
		menuEdit.addAction(self.actionFullScreen)
		menuEdit.addAction(self.actionConfig)
		menuHelp.addAction(self.actionHelp)
		menuHelp.addSeparator()
		menuHelp.addAction(self.actionAbout)
		menuHelp.addAction(self.actionAboutQt)
		menubar.addMenu(menuFile)
		menubar.addMenu(menuEdit)
		menubar.addMenu(menuHelp)
		toolBar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
		toolBar.addAction(self.actionNew)
		toolBar.addSeparator()
		toolBar.addAction(self.actionOpen)
		toolBar.addAction(self.actionSave)
		toolBar.addAction(self.actionPrint)
		toolBar.addSeparator()
		toolBar.addAction(self.actionPreview)
		toolBar.addAction(self.actionFullScreen)
		self.editBar.addAction(self.actionUndo)
		self.editBar.addAction(self.actionRedo)
		self.editBar.addSeparator()
		self.editBar.addAction(self.actionCut)
		self.editBar.addAction(self.actionCopy)
		self.editBar.addAction(self.actionPaste)
		self.editBar.addSeparator()
		self.editBar.addWidget(self.tagsBox)
		self.editBar.addWidget(self.symbolBox)
		self.searchEdit = QLineEdit(self.searchBar)
		self.searchEdit.setPlaceholderText(self.tr('Search'))
		self.searchEdit.returnPressed.connect(self.find)
		self.csBox = QCheckBox(self.tr('Case sensitively'), self.searchBar)
		self.searchBar.addWidget(self.searchEdit)
		self.searchBar.addSeparator()
		self.searchBar.addWidget(self.csBox)
		self.searchBar.addAction(self.actionFindPrev)
		self.searchBar.addAction(self.actionFind)
		self.searchBar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
		self.searchBar.setVisible(False)
		self.autoSaveEnabled = globalSettings.autoSave
		if self.autoSaveEnabled:
			timer = QTimer(self)
			timer.start(60000)
			timer.timeout.connect(self.saveAll)
		self.ind = None
		if enchant_available:
			self.sl = globalSettings.spellCheckLocale
			if self.sl:
				try:
					enchant.Dict(self.sl)
				except Exception as e:
					print(e, file=sys.stderr)
					self.sl = None
			if globalSettings.spellCheck:
				self.actionEnableSC.setChecked(True)
				self.enableSpellCheck(True)
		self.fileSystemWatcher = QFileSystemWatcher()
		self.fileSystemWatcher.fileChanged.connect(self.fileChanged)

	def updateStyleSheet(self):
		if globalSettings.styleSheet:
			sheetfile = QFile(globalSettings.styleSheet)
			sheetfile.open(QIODevice.ReadOnly)
			self.ss = QTextStream(sheetfile).readAll()
			sheetfile.close()
		else:
			self.ss = ''

	def initTabWidget(self):
		def dragEnterEvent(e):
			e.acceptProposedAction()
		def dropEvent(e):
			fn = bytes(e.mimeData().data('text/plain')).decode().rstrip()
			if fn.startswith('file:'):
				fn = QUrl(fn).toLocalFile()
			self.openFileWrapper(fn)
		self.tabWidget.setTabsClosable(True)
		self.tabWidget.setAcceptDrops(True)
		self.tabWidget.dragEnterEvent = dragEnterEvent
		self.tabWidget.dropEvent = dropEvent

	def act(self, name, icon=None, trig=None, trigbool=None, shct=None):
		if not isinstance(shct, QKeySequence):
			shct = QKeySequence(shct)
		if icon:
			action = QAction(self.actIcon(icon), name, self)
		else:
			action = QAction(name, self)
		if trig:
			action.triggered.connect(trig)
		elif trigbool:
			action.setCheckable(True)
			action.triggered[bool].connect(trigbool)
		if shct:
			action.setShortcut(shct)
		return action

	def actIcon(self, name):
		return QIcon.fromTheme(name, QIcon(icon_path+name+'.png'))

	def printError(self):
		import traceback
		print('Exception occured while parsing document:', file=sys.stderr)
		traceback.print_exc()

	def getSplitter(self, index):
		splitter = QSplitter(Qt.Horizontal)
		# Give both boxes a minimum size so the minimumSizeHint will be
		# ignored when splitter.setSizes is called below
		for widget in self.editBoxes[index], self.previewBoxes[index]:
			widget.setMinimumWidth(125)
			splitter.addWidget(widget)
		splitter.setSizes((50, 50))
		splitter.setChildrenCollapsible(False)
		return splitter

	def getWebView(self):
		webView = QWebView()
		if not globalSettings.handleWebLinks:
			webView.page().setLinkDelegationPolicy(QWebPage.DelegateExternalLinks)
			webView.page().linkClicked.connect(QDesktopServices.openUrl)
		settings = webView.settings()
		settings.setAttribute(QWebSettings.LocalContentCanAccessFileUrls, False)
		settings.setDefaultTextEncoding('utf-8')
		return webView

	def createTab(self, fileName):
		self.previewBlocked = False
		self.editBoxes.append(ReTextEdit(self))
		self.highlighters.append(ReTextHighlighter(self.editBoxes[-1].document()))
		if enchant_available and self.actionEnableSC.isChecked():
			self.highlighters[-1].dictionary = \
			enchant.Dict(self.sl) if self.sl else enchant.Dict()
			self.highlighters[-1].rehighlight()
		if globalSettings.useWebKit:
			self.previewBoxes.append(self.getWebView())
		else:
			self.previewBoxes.append(QTextBrowser())
			self.previewBoxes[-1].setOpenExternalLinks(True)
		self.previewBoxes[-1].setVisible(False)
		self.fileNames.append(fileName)
		markupClass = self.getMarkupClass(fileName)
		self.markups.append(self.getMarkup(fileName))
		self.highlighters[-1].docType = (markupClass.name if markupClass else '')
		liveMode = globalSettings.restorePreviewState and globalSettings.previewState
		self.actionPreviewChecked.append(liveMode)
		self.actionLivePreviewChecked.append(liveMode)
		metrics = QFontMetrics(self.editBoxes[-1].font())
		self.editBoxes[-1].setTabStopWidth(globalSettings.tabWidth * metrics.width(' '))
		self.editBoxes[-1].textChanged.connect(self.updateLivePreviewBox)
		self.editBoxes[-1].undoAvailable.connect(self.actionUndo.setEnabled)
		self.editBoxes[-1].redoAvailable.connect(self.actionRedo.setEnabled)
		self.editBoxes[-1].copyAvailable.connect(self.enableCopy)
		self.editBoxes[-1].document().modificationChanged.connect(self.modificationChanged)
		if globalSettings.useFakeVim:
			self.installFakeVimHandler(self.editBoxes[-1])
		return self.getSplitter(-1)

	def closeTab(self, ind):
		if self.maybeSave(ind):
			if self.tabWidget.count() == 1:
				self.tabWidget.addTab(self.createTab(""), self.tr("New document"))
			if self.fileNames[ind]:
				self.fileSystemWatcher.removePath(self.fileNames[ind])
			del self.editBoxes[ind]
			del self.previewBoxes[ind]
			del self.highlighters[ind]
			del self.markups[ind]
			del self.fileNames[ind]
			del self.actionPreviewChecked[ind]
			del self.actionLivePreviewChecked[ind]
			self.tabWidget.removeTab(ind)

	def getMarkupClass(self, fileName=None):
		if fileName is None:
			fileName = self.fileNames[self.ind]
		if fileName:
			markupClass = markups.get_markup_for_file_name(
				fileName, return_class=True)
			if markupClass:
				return markupClass
		return self.defaultMarkup

	def getMarkup(self, fileName=None):
		if fileName is None:
			fileName = self.fileNames[self.ind]
		markupClass = self.getMarkupClass(fileName=fileName)
		if markupClass and markupClass.available():
			return markupClass(filename=fileName)

	def docTypeChanged(self):
		oldType = self.highlighters[self.ind].docType
		markupClass = self.getMarkupClass()
		newType = markupClass.name if markupClass else ''
		if oldType != newType:
			self.markups[self.ind] = self.getMarkup()
			self.updatePreviewBox()
			self.highlighters[self.ind].docType = newType
			self.highlighters[self.ind].rehighlight()
		dtMarkdown = (newType == DOCTYPE_MARKDOWN)
		dtMkdOrReST = (newType in (DOCTYPE_MARKDOWN, DOCTYPE_REST))
		self.tagsBox.setEnabled(dtMarkdown)
		self.symbolBox.setEnabled(dtMarkdown)
		self.actionUnderline.setEnabled(dtMarkdown)
		self.actionBold.setEnabled(dtMkdOrReST)
		self.actionItalic.setEnabled(dtMkdOrReST)
		canReload = bool(self.fileNames[self.ind]) and not self.autoSaveActive()
		self.actionSetEncoding.setEnabled(canReload)
		self.actionReload.setEnabled(canReload)

	def changeIndex(self, ind):
		if ind > -1:
			self.actionUndo.setEnabled(self.editBoxes[ind].document().isUndoAvailable())
			self.actionRedo.setEnabled(self.editBoxes[ind].document().isRedoAvailable())
			self.actionCopy.setEnabled(self.editBoxes[ind].textCursor().hasSelection())
			self.actionCut.setEnabled(self.editBoxes[ind].textCursor().hasSelection())
			self.actionPreview.setChecked(self.actionPreviewChecked[ind])
			self.actionLivePreview.setChecked(self.actionLivePreviewChecked[ind])
			self.actionTableMode.setChecked(self.editBoxes[ind].tableModeEnabled)
			self.editBar.setDisabled(self.actionPreviewChecked[ind])
		self.ind = ind
		if self.fileNames[ind]:
			self.setCurrentFile()
		else:
			self.setWindowTitle(self.tr('New document') + '[*]')
			self.docTypeChanged()
		self.modificationChanged(self.editBoxes[ind].document().isModified())
		if globalSettings.restorePreviewState:
			globalSettings.previewState = self.actionLivePreviewChecked[ind]
		if self.actionLivePreviewChecked[ind]:
			self.enableLivePreview(True)
		self.editBoxes[self.ind].setFocus(Qt.OtherFocusReason)

	def changeEditorFont(self):
		font, ok = QFontDialog.getFont(globalSettings.editorFont, self)
		if ok:
			globalSettings.editorFont = font
			for editor in self.editBoxes:
				editor.updateFont()

	def changePreviewFont(self):
		font, ok = QFontDialog.getFont(globalSettings.font, self)
		if ok:
			globalSettings.font = font
			self.updatePreviewBox()

	def preview(self, viewmode):
		self.actionPreviewChecked[self.ind] = viewmode
		if self.actionLivePreview.isChecked():
			self.actionLivePreview.setChecked(False)
			return self.enableLivePreview(False)
		self.editBar.setDisabled(viewmode)
		self.editBoxes[self.ind].setVisible(not viewmode)
		self.previewBoxes[self.ind].setVisible(viewmode)
		if viewmode:
			self.updatePreviewBox()

	def enableLivePreview(self, livemode):
		if globalSettings.restorePreviewState:
			globalSettings.previewState = livemode
		self.actionLivePreviewChecked[self.ind] = livemode
		self.actionPreviewChecked[self.ind] = livemode
		self.actionPreview.setChecked(livemode)
		self.editBar.setEnabled(True)
		self.previewBoxes[self.ind].setVisible(livemode)
		self.editBoxes[self.ind].setVisible(True)
		if livemode:
			self.updatePreviewBox()

	def enableWebKit(self, enable):
		globalSettings.useWebKit = enable
		oldind = self.ind
		self.tabWidget.clear()
		for self.ind in range(len(self.editBoxes)):
			if enable:
				self.previewBoxes[self.ind] = self.getWebView()
			else:
				self.previewBoxes[self.ind] = QTextBrowser()
				self.previewBoxes[self.ind].setOpenExternalLinks(True)
			splitter = self.getSplitter(self.ind)
			self.tabWidget.addTab(splitter, self.getDocumentTitle(baseName=True))
			self.updatePreviewBox()
			self.previewBoxes[self.ind].setVisible(self.actionPreviewChecked[self.ind])
		self.ind = oldind
		self.tabWidget.setCurrentIndex(self.ind)

	def enableCopy(self, copymode):
		self.actionCopy.setEnabled(copymode)
		self.actionCut.setEnabled(copymode)

	def enableFullScreen(self, yes):
		if yes:
			self.showFullScreen()
		else:
			self.showNormal()

	def openConfigDialog(self):
		dlg = ConfigDialog(self)
		dlg.setWindowTitle(self.tr('Preferences'))
		dlg.show()

	def installFakeVimHandler(self, editor):
		if ReTextFakeVimHandler:
			fakeVimEditor = ReTextFakeVimHandler(editor, self)
			fakeVimEditor.setSaveAction(self.actionSave)
			fakeVimEditor.setQuitAction(self.actionQuit)
			self.actionFakeVimMode.triggered.connect(fakeVimEditor.remove)

	def enableFakeVimMode(self, yes):
		globalSettings.useFakeVim = yes
		if yes:
			FakeVimMode.init(self)
			for editor in self.editBoxes:
				self.installFakeVimHandler(editor)
		else:
			FakeVimMode.exit(self)

	def enableSpellCheck(self, yes):
		if yes:
			if self.sl:
				self.setAllDictionaries(enchant.Dict(self.sl))
			else:
				self.setAllDictionaries(enchant.Dict())
		else:
			self.setAllDictionaries(None)
		globalSettings.spellCheck = yes

	def setAllDictionaries(self, dictionary):
		for hl in self.highlighters:
			hl.dictionary = dictionary
			hl.rehighlight()

	def changeLocale(self):
		if self.sl:
			localedlg = LocaleDialog(self, defaultText=self.sl)
		else:
			localedlg = LocaleDialog(self)
		if localedlg.exec() != QDialog.Accepted:
			return
		sl = localedlg.localeEdit.text()
		setdefault = localedlg.checkBox.isChecked()
		if sl:
			try:
				sl = str(sl)
				enchant.Dict(sl)
			except Exception as e:
				QMessageBox.warning(self, '', str(e))
			else:
				self.sl = sl
				self.enableSpellCheck(self.actionEnableSC.isChecked())
		else:
			self.sl = None
			self.enableSpellCheck(self.actionEnableSC.isChecked())
		if setdefault:
			globalSettings.spellCheckLocale = sl

	def searchBarVisibilityChanged(self, visible):
		self.actionSearch.setChecked(visible)
		if visible:
			self.searchEdit.setFocus(Qt.ShortcutFocusReason)

	def find(self, back=False):
		flags = QTextDocument.FindFlags()
		if back:
			flags |= QTextDocument.FindBackward
		if self.csBox.isChecked():
			flags |= QTextDocument.FindCaseSensitively
		text = self.searchEdit.text()
		editBox = self.editBoxes[self.ind]
		cursor = editBox.textCursor()
		newCursor = editBox.document().find(text, cursor, flags)
		if not newCursor.isNull():
			editBox.setTextCursor(newCursor)
			return self.setSearchEditColor(True)
		cursor.movePosition(QTextCursor.End if back else QTextCursor.Start)
		newCursor = editBox.document().find(text, cursor, flags)
		if not newCursor.isNull():
			editBox.setTextCursor(newCursor)
			return self.setSearchEditColor(True)
		self.setSearchEditColor(False)

	def setSearchEditColor(self, found):
		palette = self.searchEdit.palette()
		palette.setColor(QPalette.Active, QPalette.Base,
		                 Qt.white if found else QColor(255, 102, 102))
		self.searchEdit.setPalette(palette)

	def getHtml(self, includeStyleSheet=True, includeTitle=True,
	            includeMeta=False, webenv=False):
		if self.markups[self.ind] is None:
			markupClass = self.getMarkupClass()
			errMsg = self.tr('Could not parse file contents, check if '
			'you have the <a href="%s">necessary module</a> installed!')
			try:
				errMsg %= markupClass.attributes[MODULE_HOME_PAGE]
			except (AttributeError, KeyError):
				# Remove the link if markupClass doesn't have the needed attribute
				errMsg = errMsg.replace('<a href="%s">', '')
				errMsg = errMsg.replace('</a>', '')
			return '<p style="color: red">%s</p>' % errMsg
		text = self.editBoxes[self.ind].toPlainText()
		headers = ''
		if includeStyleSheet:
			headers += '<style type="text/css">\n' + self.ss + '</style>\n'
		cssFileName = self.getDocumentTitle(baseName=True)+'.css'
		if QFile(cssFileName).exists():
			headers += '<link rel="stylesheet" type="text/css" href="%s">\n' \
			% cssFileName
		if includeMeta:
			headers += ('<meta name="generator" content="ReText %s">\n' %
			            app_version)
		fallbackTitle = self.getDocumentTitle() if includeTitle else ''
		return self.markups[self.ind].get_whole_html(text,
			custom_headers=headers, include_stylesheet=includeStyleSheet,
			fallback_title=fallbackTitle, webenv=webenv)

	def updatePreviewBox(self):
		self.previewBlocked = False
		pb = self.previewBoxes[self.ind]
		textedit = isinstance(pb, QTextEdit)
		if textedit:
			scrollbar = pb.verticalScrollBar()
			disttobottom = scrollbar.maximum() - scrollbar.value()
		else:
			frame = pb.page().mainFrame()
			scrollpos = frame.scrollPosition()
		try:
			html = self.getHtml()
		except Exception:
			return self.printError()
		if textedit:
			pb.setHtml(html)
			pb.document().setDefaultFont(globalSettings.font)
			scrollbar.setValue(scrollbar.maximum() - disttobottom)
		else:
			pb.settings().setFontFamily(QWebSettings.StandardFont,
			                            globalSettings.font.family())
			pb.settings().setFontSize(QWebSettings.DefaultFontSize,
			                          globalSettings.font.pointSize())
			pb.setHtml(html, QUrl.fromLocalFile(self.fileNames[self.ind]))
			frame.setScrollPosition(scrollpos)

	def updateLivePreviewBox(self):
		if self.actionLivePreview.isChecked() and self.previewBlocked == False:
			self.previewBlocked = True
			QTimer.singleShot(1000, self.updatePreviewBox)

	def showInDir(self):
		if self.fileNames[self.ind]:
			path = QFileInfo(self.fileNames[self.ind]).path()
			QDesktopServices.openUrl(QUrl.fromLocalFile(path))
		else:
			QMessageBox.warning(self, '', self.tr("Please, save the file somewhere."))

	def setCurrentFile(self):
		self.setWindowTitle("")
		self.tabWidget.setTabText(self.ind, self.getDocumentTitle(baseName=True))
		self.setWindowFilePath(self.fileNames[self.ind])
		files = readListFromSettings("recentFileList")
		while self.fileNames[self.ind] in files:
			files.remove(self.fileNames[self.ind])
		files.insert(0, self.fileNames[self.ind])
		if len(files) > 10:
			del files[10:]
		writeListToSettings("recentFileList", files)
		QDir.setCurrent(QFileInfo(self.fileNames[self.ind]).dir().path())
		self.docTypeChanged()

	def createNew(self, text=None):
		self.tabWidget.addTab(self.createTab(""), self.tr("New document"))
		self.ind = self.tabWidget.count()-1
		self.tabWidget.setCurrentIndex(self.ind)
		if text:
			self.editBoxes[self.ind].textCursor().insertText(text)

	def switchTab(self, shift=1):
		self.tabWidget.setCurrentIndex((self.ind + shift) % self.tabWidget.count())

	def updateRecentFiles(self):
		self.menuRecentFiles.clear()
		self.recentFilesActions = []
		filesOld = readListFromSettings("recentFileList")
		files = []
		for f in filesOld:
			if QFile.exists(f):
				files.append(f)
				self.recentFilesActions.append(self.act(f, trig=self.openFunction(f)))
		writeListToSettings("recentFileList", files)
		for action in self.recentFilesActions:
			self.menuRecentFiles.addAction(action)

	def markupFunction(self, markup):
		return lambda: self.setDefaultMarkup(markup)

	def openFunction(self, fileName):
		return lambda: self.openFileWrapper(fileName)

	def extensionFuntion(self, data):
		return lambda: \
		self.runExtensionCommand(data['Exec'], data['FileFilter'], data['DefaultExtension'])

	def getExportExtensionsList(self):
		extensions = []
		for extsprefix in datadirs:
			extsdir = QDir(extsprefix+'/export-extensions/')
			if extsdir.exists():
				for fileInfo in extsdir.entryInfoList(['*.desktop', '*.ini'],
				QDir.Files | QDir.Readable):
					extensions.append(self.readExtension(fileInfo.filePath()))
		locale = QLocale.system().name()
		self.extensionActions = []
		for extension in extensions:
			try:
				if ('Name[%s]' % locale) in extension:
					name = extension['Name[%s]' % locale]
				elif ('Name[%s]' % locale.split('_')[0]) in extension:
					name = extension['Name[%s]' % locale.split('_')[0]]
				else:
					name = extension['Name']
				data = {}
				for prop in ('FileFilter', 'DefaultExtension', 'Exec'):
					if 'X-ReText-'+prop in extension:
						data[prop] = extension['X-ReText-'+prop]
					elif prop in extension:
						data[prop] = extension[prop]
					else:
						data[prop] = ''
				action = self.act(name, trig=self.extensionFuntion(data))
				if 'Icon' in extension:
					action.setIcon(self.actIcon(extension['Icon']))
				mimetype = extension['MimeType'] if 'MimeType' in extension else None
			except KeyError:
				print('Failed to parse extension: Name is required', file=sys.stderr)
			else:
				self.extensionActions.append((action, mimetype))

	def updateExtensionsVisibility(self):
		markupClass = self.getMarkupClass()
		for action in self.extensionActions:
			if markupClass is None:
				action[0].setEnabled(False)
				continue
			mimetype = action[1]
			if mimetype == None:
				enabled = True
			elif markupClass == markups.MarkdownMarkup:
				enabled = (mimetype in ("text/x-retext-markdown", "text/x-markdown"))
			elif markupClass == markups.ReStructuredTextMarkup:
				enabled = (mimetype in ("text/x-retext-rst", "text/x-rst"))
			else:
				enabled = False
			action[0].setEnabled(enabled)

	def readExtension(self, fileName):
		extFile = QFile(fileName)
		extFile.open(QIODevice.ReadOnly)
		extension = {}
		stream = QTextStream(extFile)
		while not stream.atEnd():
			line = stream.readLine()
			if '=' in line:
				index = line.index('=')
				extension[line[:index].rstrip()] = line[index+1:].lstrip()
		extFile.close()
		return extension

	def openFile(self):
		supportedExtensions = ['.txt']
		for markup in markups.get_all_markups():
			supportedExtensions += markup.file_extensions
		fileFilter = ' (' + str.join(' ', ['*'+ext for ext in supportedExtensions]) + ');;'
		fileNames = QFileDialog.getOpenFileNames(self,
			self.tr("Select one or several files to open"), "",
			self.tr("Supported files") + fileFilter + self.tr("All files (*)"))
		for fileName in fileNames[0]:
			self.openFileWrapper(fileName)

	def openFileWrapper(self, fileName):
		if not fileName:
			return
		fileName = QFileInfo(fileName).canonicalFilePath()
		exists = False
		for i in range(self.tabWidget.count()):
			if self.fileNames[i] == fileName:
				exists = True
				ex = i
		if exists:
			self.tabWidget.setCurrentIndex(ex)
		elif QFile.exists(fileName):
			noEmptyTab = (
				(self.ind is None) or
				self.fileNames[self.ind] or
				self.editBoxes[self.ind].toPlainText() or
				self.editBoxes[self.ind].document().isModified()
			)
			if noEmptyTab:
				self.tabWidget.addTab(self.createTab(fileName), "")
				self.ind = self.tabWidget.count()-1
				self.tabWidget.setCurrentIndex(self.ind)
			if fileName:
				self.fileSystemWatcher.addPath(fileName)
			self.fileNames[self.ind] = fileName
			self.openFileMain()

	def openFileMain(self, encoding=None):
		openfile = QFile(self.fileNames[self.ind])
		openfile.open(QIODevice.ReadOnly)
		stream = QTextStream(openfile)
		if encoding:
			stream.setCodec(encoding)
		elif globalSettings.defaultCodec:
			stream.setCodec(globalSettings.defaultCodec)
		text = stream.readAll()
		openfile.close()
		markupClass = markups.get_markup_for_file_name(
			self.fileNames[self.ind], return_class=True)
		self.highlighters[self.ind].docType = (markupClass.name if markupClass else '')
		self.markups[self.ind] = self.getMarkup()
		if self.defaultMarkup:
			self.highlighters[self.ind].docType = self.defaultMarkup.name
		editBox = self.editBoxes[self.ind]
		modified = bool(encoding) and (editBox.toPlainText() != text)
		editBox.setPlainText(text)
		self.setCurrentFile()
		editBox.document().setModified(modified)
		self.setWindowModified(modified)

	def showEncodingDialog(self):
		if not self.maybeSave(self.ind):
			return
		encoding, ok = QInputDialog.getItem(self, '',
			self.tr('Select file encoding from the list:'),
			[bytes(b).decode() for b in QTextCodec.availableCodecs()],
			0, False)
		if ok:
			self.openFileMain(encoding)

	def saveFile(self):
		self.saveFileMain(dlg=False)

	def saveFileAs(self):
		self.saveFileMain(dlg=True)

	def saveAll(self):
		oldind = self.ind
		for self.ind in range(self.tabWidget.count()):
			if self.fileNames[self.ind] and QFileInfo(self.fileNames[self.ind]).isWritable():
				self.saveFileCore(self.fileNames[self.ind])
				self.editBoxes[self.ind].document().setModified(False)
		self.ind = oldind

	def saveFileMain(self, dlg):
		if (not self.fileNames[self.ind]) or dlg:
			markupClass = self.getMarkupClass()
			if (markupClass is None) or not hasattr(markupClass, 'default_extension'):
				defaultExt = self.tr("Plain text (*.txt)")
				ext = ".txt"
			else:
				defaultExt = self.tr('%s files',
					'Example of final string: Markdown files') \
					% markupClass.name + ' (' + str.join(' ',
					('*'+extension for extension in markupClass.file_extensions)) + ')'
				if markupClass == markups.MarkdownMarkup:
					ext = globalSettings.markdownDefaultFileExtension
				elif markupClass == markups.ReStructuredTextMarkup:
					ext = globalSettings.restDefaultFileExtension
				else:
					ext = markupClass.default_extension
			newFileName = QFileDialog.getSaveFileName(self,
				self.tr("Save file"), "", defaultExt)[0]
			if newFileName:
				if not QFileInfo(newFileName).suffix():
					newFileName += ext
				if self.fileNames[self.ind]:
					self.fileSystemWatcher.removePath(self.fileNames[self.ind])
				self.fileNames[self.ind] = newFileName
				self.actionSetEncoding.setDisabled(self.autoSaveActive())
		if self.fileNames[self.ind]:
			result = self.saveFileCore(self.fileNames[self.ind])
			if result:
				self.setCurrentFile()
				self.editBoxes[self.ind].document().setModified(False)
				self.setWindowModified(False)
				return True
			else:
				QMessageBox.warning(self, '',
				self.tr("Cannot save to file because it is read-only!"))
		return False

	def saveFileCore(self, fn, addToWatcher=True):
		self.fileSystemWatcher.removePath(fn)
		savefile = QFile(fn)
		result = savefile.open(QIODevice.WriteOnly)
		if result:
			savestream = QTextStream(savefile)
			if globalSettings.defaultCodec:
				savestream.setCodec(globalSettings.defaultCodec)
			savestream << self.editBoxes[self.ind].toPlainText()
			savefile.close()
		if result and addToWatcher:
			self.fileSystemWatcher.addPath(fn)
		return result

	def saveHtml(self, fileName):
		if not QFileInfo(fileName).suffix():
			fileName += ".html"
		try:
			htmltext = self.getHtml(includeStyleSheet=False, includeMeta=True,
			webenv=True)
		except Exception:
			return self.printError()
		htmlFile = QFile(fileName)
		htmlFile.open(QIODevice.WriteOnly)
		html = QTextStream(htmlFile)
		if globalSettings.defaultCodec:
			html.setCodec(globalSettings.defaultCodec)
		html << htmltext
		htmlFile.close()

	def textDocument(self):
		td = QTextDocument()
		td.setMetaInformation(QTextDocument.DocumentTitle, self.getDocumentTitle())
		if self.ss:
			td.setDefaultStyleSheet(self.ss)
		td.setHtml(self.getHtml())
		td.setDefaultFont(globalSettings.font)
		return td

	def saveOdf(self):
		try:
			document = self.textDocument()
		except Exception:
			return self.printError()
		fileName = QFileDialog.getSaveFileName(self,
			self.tr("Export document to ODT"), "",
			self.tr("OpenDocument text files (*.odt)"))[0]
		if not QFileInfo(fileName).suffix():
			fileName += ".odt"
		writer = QTextDocumentWriter(fileName)
		writer.setFormat("odf")
		writer.write(document)

	def saveFileHtml(self):
		fileName = QFileDialog.getSaveFileName(self,
			self.tr("Save file"), "",
			self.tr("HTML files (*.html *.htm)"))[0]
		if fileName:
			self.saveHtml(fileName)

	def getDocumentForPrint(self):
		if globalSettings.useWebKit:
			return self.previewBoxes[self.ind]
		try:
			return self.textDocument()
		except Exception:
			self.printError()

	def standardPrinter(self):
		printer = QPrinter(QPrinter.HighResolution)
		printer.setDocName(self.getDocumentTitle())
		printer.setCreator('ReText %s' % app_version)
		return printer

	def savePdf(self):
		self.updatePreviewBox()
		fileName = QFileDialog.getSaveFileName(self,
			self.tr("Export document to PDF"),
			"", self.tr("PDF files (*.pdf)"))[0]
		if fileName:
			if not QFileInfo(fileName).suffix():
				fileName += ".pdf"
			printer = self.standardPrinter()
			printer.setOutputFormat(QPrinter.PdfFormat)
			printer.setOutputFileName(fileName)
			document = self.getDocumentForPrint()
			if document != None:
				document.print(printer)

	def printFile(self):
		self.updatePreviewBox()
		printer = self.standardPrinter()
		dlg = QPrintDialog(printer, self)
		dlg.setWindowTitle(self.tr("Print document"))
		if (dlg.exec() == QDialog.Accepted):
			document = self.getDocumentForPrint()
			if document != None:
				document.print(printer)

	def printPreview(self):
		document = self.getDocumentForPrint()
		if document == None:
			return
		printer = self.standardPrinter()
		preview = QPrintPreviewDialog(printer, self)
		preview.paintRequested.connect(document.print)
		preview.exec()

	def runExtensionCommand(self, command, filefilter, defaultext):
		of = ('%of' in command)
		html = ('%html' in command)
		if of:
			if defaultext and not filefilter:
				filefilter = '*'+defaultext
			fileName = QFileDialog.getSaveFileName(self,
				self.tr('Export document'), '', filefilter)[0]
			if not fileName:
				return
			if defaultext and not QFileInfo(fileName).suffix():
				fileName += defaultext
		basename = '.%s.retext-temp' % self.getDocumentTitle(baseName=True)
		if html:
			tmpname = basename+'.html'
			self.saveHtml(tmpname)
		else:
			tmpname = basename+self.getMarkupClass().default_extension
			self.saveFileCore(tmpname, addToWatcher=False)
		command = command.replace('%of', '"out'+defaultext+'"')
		command = command.replace('%html' if html else '%if', '"'+tmpname+'"')
		try:
			Popen(str(command), shell=True).wait()
		except Exception as error:
			errorstr = str(error)
			QMessageBox.warning(self, '', self.tr('Failed to execute the command:')
			+ '\n' + errorstr)
		QFile(tmpname).remove()
		if of:
			QFile('out'+defaultext).rename(fileName)

	def getDocumentTitle(self, baseName=False):
		markup = self.markups[self.ind]
		realTitle = ''
		if markup and not baseName:
			text = self.editBoxes[self.ind].toPlainText()
			try:
				realTitle = markup.get_document_title(text)
			except Exception:
				self.printError()
		if realTitle:
			return realTitle
		elif self.fileNames[self.ind]:
			fileinfo = QFileInfo(self.fileNames[self.ind])
			basename = fileinfo.completeBaseName()
			return (basename if basename else fileinfo.fileName())
		return self.tr("New document")

	def autoSaveActive(self):
		return self.autoSaveEnabled and self.fileNames[self.ind] and \
		QFileInfo(self.fileNames[self.ind]).isWritable()

	def modificationChanged(self, changed):
		if self.autoSaveActive():
			changed = False
		self.actionSave.setEnabled(changed)
		self.setWindowModified(changed)

	def clipboardDataChanged(self):
		mimeData = QApplication.instance().clipboard().mimeData()
		if mimeData is not None:
			self.actionPaste.setEnabled(mimeData.hasText())

	def insertChars(self, chars):
		tc = self.editBoxes[self.ind].textCursor()
		if tc.hasSelection():
			selection = tc.selectedText()
			if selection.startswith(chars) and selection.endswith(chars):
				if len(selection) > 2*len(chars):
					selection = selection[len(chars):-len(chars)]
					tc.insertText(selection)
			else:
				tc.insertText(chars+tc.selectedText()+chars)
		else:
			tc.insertText(chars)

	def insertTag(self, ut):
		if not ut:
			return
		if isinstance(ut, int):
			ut = self.usefulTags[ut - 1]
		arg = ' style=""' if ut == 'span' else ''
		tc = self.editBoxes[self.ind].textCursor()
		if ut == 'img':
			toinsert = ('<a href="' + tc.selectedText() +
			'" target="_blank"><img src="' + tc.selectedText() + '"/></a>')
		elif ut == 'a':
			toinsert = ('<a href="' + tc.selectedText() +
			'" target="_blank">' + tc.selectedText() + '</a>')
		else:
			toinsert = '<'+ut+arg+'>'+tc.selectedText()+'</'+ut+'>'
		tc.insertText(toinsert)
		self.tagsBox.setCurrentIndex(0)

	def insertSymbol(self, num):
		if num:
			self.editBoxes[self.ind].insertPlainText('&'+self.usefulChars[num-1]+';')
		self.symbolBox.setCurrentIndex(0)

	def fileChanged(self, fileName):
		ind = self.fileNames.index(fileName)
		self.tabWidget.setCurrentIndex(ind)
		if not QFile.exists(fileName):
			self.editBoxes[ind].document().setModified(True)
			QMessageBox.warning(self, '', self.tr(
				'This file has been deleted by other application.\n'
				'Please make sure you save the file before exit.'))
		elif not self.editBoxes[ind].document().isModified():
			# File was not modified in ReText, reload silently
			self.openFileMain()
			self.updatePreviewBox()
		else:
			text = self.tr(
				'This document has been modified by other application.\n'
				'Do you want to reload the file (this will discard all '
				'your changes)?\n')
			if self.autoSaveEnabled:
				text += self.tr(
					'If you choose to not reload the file, auto save mode will '
					'be disabled for this session to prevent data loss.')
			messageBox = QMessageBox(QMessageBox.Warning, '', text)
			reloadButton = messageBox.addButton(self.tr('Reload'), QMessageBox.YesRole)
			messageBox.addButton(QMessageBox.Cancel)
			messageBox.exec()
			if messageBox.clickedButton() is reloadButton:
				self.openFileMain()
				self.updatePreviewBox()
			else:
				self.autoSaveEnabled = False
				self.editBoxes[ind].document().setModified(True)
		if fileName not in self.fileSystemWatcher.files():
			# https://github.com/retext-project/retext/issues/137
			self.fileSystemWatcher.addPath(fileName)

	def maybeSave(self, ind):
		if self.autoSaveActive():
			self.saveFileCore(self.fileNames[self.ind])
			return True
		if not self.editBoxes[ind].document().isModified():
			return True
		self.tabWidget.setCurrentIndex(ind)
		ret = QMessageBox.warning(self, '',
			self.tr("The document has been modified.\nDo you want to save your changes?"),
			QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel)
		if ret == QMessageBox.Save:
			return self.saveFileMain(False)
		elif ret == QMessageBox.Cancel:
			return False
		return True

	def closeEvent(self, closeevent):
		for self.ind in range(self.tabWidget.count()):
			if not self.maybeSave(self.ind):
				return closeevent.ignore()
		if globalSettings.saveWindowGeometry and not self.isMaximized():
			globalSettings.windowGeometry = self.saveGeometry()
		closeevent.accept()

	def viewHtml(self):
		htmlDlg = HtmlDialog(self)
		try:
			htmltext = self.getHtml(includeStyleSheet=False, includeTitle=False)
		except Exception:
			return self.printError()
		winTitle = self.getDocumentTitle(baseName=True)
		htmlDlg.setWindowTitle(winTitle+" ("+self.tr("HTML code")+")")
		htmlDlg.textEdit.setPlainText(htmltext.rstrip())
		htmlDlg.hl.rehighlight()
		htmlDlg.show()
		htmlDlg.raise_()
		htmlDlg.activateWindow()

	def openHelp(self):
		QDesktopServices.openUrl(QUrl('https://github.com/retext-project/retext/wiki'))

	def aboutDialog(self):
		QMessageBox.about(self, self.aboutWindowTitle,
		'<p><b>' + (self.tr('ReText %s (using PyMarkups %s)') % (app_version, markups.__version__))
		+'</b></p>' + self.tr('Simple but powerful editor'
		' for Markdown and reStructuredText')
		+'</p><p>'+self.tr('Author: Dmitry Shachnev, 2011').replace('2011', '2011\u2013' '2015')
		+'<br><a href="https://github.com/retext-project/retext">'+self.tr('Website')
		+'</a> | <a href="http://daringfireball.net/projects/markdown/syntax">'
		+self.tr('Markdown syntax')
		+'</a> | <a href="http://docutils.sourceforge.net/docs/user/rst/quickref.html">'
		+self.tr('reStructuredText syntax')+'</a></p>')

	def setDefaultMarkup(self, markup):
		self.defaultMarkup = markup
		defaultName = markups.get_available_markups()[0].name
		writeToSettings('defaultMarkup', markup.name, defaultName)
		oldind = self.ind
		for self.ind in range(len(self.previewBoxes)):
			self.docTypeChanged()
		self.ind = oldind
コード例 #36
0
class CueSettings(QDialog):

    on_apply = QtCore.pyqtSignal(dict)

    def __init__(self, cue=None, cue_class=None, **kwargs):
        """

        :param cue: Target cue, or None for multi-editing
        :param cue_class: when cue is None, used to specify the reference class
        """
        super().__init__(**kwargs)

        if cue is not None:
            cue_class = cue.__class__
            cue_properties = deepcopy(cue.properties())
            self.setWindowTitle(cue_properties['name'])
        else:
            cue_properties = {}
            if cue_class is None:
                cue_class = Cue

        self.setWindowModality(QtCore.Qt.ApplicationModal)
        self.setMaximumSize(635, 530)
        self.setMinimumSize(635, 530)
        self.resize(635, 530)

        self.sections = QTabWidget(self)
        self.sections.setGeometry(QtCore.QRect(5, 10, 625, 470))

        for widget in sorted(CueSettingsRegistry().filter(cue_class), key=lambda w: w.Name):
            if issubclass(widget, CueSettingsPage):
                settings_widget = widget(cue_class)
            else:
                settings_widget = widget()

            settings_widget.load_settings(cue_properties)
            settings_widget.enable_check(cue is None)
            self.sections.addTab(settings_widget, settings_widget.Name)

        self.dialogButtons = QDialogButtonBox(self)
        self.dialogButtons.setGeometry(10, 490, 615, 30)
        self.dialogButtons.setStandardButtons(QDialogButtonBox.Cancel |
                                              QDialogButtonBox.Ok |
                                              QDialogButtonBox.Apply)

        self.dialogButtons.rejected.connect(self.reject)
        self.dialogButtons.accepted.connect(self.accept)
        apply = self.dialogButtons.button(QDialogButtonBox.Apply)
        apply.clicked.connect(self.apply)

    def accept(self):
        self.apply()
        super().accept()

    def apply(self):
        settings = {}

        for n in range(self.sections.count()):
            deep_update(settings, self.sections.widget(n).get_settings())

        self.on_apply.emit(settings)
コード例 #37
0
ファイル: run_widget.py プロジェクト: ninja-ide/ninja-ide
class RunWidget(QWidget):

    allTabsClosed = pyqtSignal()
    projectExecuted = pyqtSignal(str)
    fileExecuted = pyqtSignal(str)

    def __init__(self):
        QWidget.__init__(self)
        self.__programs = []

        vbox = QVBoxLayout(self)
        vbox.setContentsMargins(0, 0, 0, 0)
        vbox.setSpacing(0)

        connections = (
            {
                "target": "tools_dock",
                "signal_name": "executeFile",
                "slot": self.execute_file
            },
            {
                "target": "tools_dock",
                "signal_name": "executeProject",
                "slot": self.execute_project
            },
            {
                "target": "tools_dock",
                "signal_name": "executeSelection",
                "slot": self.execute_selection
            },
            {
                "target": "tools_dock",
                "signal_name": "stopApplication",
                "slot": self.kill_application
            }
        )
        IDE.register_signals("tools_dock", connections)

        self._tabs = QTabWidget()
        self._tabs.setTabsClosable(True)
        self._tabs.setMovable(True)
        self._tabs.setDocumentMode(True)
        vbox.addWidget(self._tabs)
        # Menu for tab
        self._tabs.tabBar().setContextMenuPolicy(Qt.CustomContextMenu)
        self._tabs.tabBar().customContextMenuRequested.connect(
            self._menu_for_tabbar)
        self._tabs.tabCloseRequested.connect(self.close_tab)

        IDE.register_service("run_widget", self)
        _ToolsDock.register_widget(translations.TR_OUTPUT, self)

    def install(self):
        ninjaide = IDE.get_service("ide")
        ninjaide.goingDown.connect(self._kill_processes)

    def _kill_processes(self):
        """Stop all applications"""
        for program in self.__programs:
            program.kill()

    def kill_application(self):
        """Stop application by current tab index"""
        index = self._tabs.currentIndex()
        if index == -1:
            return
        program = self.__programs[index]
        program.kill()

    def _menu_for_tabbar(self, position):
        menu = QMenu()
        close_action = menu.addAction(translations.TR_CLOSE_TAB)
        close_all_action = menu.addAction(translations.TR_CLOSE_ALL_TABS)
        close_other_action = menu.addAction(translations.TR_CLOSE_OTHER_TABS)

        qaction = menu.exec_(self.mapToGlobal(position))

        if qaction == close_action:
            index = self._tabs.tabBar().tabAt(position)
            self.close_tab(index)
        elif qaction == close_all_action:
            self.close_all_tabs()
        elif qaction == close_other_action:
            self.close_all_tabs_except_this()

    def close_tab(self, tab_index):
        program = self.__programs[tab_index]
        self.__programs.remove(program)
        self._tabs.removeTab(tab_index)
        # Close process and delete OutputWidget
        program.main_process.close()
        program.outputw.deleteLater()
        del program.outputw

        if self._tabs.count() == 0:
            # Hide widget
            tools = IDE.get_service("tools_dock")
            tools.hide_widget(self)

    def close_all_tabs(self):
        for _ in range(self._tabs.count()):
            self.close_tab(0)

    def close_all_tabs_except_this(self):
        self._tabs.tabBar().moveTab(self._tabs.currentIndex(), 0)
        for _ in range(self._tabs.count()):
            if self._tabs.count() > 1:
                self.close_tab(1)

    def execute_file(self):
        """Execute the current file"""
        main_container = IDE.get_service("main_container")
        editor_widget = main_container.get_current_editor()
        if editor_widget is not None and (editor_widget.is_modified or
                                          editor_widget.file_path):
            main_container.save_file(editor_widget)
            file_path = editor_widget.file_path
            if file_path is None:
                return
            # Emit signal for plugin!
            self.fileExecuted.emit(editor_widget.file_path)
            extension = file_manager.get_file_extension(file_path)
            # TODO: Remove the IF statment and use Handlers
            if extension == "py":
                self.start_process(filename=file_path)

    def execute_selection(self):
        """Execute selected text or current line if not have a selection"""

        main_container = IDE.get_service("main_container")
        editor_widget = main_container.get_current_editor()
        if editor_widget is not None:
            text = editor_widget.selected_text().splitlines()
            if not text:
                # Execute current line
                text = [editor_widget.line_text()]
            code = []
            for line_text in text:
                # Get part before firs '#'
                code.append(line_text.split("#", 1)[0])
            # Join to execute with python -c command
            final_code = ";".join([line.strip() for line in code if line])
            # Highlight code to be executed
            editor_widget.show_run_cursor()
            # Ok run!
            self.start_process(
                filename=editor_widget.file_path, code=final_code)

    def execute_project(self):
        """Execute the project marked as Main Project."""

        projects_explorer = IDE.get_service("projects_explorer")
        if projects_explorer is None:
            return
        nproject = projects_explorer.current_project
        if nproject:
            main_file = nproject.main_file
            if not main_file:
                # Open project properties to specify the main file
                projects_explorer.current_tree.open_project_properties()
            else:
                # Save project files
                projects_explorer.save_project()
                # Emit a signal for plugin!
                self.projectExecuted.emit(nproject.path)

                main_file = file_manager.create_path(
                    nproject.path, nproject.main_file)
                self.start_process(
                    filename=main_file,
                    python_exec=nproject.python_exec,
                    pre_exec_script=nproject.pre_exec_script,
                    post_exec_script=nproject.post_exec_script,
                    program_params=nproject.program_params
                )

    def start_process(self, **kwargs):
        # First look if we can reuse a tab
        fname = kwargs.get("filename")
        program = None
        for prog in self.__programs:
            if prog.filename == fname:
                if not prog.is_running():
                    program = prog
                    break

        if program is not None:
            index = self.__programs.index(program)
            program.update(**kwargs)
            self._tabs.setCurrentIndex(index)
            program.outputw.gray_out_old_text()
        else:
            program = Program(**kwargs)
            # Create new output widget
            outputw = OutputWidget(self)
            program.set_output_widget(outputw)
            self.add_tab(outputw, program.display_name())
            self.__programs.append(program)

        program.start()

    def add_tab(self, outputw, tab_text):
        inserted_index = self._tabs.addTab(outputw, tab_text)
        self._tabs.setCurrentIndex(inserted_index)
コード例 #38
0
ファイル: dialog.py プロジェクト: 19joho66/frescobaldi
class ScoreWizardDialog(QDialog):

    pitchLanguageChanged = pyqtSignal(str)

    def __init__(self, mainwindow):
        super(ScoreWizardDialog, self).__init__(mainwindow)
        self.addAction(mainwindow.actionCollection.help_whatsthis)
        self._pitchLanguage = None

        layout = QVBoxLayout()
        self.setLayout(layout)

        self.tabs = QTabWidget()
        b = self.dialogButtons = QDialogButtonBox()
        b.setStandardButtons(
            QDialogButtonBox.Reset
            | QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        b.accepted.connect(self.accept)
        b.rejected.connect(self.reject)
        userguide.addButton(b, "scorewiz")
        b.button(QDialogButtonBox.Reset).clicked.connect(self.reset)
        self.previewButton = b.addButton('', QDialogButtonBox.ActionRole)
        self.previewButton.clicked.connect(self.showPreview)
        layout.addWidget(self.tabs)
        layout.addWidget(b)

        self.header = Header(self)
        self.tabs.addTab(self.header, '')
        self.parts = Parts(self)
        self.tabs.addTab(self.parts, '')
        self.settings = Settings(self)
        self.tabs.addTab(self.settings, '')

        self.tabs.setCurrentIndex(0)
        self.tabs.widget(0).widget() # activate it
        self.tabs.currentChanged.connect(self.slotCurrentChanged)
        qutil.saveDialogSize(self, "scorewiz/dialog/size")
        app.translateUI(self)
        self.accepted.connect(self.slotAccepted)

    def translateUI(self):
        self.setWindowTitle(app.caption(_("Score Setup Wizard")))
        for i in range(self.tabs.count()):
            self.tabs.setTabText(i, self.tabs.widget(i).title())
        self.dialogButtons.button(QDialogButtonBox.Reset).setText(_("Clear"))
        self.dialogButtons.button(QDialogButtonBox.Reset).setToolTip(_(
            "Clears the current page of the Score Wizard."))
        self.previewButton.setText(_("Preview"))

    def slotCurrentChanged(self, i):
        """Lazy-loads the tab's page if shown for the first time."""
        self.tabs.widget(i).widget()

    def reset(self):
        self.tabs.currentWidget().widget().clear()

    def setPitchLanguage(self, language):
        if language != self._pitchLanguage:
            self._pitchLanguage = language
            self.pitchLanguageChanged.emit(language)

    def pitchLanguage(self):
        if self._pitchLanguage is None:
            # load setting; saving occurs in .settings.py
            lang = QSettings().value('scorewiz/lilypond/pitch_language', '', str)
            from .scoreproperties import keyNames
            if lang not in keyNames:
                lang = ''
            self._pitchLanguage = lang
        return self._pitchLanguage

    def slotAccepted(self):
        """Makes the score and puts it in the editor."""
        from . import build
        builder = build.Builder(self)       # get the builder
        text = builder.text()               # get the source text
        lydoc = ly.document.Document(text)  # temporarily store it in a lydoc
        cursor = ly.document.Cursor(lydoc)  # make a cursor selecting it
        indent.indenter().indent(cursor)    # indent it according to user prefs
        doc = app.openUrl(QUrl())           # get a new Frescobaldi document
        doc.setPlainText(lydoc.plaintext()) # write the text in it
        doc.setModified(False)              # make it "not modified"
        self.parent().setCurrentDocument(doc)

    def showPreview(self):
        """Shows a preview."""
        # get the document and fill in some example music
        from . import preview, build
        builder = build.Builder(self)
        doc = builder.document()
        preview.examplify(doc)
        # preview it
        import musicpreview
        dlg = musicpreview.MusicPreviewDialog(self)
        dlg.preview(builder.text(doc), _("Score Preview"))
        dlg.exec_()
        dlg.cleanup()
コード例 #39
0
ファイル: settings_dialog.py プロジェクト: ismlsmile/nimbus
class SettingsDialog(QDialog):
    def __init__(self, parent=None):
        super(SettingsDialog, self).__init__(parent)

        # Set layout.
        _layout = QVBoxLayout(self)
        _layout.setContentsMargins(0,0,0,0)
        self.setLayout(_layout)

        # Set window title.
        self.setWindowTitle(tr("Settings"))

        # Tab widget
        self.tabs = QTabWidget(self)
        self.layout().addWidget(self.tabs)

        self.tabs.addTab(GeneralSettingsPanel(self), tr("&General"))
        self.tabs.addTab(ContentSettingsPanel(self), tr("Con&tent"))
        self.tabs.addTab(AdremoverSettingsPanel(self), tr("Ad &Remover"))
        self.tabs.addTab(DataSettingsPanel(self), tr("&Data && Privacy"))
        self.tabs.addTab(NetworkSettingsPanel(self), tr("N&etwork"))
        self.tabs.addTab(ExtensionsSettingsPanel(self), tr("E&xtensions"))

        # Toolbar
        self.toolBar = QToolBar(self)
        self.toolBar.setMovable(False)
        self.toolBar.setContextMenuPolicy(Qt.CustomContextMenu)
        self.toolBar.setStyleSheet(common.blank_toolbar)
        self.layout().addWidget(self.toolBar)

        # Apply button
        applyButton = QPushButton(tr("&Apply"), self)
        applyButton.clicked.connect(self.saveSettings)
        self.toolBar.addWidget(applyButton)

        # Reload settings button
        closeButton = QPushButton(tr("&Close"), self)
        closeButton.clicked.connect(self.hide)
        self.toolBar.addWidget(closeButton)

        # Load settings
        self.loadSettings()

    def show(self):
        super(SettingsDialog, self).show()
        self.loadSettings()

    def url(self):
        return QUrl("")

    def icon(self):
        return common.complete_icon("preferences-system")

    # Method to load all settings.
    def loadSettings(self):
        for index in range(0, self.tabs.count()):
            self.tabs.widget(index).loadSettings()
    
    # Method to save all settings.
    def saveSettings(self):
        for index in range(0, self.tabs.count()):
            self.tabs.widget(index).saveSettings()
        settings.reset_extensions()
        settings.reload_userscripts()
        for window in browser.windows:
            try: window.reloadExtensions()
            except: pass
            try: window.applySettings()
            except: pass
コード例 #40
0
class ObserverWindow(QMainWindow):

    messageReceived = pyqtSignal(str, str, str, str, str)
    newFilterSettingsApplied = pyqtSignal(str)
    resetDisplays = pyqtSignal()

    #__________________________________________________________________
    def __init__(self, client, logger):

        super(ObserverWindow, self).__init__()

        self._connectionState = None

        self._countUntitledDisplay = 0
        self._displays = []
        self._session = 'Default session'
        self._host = 'localhost'
        self._port = 1883
        self._rootTopic = ''
        self._logger = logger

        self._logger.info(self.tr("Started"))

        reg = QSettings()

        if "current session" in reg.childKeys() and reg.value(
                "current session", '').strip() and reg.value(
                    "current session", '').strip() in reg.childGroups():
            self._session = reg.value("current session")

        self._logger.info(self.tr("Current session : ") + self._session)

        if self._session not in reg.childGroups():
            reg.beginGroup(self._session)
            reg.setValue("host", self._host)
            reg.setValue("port", self._port)
            reg.setValue("root topic", self._rootTopic)
            reg.endGroup()
        else:
            reg.beginGroup(self._session)
            self._host = reg.value("host", 'localhost')
            try:
                self._port = reg.value("port", 1883, type=int)
            except:
                pass
            self._rootTopic = reg.value("root topic", '')
            reg.endGroup()

        if "current session" in reg.childKeys() and not reg.value(
                "current session", '') in reg.childGroups():
            reg.remove("current session")

        self._mqttSwitchingConnection = False

        self._mqttClient = client
        self._mqttServerHost = self._host
        self._mqttServerPort = self._port
        self._mqttRootTopic = self._rootTopic
        self._mqttSubTopic = '#'

        if self._rootTopic:
            self._mqttSubTopic = self._rootTopic + '/#'

        QApplication.desktop().screenCountChanged.connect(self.restoreWindow)
        QApplication.desktop().resized.connect(self.restoreWindow)

        self.setWindowTitle(self._session)
        self.setWindowIcon(QIcon(':/view-eye.svg'))

        self._tabWidget = QTabWidget()
        self._cloudLabel = QLabel()
        self._connectionStateLabel = QLabel()

        self.builUi()

        reg.beginGroup(self._session)
        inbox = reg.value("param inbox", 'inbox')
        outbox = reg.value("param outbox", 'outbox')
        regexInbox = reg.value("regex inbox",
                               r'^%ROOT%/(?P<correspondent>.+)/%INBOX%$')
        regexOutbox = reg.value("regex outbox",
                                r'^%ROOT%/(?P<correspondent>.+)/%OUTBOX%$')
        regexDefault = reg.value("regex default",
                                 r'.*/(?P<correspondent>[^/]+)/[^/]+$')
        reg.endGroup()

        regexInbox = regexInbox.replace("%ROOT%", self._rootTopic).replace(
            "%INBOX%", inbox)
        regexOutbox = regexOutbox.replace("%ROOT%", self._rootTopic).replace(
            "%OUTBOX%", outbox)

        self._topicRegexInbox = None
        try:
            self._topicRegexInbox = re.compile(regexInbox)
        except Exception as e:
            self._logger.error(self.tr("Failed to compile inbox regex"))
            self._logger.debug(e)

        self._topicRegexOutbox = None
        try:
            self._topicRegexOutbox = re.compile(regexOutbox)
        except Exception as e:
            self._logger.error(self.tr("Failed to compile outbox regex"))
            self._logger.debug(e)

        self._topicRegexDefault = None
        try:
            self._topicRegexDefault = re.compile(regexDefault)
        except Exception as e:
            self._logger.error(
                self.tr("Failed to compile topic default regex"))
            self._logger.debug(e)

        self.addDisplay(self.tr("All messsages"))

        reg.beginGroup(self._session)
        for i in reg.childGroups():
            self.addDisplay(i)
        reg.endGroup()

        self.changeConnectionState(ConnectionState.DISCONNECTED)

        self._logger.info("{0} : {1}".format(self.tr("MQTT server host"),
                                             self._mqttServerHost))
        self._logger.info("{0} : {1}".format(self.tr("MQTT server port"),
                                             self._mqttServerPort))
        self._logger.info("{0} : {1}".format(
            self.tr("MQTT clientid"),
            self._mqttClient._client_id.decode("latin1")))

        Timer(0, self.layoutLoadSettings).start()
        Timer(0, self.start).start()

    #__________________________________________________________________
    @pyqtSlot()
    def addDisplay(self, title=None):

        if not title:
            if self._countUntitledDisplay:
                title = "{0} ({1})".format(self.tr("New observation"),
                                           self._countUntitledDisplay)
            else:
                title = self.tr("New observation")
            self._countUntitledDisplay = self._countUntitledDisplay + 1
            reg = QSettings()
            reg.beginGroup(self._session)
            if title not in reg.childGroups():
                reg.beginGroup(title)
                reg.setValue("display",
                             int(TopicDisplay.EMPHASIZEDCORRESPONDENT))
                reg.endGroup()
            reg.endGroup()
            reg.sync()

        root_observation = not len(self._displays)

        new_display = ObserverDisplayWidget(title,
                                            self._logger,
                                            self._session,
                                            self._mqttServerHost,
                                            self._mqttServerPort,
                                            self._mqttRootTopic,
                                            remove=not root_observation,
                                            filter=not root_observation)

        new_display.addObservation.connect(self.addDisplay)
        new_display.delObservation.connect(self.removeCurrentDisplay)
        self.newFilterSettingsApplied.connect(new_display.applyFilterSettings)

        self._displays.append(new_display)
        self._tabWidget.addTab(new_display, title)

        self.resetDisplays.connect(new_display.reset)
        self.messageReceived.connect(new_display.processMessage)
        new_display.newFilterSettings.connect(self.applyFilterSettings)
        new_display.resetWills.connect(self.applyResetWills)

        self._tabWidget.setCurrentWidget(new_display)

        self._logger.info("{0} : {1}".format(self.tr("Added observation"),
                                             title))

        dspmsg = ''
        for d in self._displays:
            if dspmsg:
                dspmsg += ' | '
            else:
                dspmsg = 'Displays : '
            dspmsg += d.title()
        self._logger.debug(dspmsg)

    #__________________________________________________________________
    @pyqtSlot(dict)
    def applyFilterSettings(self, filter):

        try:
            display = None
            for d in self._displays:
                if d.title() == filter["observation"]:
                    display = d

            if not display:
                self._logger.error(
                    self.tr("Observation not found in displays : ") +
                    filter["observation"])
            else:

                if filter["name"] != filter["observation"]:
                    for d in self._displays:
                        if d.title() == filter["name"]:
                            self._logger.warning(
                                self.tr("Can't rename observation '") +
                                filter["observation"] + self.tr("' : '") +
                                filter["name"] + self.tr("' already exists"))
                            msgbox = QMessageBox()
                            msgbox.setWindowTitle(self.tr("Observer"))
                            msgbox.setWindowIcon(
                                QIcon(':/magnifier-black.svg'))
                            msgbox.setText(
                                self.tr("Ignore apply filter !") +
                                "<br><br><i>" + self.
                                tr("Can't rename observation (name already in use)."
                                   ) + "</i><br>")
                            msgbox.setStandardButtons(QMessageBox.Close)
                            msgbox.setAttribute(Qt.WA_DeleteOnClose)
                            msgbox.setWindowFlags(
                                msgbox.windowFlags()
                                & ~Qt.WindowContextHelpButtonHint)
                            msgbox.button(QMessageBox.Close).setText(
                                self.tr("Close"))
                            msgbox.move(self.pos() + QPoint(40, 40))
                            msgbox.exec()
                            return
                    display.setTitle(filter["name"])
                    self._tabWidget.setTabText(self._tabWidget.currentIndex(),
                                               filter["name"])
                    reg = QSettings()
                    reg.beginGroup(self._session)
                    reg.remove(filter["observation"])
                    reg.endGroup()

                reg = QSettings()
                reg.beginGroup(self._session)
                reg.beginGroup(filter["name"])
                reg.setValue("display", int(filter["display"]))
                reg.setValue("filter 1", filter["filter 1"])
                reg.setValue("filter 2", filter["filter 2"])
                reg.setValue("filter 3", filter["filter 3"])
                reg.setValue("filter 4", filter["filter 4"])
                reg.setValue("buffer size", filter["buffer size"])
                reg.remove("Hidden correspondents")
                reg.beginGroup("Hidden correspondents")
                for p in filter["hidden correspondents"]:
                    reg.setValue(p.replace('/', '\\'), '')
                reg.endGroup()
                reg.remove("Hidden topics")
                reg.beginGroup("Hidden topics")
                for t in filter["hidden topics"]:
                    reg.setValue(t.replace('/', '\\'), '')
                reg.endGroup()
                reg.endGroup()
                reg.endGroup()
                reg.sync()

                self.newFilterSettingsApplied.emit(filter["name"])

        except Exception as e:
            self._logger.error("Failed to apply filter settings")
            self._logger.debug(e)

    #__________________________________________________________________
    @pyqtSlot(list)
    def applyResetWills(self, topics):

        for topic in topics:
            if self._connectionState == ConnectionState.CONNECTED:
                try:
                    (result, mid) = self._mqttClient.publish(topic,
                                                             '',
                                                             qos=0,
                                                             retain=True)
                    self._logger.info("{0} {1} (mid={2})".format(
                        self.tr("MQTT sending '' to clear will for "), topic,
                        mid))
                except Exception as e:
                    self._logger.info("{0} {1} (mid={2})".format(
                        self.tr("MQTT failed to send '' to clear will for "),
                        topic, mid))
                    self._logger.debug(e)
            else:
                self._logger.info("{0} {1}".format(
                    self.tr("MQTT failed to reset will (disconnected) for "),
                    topic))

    #__________________________________________________________________
    def builUi(self):

        mw = QWidget()
        self.setCentralWidget(mw)

        main_layout = QVBoxLayout(mw)
        main_layout.setSpacing(12)

        cloud_image = QLabel()
        cloud_image.setPixmap(QIcon(":/cloud-data.svg").pixmap(QSize(36, 36)))
        cloud_image.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)

        cloud = self._mqttServerHost + ':' + str(self._mqttServerPort)

        if self._mqttRootTopic:
            cloud += '/' + self._mqttRootTopic + '/#'
        else:
            cloud += '/#'

        self._cloudLabel.setText(cloud)
        font = self._cloudLabel.font()
        font.setPixelSize(12)
        font.setBold(True)
        self._cloudLabel.setFont(font)

        settings_button = QPushButton()
        settings_button.setIcon(QIcon(":/settings.svg"))
        settings_button.setFlat(True)
        settings_button.setToolTip(self.tr("Settings"))
        settings_button.setIconSize(QSize(16, 16))
        settings_button.setFixedSize(QSize(24, 24))
        settings_button.setStyleSheet("QPushButton { padding-bottom: 4px }")

        self._connectionStateLabel = QLabel()
        self._connectionStateLabel.setPixmap(
            QIcon(":/led-circle-grey.svg").pixmap(QSize(24, 24)))
        self._connectionStateLabel.setSizePolicy(QSizePolicy.Fixed,
                                                 QSizePolicy.Fixed)

        header_layout = QHBoxLayout()
        header_layout.addWidget(cloud_image)
        header_layout.addWidget(self._cloudLabel)
        header_layout.addStretch()
        header_layout.addWidget(settings_button)
        header_layout.addWidget(self._connectionStateLabel)
        main_layout.addLayout(header_layout)

        main_layout.addWidget(self._tabWidget)

        settings_button.pressed.connect(self.settings)

    #__________________________________________________________________
    def changeConnectionState(self, state):

        self._connectionState = state

        if state == ConnectionState.CONNECTED:
            self._connectionStateLabel.setPixmap(
                QIcon(":/led-circle-green.svg").pixmap(QSize(24, 24)))
            self._connectionStateLabel.setToolTip(self.tr("Connected"))
        elif state == ConnectionState.CONNECTING:
            self._connectionStateLabel.setPixmap(
                QIcon(":/led-circle-yellow.svg").pixmap(QSize(24, 24)))
            self._connectionStateLabel.setToolTip(self.tr("Connecting"))
        elif state == ConnectionState.DISCONNECTED:
            self._connectionStateLabel.setPixmap(
                QIcon(":/led-circle-red.svg").pixmap(QSize(24, 24)))
            self._connectionStateLabel.setToolTip(self.tr("Disconnected"))
        else:
            self._connectionStateLabel.setPixmap(
                QIcon(":/led-circle-grey.svg").pixmap(QSize(24, 24)))
            self._connectionStateLabel.setToolTip("")

    #__________________________________________________________________
    def closeEvent(self, event):

        self._logger.info(self.tr("Done"))

    #__________________________________________________________________
    def layoutLoadSettings(self):

        reg = QSettings()
        pos = reg.value("position", QPoint(200, 200))
        size = reg.value("size", QSize(400, 400))

        self.move(pos)
        self.resize(size)

    #__________________________________________________________________
    def layoutSaveSettings(self):

        reg = QSettings()
        reg.setValue("position", self.pos())
        reg.setValue("size", self.size())
        reg.sync()

    #__________________________________________________________________
    def moveEvent(self, event):

        if self.isVisible():
            Timer(0, self.layoutSaveSettings).start()

    #__________________________________________________________________
    def mqttConnect(self):

        self._logger.info(self.tr("May connect to MQTT server..."))

        if self._mqttSwitchingConnection and self._connectionState == ConnectionState.DISCONNECTED:
            self._mqttServerHost = self._host
            self._mqttServerPort = self._port
            self._mqttRootTopic = self._rootTopic

            if self._rootTopic:
                self._mqttSubTopic = self._rootTopic + '/#'
            else:
                self._mqttSubTopic = '#'

            cloud = self._mqttServerHost + ':' + str(self._mqttServerPort)

            if self._mqttRootTopic:
                cloud += '/' + self._mqttRootTopic + '/#'
            else:
                cloud += '/#'

            self._cloudLabel.setText(cloud)

            clientid = "Observer/" + QUuid.createUuid().toString()
            self._logger.debug("MQTT clientid %s", clientid)

            self._mqttClient.reinitialise(client_id=clientid,
                                          clean_session=True,
                                          userdata=None)

            self._logger.info(self.tr("MQTT client reinitialised"))
            self._logger.info("{0} : {1}".format(self.tr("MQTT server host"),
                                                 self._mqttServerHost))
            self._logger.info("{0} : {1}".format(self.tr("MQTT server port"),
                                                 self._mqttServerPort))
            self._logger.info("{0} : {1}".format(
                self.tr("MQTT clientid"),
                self._mqttClient._client_id.decode("latin1")))
            self._mqttClient.on_connect = self.mqttOnConnect
            self._mqttClient.on_disconnect = self.mqttOnDisconnect
            self._mqttClient.on_log = self.mqttOnLog
            self._mqttClient.on_message = self.mqttOnMessage
            self._mqttClient.on_publish = self.mqttOnPublish
            self._mqttClient.on_subscribe = self.mqttOnSubscribe
            self._mqttClient.on_unsubscribe = self.mqttOnUnsubscribe

            self._mqttSwitchingConnection = False
            self._mqttClient.loop_start()

        if self._connectionState == ConnectionState.CONNECTED or self._connectionState == ConnectionState.CONNECTING:
            self._logger.info(
                self.tr("MQTT connect ignored (already ongoing)"))
        else:
            self._logger.info(self.tr("Connect to MQTT server"))
            try:
                self._mqttClient.connect(self._mqttServerHost,
                                         port=self._mqttServerPort,
                                         keepalive=MQTT_KEEPALIVE)
                self.changeConnectionState(ConnectionState.CONNECTING)
                self._logger.info(self.tr("MQTT connecting"))
            except Exception as e:
                self.changeConnectionState(ConnectionState.DISCONNECTED)
                self._logger.warning(
                    self.tr("Failed to connect to MQTT server"))
                self._logger.debug(e)
                Timer(15.000, self.mqttConnect).start()

        self._logger.debug("Connection state = " + str(self._connectionState))

    #__________________________________________________________________
    def mqttDisconnect(self):

        try:
            self._mqttClient.disconnect()
        except Exception as e:
            self._logger.error(self.tr("MQTT disconnection call failed"))
            self._logger.debug(e)

    #__________________________________________________________________
    def mqttOnConnect(self, client, userdata, flags, rc):

        self._logger.debug("Connected to MQTT server with result code: " +
                           str(rc) + " and flags: ", flags)  # flags is dict

        if rc == 0:
            self._logger.info(self.tr("MQTT connected"))
            self.changeConnectionState(ConnectionState.CONNECTED)
            mydata = {
                'host': self._mqttServerHost,
                'port': self._mqttServerPort
            }
            self._mqttClient.user_data_set(str(mydata))
            try:
                (result, mid) = self._mqttClient.subscribe(self._mqttSubTopic)
                self._logger.info("{0} {1} : {2}".format(
                    self.tr("MQTT subscribing to"), mid, self._mqttSubTopic))
            except Exception as e:
                self._logger.error(self.tr("MQTT subscribe call failed"))
                self._logger.debug(e)
        elif rc == 1:
            self._logger.warning(
                self.
                tr("MQTT failed to connect : connection refused - incorrect protocol version"
                   ))
        elif rc == 2:
            self._logger.warning(
                self.
                tr("MQTT failed to connect : connection refused - invalid client identifier"
                   ))
        elif rc == 3:
            self._logger.warning(
                self.
                tr("MQTT failed to connect : connection refused - server unavailable"
                   ))
        elif rc == 4:
            self._logger.warning(
                self.
                tr("MQTT failed to connect : connection refused - bad username or password"
                   ))
        elif rc == 5:
            self._logger.warning(
                self.
                tr("MQTT failed to connect : connection refused - not authorised"
                   ))
        else:
            self._logger.warning("{0} : {1}".format(
                self.tr("MQTT failed to connect : return code"), rc))

        self._logger.debug("Connection state = " + str(self._connectionState))

    #__________________________________________________________________
    def mqttOnDisconnect(self, client, userdata, rc):

        self.changeConnectionState(ConnectionState.DISCONNECTED)

        if self._mqttSwitchingConnection:
            self._logger.info(
                self.tr(
                    "Disconnected from MQTT server (switching connection)"))
            Timer(0, self.mqttConnect).start()
            return
        else:
            self._logger.info(self.tr("Disconnected from MQTT server"))

        serv = ''
        if isinstance(userdata, str):
            try:
                mydata = eval(userdata)
                if isinstance(mydata,
                              dict) and 'host' in mydata and 'port' in mydata:
                    serv = mydata['host'] + ':' + str(mydata['port'])
            except Exception as e:
                self._logger.info(
                    self.tr("MQTT client userdata not as expected"))
                self._logger.debug(e)

        if rc == 0:
            if serv:
                self._logger.info("{0} {1}".format(
                    self.tr("MQTT disconnected on request from"), serv))
            else:
                self._logger.info(self.tr("MQTT disconnected on request"))

        else:
            Timer(15.000, self.mqttConnect).start()
            if serv:
                self._logger.warning("{0}{1} {2} {3}".format(
                    self.tr("MQTT disconnected with rc="), rc, self.tr("from"),
                    serv))
            else:
                self._logger.warning("{0}{1}".format(
                    self.tr("MQTT disconnected with rc="), rc))

        self._logger.debug("Connection state = " + str(self._connectionState))

    #__________________________________________________________________
    def mqttOnLog(self, client, userdata, level, buf):

        self._logger.debug("MQTT log level {0} : {1}".format(level, buf))

    #__________________________________________________________________
    def mqttOnMessage(self, client, userdata, msg):

        if self._mqttSwitchingConnection:
            self._logger.info(
                self.tr("Ignore MQTT message (switching connection)"))
            return

        message = None
        try:
            message = msg.payload.decode(encoding="utf-8", errors="strict")
        except:
            pass

        if not message:
            self._logger.warning("{0} {1}".format(
                self.tr("MQTT message decoding failed on"), msg.topic))
            return

        self._logger.debug('Message: ' + message + ' in ' + msg.topic)

        direction = "&mdash;"
        correspondent = None

        if self._topicRegexInbox:
            if "correspondent" in self._topicRegexInbox.pattern:
                try:
                    m = re.match(self._topicRegexInbox, msg.topic)
                    if m:
                        match = m.groupdict()
                        if match["correspondent"]:
                            correspondent = match["correspondent"]
                            direction = "&rarr;"
                except Exception as e:
                    self._logger.debug(e)
            else:
                self._logger.warning(
                    self.tr("No 'correspondent' field in inbox regex : ") +
                    self._topicRegexInbox.pattern)

        if not correspondent and self._topicRegexOutbox:
            if "correspondent" in self._topicRegexOutbox.pattern:
                try:
                    m = re.match(self._topicRegexOutbox, msg.topic)
                    if m:
                        match = m.groupdict()
                        if match["correspondent"]:
                            correspondent = match["correspondent"]
                            direction = "&larr;"
                except Exception as e:
                    self._logger.debug(e)
            else:
                self._logger.warning(
                    self.tr("No 'correspondent' field in outbox regex : ") +
                    self._topicRegexInbox.pattern)

        if not correspondent and self._topicRegexDefault:
            if "correspondent" in self._topicRegexDefault.pattern:
                try:
                    m = re.match(self._topicRegexDefault, msg.topic)
                    if m:
                        match = m.groupdict()
                        if match["correspondent"]:
                            correspondent = match["correspondent"]
                except Exception as e:
                    self._logger.debug(e)
            else:
                self._logger.warning(
                    self.tr("No 'correspondent' field in default regex : ") +
                    self._topicRegexInbox.pattern)

        if not correspondent:
            self._logger.warning(
                self.tr("No correspondent defined for topic : ") + msg.topic)

        now = time.time()
        msec = repr(now).split('.')[1][:3]
        timestamp = time.strftime("[%d/%m/%Y %H:%M:%S.{}]".format(msec),
                                  time.localtime(now))
        self.messageReceived.emit(correspondent, msg.topic, message, timestamp,
                                  direction)

    #__________________________________________________________________
    def mqttOnPublish(self, client, userdata, mid):

        self._logger.debug("userdata=%s mid=%s", userdata, mid)
        self._logger.info("{0} : mid={1}".format(
            self.tr("MQTT published"), mid))  # mid is a number (message id)

    #__________________________________________________________________
    def mqttOnSubscribe(self, client, userdata, mid, granted_qos):

        self._logger.debug("mid=%s granted_qos=%s", mid,
                           granted_qos)  # granted_qos is (2,)
        self._logger.info("{0} : {1} {2} {3}".format(
            self.tr("MQTT susbcribed to"), mid, self.tr("with QoS"),
            granted_qos))  # mid is a number (count)

    #__________________________________________________________________
    def mqttOnUnsubscribe(self, client, userdata, mid):

        self._logger.debug("mid=%s", mid)
        self._logger.info(
            "{0} : {1}".format(self.tr("MQTT unsusbcribed from"),
                               mid))  # mid is a number (message id)

        if self._mqttSwitchingConnection:
            Timer(0, self.mqttDisconnect).start()

    #__________________________________________________________________
    def mqttReconnect(self):

        self._logger.info(self.tr("MQTT reconnecting"))

        if self._mqttSwitchingConnection:
            self._logger.info(
                self.tr("Ignore MQTT reconnecting (switching connection)"))
            return

        try:
            self._mqttClient.reconnect()
        except Exception as e:
            self._logger.error(self.tr("MQTT reconnection call failed"))
            Timer(15.000, self.mqttConnect).start()
            self._logger.debug(e)

    #__________________________________________________________________
    @pyqtSlot()
    def reload(self):

        reg = QSettings()

        if "current session" in reg.childKeys() and reg.value(
                "current session", '').strip() and reg.value(
                    "current session", '').strip() in reg.childGroups():
            self._session = reg.value("current session")

        self._logger.info(self.tr("Current session : ") + self._session)

        self.setWindowTitle(self._session)

        if self._session not in reg.childGroups():
            reg.beginGroup(self._session)
            reg.setValue("host", self._host)
            reg.setValue("port", self._port)
            reg.setValue("root topic", self._rootTopic)
            reg.endGroup()
        else:
            reg.beginGroup(self._session)
            self._host = reg.value("host", 'localhost')
            try:
                self._port = reg.value("port", 1883, type=int)
            except:
                pass
            self._rootTopic = reg.value("root topic", '')
            reg.endGroup()

        if "current session" in reg.childKeys() and not reg.value(
                "current session", '') in reg.childGroups():
            reg.remove("current session")

        self._mqttSwitchingConnection = False
        self._mqttSwitchingSubscription = False

        if self._host != self._mqttServerHost or self._port != self._mqttServerPort:
            self._mqttSwitchingConnection = True
        elif self._rootTopic != self._mqttRootTopic:
            self._mqttSwitchingSubscription = True

        self._mqttServerHost = self._host
        self._mqttServerPort = self._port
        self._mqttRootTopic = self._rootTopic
        self._mqttSubTopic = '#'

        if self._rootTopic:
            self._mqttSubTopic = self._rootTopic + '/#'

        reg.beginGroup(self._session)
        inbox = reg.value("param inbox", 'inbox')
        outbox = reg.value("param outbox", 'outbox')
        regexInbox = reg.value("regex inbox",
                               r'^%ROOT%/(?P<correspondent>.+)/%INBOX%$')
        regexOutbox = reg.value("regex outbox",
                                r'^%ROOT%/(?P<correspondent>.+)/%OUTBOX%$')
        regexDefault = reg.value("regex default",
                                 r'.*/(?P<correspondent>[^/]+)/[^/]+$')
        reg.endGroup()

        regexInbox = regexInbox.replace("%ROOT%", self._rootTopic).replace(
            "%INBOX%", inbox)
        regexOutbox = regexOutbox.replace("%ROOT%", self._rootTopic).replace(
            "%OUTBOX%", outbox)

        self._topicRegexInbox = None
        try:
            self._topicRegexInbox = re.compile(regexInbox)
        except Exception as e:
            self._logger.error(self.tr("Failed to compile inbox regex"))
            self._logger.debug(e)

        self._topicRegexOutbox = None
        try:
            self._topicRegexOutbox = re.compile(regexOutbox)
        except Exception as e:
            self._logger.error(self.tr("Failed to compile outbox regex"))
            self._logger.debug(e)

        self._topicRegexDefault = None
        try:
            self._topicRegexDefault = re.compile(regexDefault)
        except Exception as e:
            self._logger.error(
                self.tr("Failed to compile topic default regex"))
            self._logger.debug(e)

        index = self._tabWidget.currentIndex()
        current = self._tabWidget.currentWidget()

        for index in (1, self._tabWidget.count()):
            try:
                self._displays.remove(self._tabWidget.widget(index))
                self._tabWidget.widget(index).deleteLater()
                self._tabWidget.removeTab(index)
            except Exception as e:
                self._logger.error(
                    self.
                    tr("Failed to remove observation : not in display list (index="
                       ) + str(index) + self.tr(")"))
                self._logger.debug(e)

        dspmsg = ''
        for d in self._displays:
            if dspmsg:
                dspmsg += ' | '
            else:
                dspmsg = 'Displays : '
            dspmsg += d.title()
        self._logger.debug(dspmsg)

        reg.beginGroup(self._session)
        for i in reg.childGroups():
            self.addDisplay(i)
        reg.endGroup()

        QCoreApplication.processEvents()

        if self._mqttSwitchingConnection:
            self.switchConnection()
        elif self._mqttSwitchingSubscription:
            self.switchSubscription()

    #__________________________________________________________________
    @pyqtSlot()
    def removeCurrentDisplay(self):

        index = self._tabWidget.currentIndex()
        current = self._tabWidget.currentWidget()

        if index > 0 and current == self.sender():
            try:
                title = self._tabWidget.tabText(index)
                self._tabWidget.removeTab(index)
                if current in self._displays:
                    self._displays.remove(self.sender())
                    self.sender().deleteLater()
                    self._logger.info("{0} : {1}".format(
                        self.tr("Remove observation"), title))
                    reg = QSettings()
                    reg.beginGroup(self._session)
                    reg.remove(title)
                    reg.endGroup()
                    reg.sync()
                else:
                    self._logger.warning(
                        self.
                        tr("Failed to remove observation : not in display list (index="
                           ) + str(index) + self.tr(")"))
            except Exception as e:
                self._logger.error(
                    self.
                    tr("Failed to remove observation : not in display list (index="
                       ) + str(index) + self.tr(")"))
                self._logger.debug(e)

        dspmsg = ''
        for d in self._displays:
            if dspmsg:
                dspmsg += ' | '
            else:
                dspmsg = 'Displays : '
            dspmsg += d.title()
        self._logger.debug(dspmsg)

    #__________________________________________________________________
    @pyqtSlot()
    def restoreWindow(self):

        self.resize(QSize(400, 400))
        self.move(QPoint(200, 200))

    #__________________________________________________________________
    def resizeEvent(self, event):

        if self.isVisible():
            Timer(0, self.layoutSaveSettings).start()

    #__________________________________________________________________
    @pyqtSlot()
    def settings(self):

        dlg = ObserverSettingsDialog(self._logger, self._session)
        dlg.move(self.pos() + QPoint(20, 20))

        dlg.correspondentRegex.connect(self.settingsRegex)
        dlg.reloadSession.connect(self.reload)
        dlg.exec()

        reg = QSettings()

        reg.beginGroup(self._session)
        self._host = reg.value("host", 'localhost')
        try:
            self._port = reg.value("port", 1883, type=int)
        except:
            self._port = 1883
        self._rootTopic = reg.value("root topic", '')
        reg.endGroup()

        if self._host != self._mqttServerHost or self._port != self._mqttServerPort:
            self.switchConnection()
        elif self._rootTopic != self._mqttRootTopic:
            self.switchSubscription()

    #__________________________________________________________________
    @pyqtSlot()
    def settingsRegex(self):

        dlg = ObserverRegexDialog(self._logger, self._session)
        dlg.move(self.pos() + QPoint(20, 20))
        dlg.exec()

        reg = QSettings()
        reg.beginGroup(self._session)
        inbox = reg.value("param inbox", 'inbox')
        outbox = reg.value("param outbox", 'outbox')
        regexInbox = reg.value("regex inbox",
                               r'^%ROOT%/(?P<correspondent>.+)/%INBOX%$')
        regexOutbox = reg.value("regex outbox",
                                r'^%ROOT%/(?P<correspondent>.+)/%OUTBOX%$')
        regexDefault = reg.value("regex default",
                                 r'.*/(?P<correspondent>[^/]+)/[^/]+$')
        reg.endGroup()

        regexInbox = regexInbox.replace("%ROOT%", self._rootTopic).replace(
            "%INBOX%", inbox)
        regexOutbox = regexOutbox.replace("%ROOT%", self._rootTopic).replace(
            "%OUTBOX%", outbox)

        self._topicRegexInbox = None
        try:
            self._topicRegexInbox = re.compile(regexInbox)
        except Exception as e:
            self._logger.error(
                self.tr("Failed to compile inbox regex :") + regexInbox)
            self._logger.debug(e)

        self._topicRegexOutbox = None
        try:
            self._topicRegexOutbox = re.compile(regexOutbox)
        except Exception as e:
            self._logger.error(
                self.tr("Failed to compile outbox regex :") + regexOutbox)
            self._logger.debug(e)

        self._topicRegexDefault = None
        try:
            self._topicRegexDefault = re.compile(regexDefault)
        except Exception as e:
            self._logger.error(
                self.tr("Failed to compile topic default regex :") +
                regexDefault)
            self._logger.debug(e)

    #__________________________________________________________________
    def start(self):

        try:
            self._mqttClient.on_connect = self.mqttOnConnect
            self._mqttClient.on_disconnect = self.mqttOnDisconnect
            self._mqttClient.on_log = self.mqttOnLog
            self._mqttClient.on_message = self.mqttOnMessage
            self._mqttClient.on_publish = self.mqttOnPublish
            self._mqttClient.on_subscribe = self.mqttOnSubscribe
            self._mqttClient.on_unsubscribe = self.mqttOnUnsubscribe
            Timer(0, self.mqttConnect).start()
        except:
            self._logger.error(
                self.tr("Can't start MQTT (check definitions in .INI)"))
            msgbox = QMessageBox()
            msgbox.setWindowTitle(self.tr("Observer"))
            msgbox.setWindowIcon(QIcon(':/view-eye.svg'))
            msgbox.setText(
                self.tr("Failed to set MQTT client !") + "<br><br><i>" +
                self.tr("Application will be closed.") + "</i><br>")
            msgbox.setStandardButtons(QMessageBox.Close)
            msgbox.setAttribute(Qt.WA_DeleteOnClose)
            msgbox.setWindowFlags(msgbox.windowFlags()
                                  & ~Qt.WindowContextHelpButtonHint)
            msgbox.button(QMessageBox.Close).setText(self.tr("Close"))
            msgbox.resize(QSize(400, 300))
            msgbox.exec()
            self._logger.info(self.tr("Done"))
            Timer(0, QCoreApplication.quit).start()

        self._logger.debug("Connection state = " + str(self._connectionState))

    #__________________________________________________________________
    def switchConnection(self):

        self._mqttSwitchingConnection = True

        self.resetDisplays.emit()

        current_topic = self._mqttSubTopic

        if self._connectionState == ConnectionState.CONNECTED or self._connectionState == ConnectionState.CONNECTING:
            try:
                (result, mid) = self._mqttClient.unsubscribe(current_topic)
                self._logger.info("{0} {1} : {2}".format(
                    self.tr("MQTT unsubscribing from"), mid, current_topic))
            except Exception as e:
                self._logger.debug(e)
                Timer(0, self.mqttDisconnect).start()
        else:
            Timer(0, self.mqttConnect).start()

        self._logger.debug("Connection state = " + str(self._connectionState))

    #__________________________________________________________________
    def switchSubscription(self):

        self.resetDisplays.emit()

        current_topic = self._mqttSubTopic
        self._mqttRootTopic = self._rootTopic

        if self._rootTopic:
            self._mqttSubTopic = self._rootTopic + '/#'
        else:
            self._mqttSubTopic = '#'

        cloud = self._mqttServerHost + ':' + str(self._mqttServerPort)

        if self._mqttRootTopic:
            cloud += '/' + self._mqttRootTopic + '/#'
        else:
            cloud += '/#'

        self._cloudLabel.setText(cloud)
        self.resetDisplays.emit()

        if self._connectionState == ConnectionState.CONNECTED:
            try:
                (result, mid) = self._mqttClient.unsubscribe(current_topic)
                self._logger.info("{0} {1} : {2}".format(
                    self.tr("MQTT unsubscribing from"), mid, current_topic))
                (result, mid) = self._mqttClient.subscribe(self._mqttSubTopic)
                self._logger.info("{0} {1} : {2}".format(
                    self.tr("MQTT subscribing to"), mid, self._mqttSubTopic))
            except Exception as e:
                self._logger.debug(e)
        else:
            Timer(0, self.mqttReconnect).start()

        self._logger.debug("Connection state = " + str(self._connectionState))
コード例 #41
0
class QueryUI(QWidget):
    def __init__(self):
        super().__init__()
        try:
            self.keyValues = getOfficialKeys()
        except RequestException:
            logging.warning(
                "There was a problem with the internet connection. You will not be able to see the existing keys."
            )
        self.onClearPolygonF = lambda: None
        self.onPolygonEnabledF = lambda: None
        self.onPolygonDisabledF = lambda: None
        self.currentHtml = EMPTY_HTML
        self.initUI()

    def initUI(self):
        self.layout = QVBoxLayout()
        self.layout.setContentsMargins(0, 0, 0, 0)

        self.requestAreaWidget = QToolBox()
        self.requestAreaWidget.layout().setSpacing(1)

        self.requestTabs = QTabWidget()
        self.requestTabs.setUsesScrollButtons(True)
        self.requestTabs.currentChanged.connect(self.__updateTabSizes__)
        self.requestAreaWidget.addItem(self.requestTabs, "Requests")

        self.requestOps = RequestsOperations(self)
        self.requestAreaWidget.addItem(self.requestOps, "Operations")

        self.generalConfig = GlobalOverpassSettingUI(self)
        self.requestAreaWidget.addItem(self.generalConfig, "General")

        self.disambiguationWidget = DisambiguationWidget(
            self.__getRequestByName__, self.__applyTableRow__, self)
        self.requestAreaWidget.addItem(self.disambiguationWidget,
                                       "Disambiguation")

        self.headers = self.requestAreaWidget.findChildren(
            QAbstractButton, "qt_toolbox_toolboxbutton")
        self.requestAreaWidget.currentChanged.connect(
            self.__onToolTabChanged__)
        self.headers[0].setIcon(QIcon(os.path.join(picturesDir,
                                                   "arrowUp.png")))
        for i in range(1, len(self.headers)):
            self.headers[i].setIcon(
                QIcon(os.path.join(picturesDir, "arrowDown.png")))

        self.layout.addWidget(self.requestAreaWidget)

        self.setLayout(self.layout)

    def __getRequestByName__(self, requestName):
        for requestWidget in self.findChildren(RequestWidget):
            if requestWidget.getName() == requestName:
                return requestWidget.getRequest()
        return None

    def __applyTableRow__(self, name, data):
        filters, ids = data
        for requestWidget in self.findChildren(RequestWidget):
            if requestWidget.getName() == name:
                for newFilter in filters:
                    requestWidget.addFilter(newFilter)
                break

        if len(ids) > 0:
            idsRequestName = SetNameManagement.getUniqueSetName()
            request = OverpassRequest(OsmType.WAYS, Surround.NONE,
                                      idsRequestName)
            request.setIds(ids)
            self.addRequest(request)

            differenceOpName = SetNameManagement.getUniqueSetName()
            self.requestOps.addOp(OverpassDiff(name, differenceOpName),
                                  [idsRequestName])
            self.requestOps.setOutputSet(differenceOpName)

        logging.info("Configuration from the table row has been applied.")

    def __onToolTabChanged__(self, i):
        for h in range(len(self.headers)):
            if h == i:
                self.headers[h].setIcon(
                    QIcon(os.path.join(picturesDir, "arrowUp.png")))
            else:
                self.headers[h].setIcon(
                    QIcon(os.path.join(picturesDir, "arrowDown.png")))

    def __updateTabSizes__(self, index):
        for i in range(self.requestTabs.count()):
            if i != index:
                self.requestTabs.widget(i).setSizePolicy(
                    QSizePolicy.Ignored, QSizePolicy.Ignored)

        if index >= 0:
            self.requestTabs.widget(index).setSizePolicy(
                QSizePolicy.Preferred, QSizePolicy.Preferred)
            self.requestTabs.widget(index).resize(
                self.requestTabs.widget(index).minimumSizeHint())
            self.requestTabs.widget(index).adjustSize()

    def setOnRequestChanged(self, f):
        self.requestTabs.currentChanged.connect(f)

    def addRequestByFilters(self, filters=None):
        requestWidget = RequestWidget(self, self.keyValues)
        setName = requestWidget.requestName
        requestWidget.changePage(self.currentHtml)
        self.requestTabs.addTab(requestWidget, setName)
        self.requestOps.addRequest(setName)
        self.disambiguationWidget.addSet(setName)

        if filters is not None:
            for filter in filters:
                requestWidget.addFilter(filter)

    def addRequest(self, request):
        if not SetNameManagement.isAvailable(request.name):
            raise ValueError("There is another request with the same name.")
        else:
            SetNameManagement.assign(request.name)

        requestWidget = RequestWidget(self, self.keyValues, request)
        requestWidget.changePage(self.currentHtml)
        self.requestTabs.addTab(requestWidget, request.name)
        self.requestOps.addRequest(request.name)
        self.disambiguationWidget.addSet(request.name)

    def removeRequest(self):
        requestName = self.requestTabs.currentWidget().getName()
        self.requestOps.removeSetAndDependencies(requestName)
        self.disambiguationWidget.removeSet(requestName)
        currentRequestWidget = self.requestTabs.currentWidget()
        SetNameManagement.releaseName(currentRequestWidget.requestName)
        self.requestTabs.removeTab(self.requestTabs.currentIndex())
        currentRequestWidget.deleteLater()

    def requestsCount(self):
        return self.requestTabs.count()

    def getQuery(self):
        query = OverpassQuery(self.requestOps.outputSet())
        query.addDate(self.generalConfig.getDate())

        for i in range(self.requestTabs.count()):
            query.addRequest(self.requestTabs.widget(i).getRequest())

        for op in self.requestOps.ops:
            query.addSetsOp(op)

        return query

    def setQuery(self, query):
        self.reset()
        for request in query.requests:
            self.addRequest(request)
        for op in query.ops:
            self.requestOps.addOp(op)
        if query.config.get("date") is not None:
            self.generalConfig.setDate(
                datetime.strptime(query.config["date"], "%Y-%m-%dT00:00:00Z"))
        else:
            self.generalConfig.setDate()
        self.requestOps.setOutputSet(query.outputSet)

    def reset(self):
        while self.requestTabs.count() > 0:
            self.removeRequest()
        self.generalConfig.setDate()

    def updateMaps(self, html):
        self.currentHtml = html
        for requestWidget in self.findChildren(RequestWidget):
            requestWidget.changePage(html)

        return self.getCurrentMap()

    def updateMapFromRow(self):
        return self.updateMaps(
            self.disambiguationWidget.getHtmlFromSelectedRow())

    def getCurrentMap(self):
        if self.requestTabs.currentWidget() is None:
            return None
        else:
            return self.requestTabs.currentWidget().getMap()
コード例 #42
0
class MainLayout:
    def __init__(self):

        self.parameters = {}
        self.main = QVBoxLayout()
        container = QHBoxLayout()
        self.opf = QFormLayout()

        title = QLabel("Set Operational Parameters")
        title.setFont(QFont('Helvetica', 14))
        title.setAlignment(Qt.AlignCenter)
        self.opf.addRow(title)
        self.opf.setVerticalSpacing(20)
        ops = [('Nm', "Speed of Motor", '1450'), ('Nd', "Speed of Digester Shaft", '109'),
               ('Nc', "Speed of Cake Breaker Shaft", '109'), ('Na', "Speed of Auger Shaft", '218'),
               ('Nsp', "Speed of Screw Press Shaft", '60')]
        self.defaults = QPushButton('Clear')
        self.defaults.setToolTip('Toggle this button to use optimized values for Operational Parameters')
        self.defaults.setCheckable(1)
        self.defaults.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
        self.defaults.toggled.connect(self._defaults)
        dl = QLabel('Reset')
        dl.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
        for op in ops:
            opp = QLineEdit()
            opp.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
            opp.setText(op[2])
            lb = QLabel(op[1])
            lb.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
            opp.setPlaceholderText(op[1])
            opp.setObjectName(op[1])
            opp.setAccessibleName(op[0])
            opp.setInputMask('>0000;_')
            self.opf.addRow(lb, opp)
        self.opf.addRow(dl, self.defaults)

        frame = QFrame()
        frame.setLayout(self.opf)
        frame.setObjectName('opf')

        # Layout for Throughput input
        tpf = QVBoxLayout()
        self.capacity = QLineEdit()
        self.capacity.setAlignment(Qt.AlignLeft | Qt.AlignCenter)
        self.capacity.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
        dv = DV(280, 5650, 3, self.capacity)
        dv.setNotation(DV.StandardNotation)
        self.capacity.setValidator(dv)
        self.capacity.setPlaceholderText('Enter value between 280 and 5650')
        title = QLabel("Set Throughput Capacity")
        title.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
        title.setFont(QFont('Helvetica', 14))
        title.setAlignment(Qt.AlignLeft | Qt.AlignCenter)
        tpf.addWidget(title)
        tpf.addSpacing(15)
        tpf.addWidget(self.capacity)
        tpf.setAlignment(Qt.AlignLeft | Qt.AlignCenter)
        frame1 = QFrame()
        frame1.setLayout(tpf)
        frame1.setObjectName('tpf')

        container.addWidget(frame1)
        container.addSpacing(50)
        container.addWidget(frame)

        self.bs = QHBoxLayout()
        self.compute = QPushButton('Compute')
        self.compute.setCheckable(True)
        self.compute.clicked.connect(self.run)

        self.reset = QPushButton('Reset')
        self.reset.setCheckable(True)
        self.reset.clicked.connect(self._reset)
        self.reset.setEnabled(False)

        self.report = QPushButton('Generate Report')
        self.report.setCheckable(True)
        self.report.clicked.connect(self._generate)
        self.report.setEnabled(False)

        self.bs.addWidget(self.compute)
        self.bs.setSpacing(15)
        self.bs.addWidget(self.report)
        self.bs.addWidget(self.reset)
        self.bs.setAlignment(Qt.AlignCenter | Qt.AlignBottom)

        self.main.addLayout(container)
        self.main.addSpacing(20)
        self.main.addLayout(self.bs)

        mframe = QFrame()
        mframe.setLayout(self.main)
        mframe.setObjectName('main')
        mframe.setFrameShape(QFrame.StyledPanel)
        mframe.setFrameStyle(QFrame.Raised | QFrame.Panel)
        mframe.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)

        ml = QVBoxLayout()
        ml.addWidget(mframe)
        ml.setAlignment(Qt.AlignCenter | Qt.AlignTop)

        self.tabs = QTabWidget()
        self.tabs.setTabPosition(QTabWidget.North)
        self.tabs.setMovable(True)

        self.widget = QWidget()
        self.widget.setObjectName('mainf')
        self.widget.setContentsMargins(0, 50, 0, 0)
        self.widget.setLayout(ml)
        self.tabs.insertTab(0, self.widget, 'Results')

    def _defaults(self, s):
        dp = {'Nm': '1450', 'Nd': '109', 'Nc': '109', 'Na': '218', 'Nsp': '60'}
        num = self.opf.count()
        if s:
            self.defaults.setText('Defaults')
        else:
            self.defaults.setText('Clear')
        for i in range(num):
            child = self.opf.itemAt(i).widget()
            if isinstance(child, QLineEdit):
                if s:
                    child.setText('')
                else:
                    child.setText(dp[child.accessibleName()])

    def _generate(self):
        path = homedir('m')
        path = str(path / self.parameters['filename'])
        file, _ = QFileDialog.getSaveFileName(self.report, 'Save Manual', path, "PDF Format (*.pdf)")

        if file:
            BuildDoc(self.parameters, file)

    def run(self, s):
        res = self.validate()
        if res['status']:
            tpd, op = res['results'][0], res['results'][1:]
            output = model(tpd, op)
            self.parameters = format_results(output, tpd)
            self.buiildTables()
            self.showImages()
            self.compute.setDisabled(True)
            self.reset.setEnabled(True)
            self.report.setEnabled(True)
        else:
            self.msgBox(res['err'])

    def _reset(self, r):
        self.compute.setDisabled(False)
        while self.tabs.count() > 1:
            self.tabs.removeTab(1)
        self.reset.setEnabled(False)
        self.report.setEnabled(False)

    def validate(self):
        err = ''
        inputs = []
        try:
            if (i := self.capacity.text()) and (280 <= int(i) <= 5650):
                inputs.append(int(i))
            else:
コード例 #43
0
class PlotWindow(QWidget):
    def __init__(self, tab):
        super(PlotWindow, self).__init__()
        self.tab = tab
        self.allAxes = {}
        self.curveList = []
        self.extraLines = []
        self.layout = QHBoxLayout()
        self.graph_layout = QVBoxLayout()
        self.gbox_layout = QVBoxLayout()

        self.tabGBActor = QTabWidget()

        self.dateplot = DatePlot(self)
        self.customize = Customize(self)
        self.button_arrow = self.ButtonArrow()
        self.button_del_graph = self.ButtonDelete()

        self.gbox_layout.addWidget(self.dateplot)
        self.gbox_layout.addWidget(self.customize)
        self.gbox_layout.addWidget(self.tabGBActor)
        self.gbox_layout.addWidget(self.button_del_graph)

        self.layout.addLayout(self.graph_layout)
        self.layout.addWidget(self.button_arrow)
        self.layout.addLayout(self.gbox_layout)

        for widget in [self.dateplot, self.customize, self.tabGBActor]:
            widget.setMaximumWidth(400)

        self.setLayout(self.layout)

    @property
    def mainwindow(self):
        return self.tab.mainwindow

    @property
    def config(self):
        return self.dateplot.config

    @property
    def axes2curves(self):
        d = {ax: [] for ax in [None] + list(self.allAxes.values())}

        for curve in self.curveList:
            d[curve.getAxes()].append(curve)

        return d

    @property
    def line2Curve(self):
        return {curve.line: curve for curve in self.curveList}

    @property
    def axes2id(self):
        d = {ax: id for id, ax in self.allAxes.items()}
        d[None] = None
        return d

    def createGraph(self, custom):
        try:
            self.graph.close()
            self.graph_layout.removeWidget(self.graph)
            self.graph.deleteLater()
        except AttributeError:
            pass

        self.graph = Graph(self, custom)
        self.graph_layout.insertWidget(0, self.graph)

    def getAxes(self, newType, i=-1):

        for i, ax in self.allAxes.items():
            try:
                curve = self.axes2curves[ax][0]
                if curve.type == newType:
                    return ax
            except IndexError:
                return ax

            if i == 3:
                raise ValueError('No Axe available')
        return i + 1

    def setAxes(self, allAxes):
        for idAxes, oldAxes in list(self.allAxes.items()):
            self.unsetLines(oldAxes, allAxes)
            self.allAxes.pop(idAxes, None)

        self.allAxes = allAxes

    def unsetLines(self, axes, newAxes):
        while axes.lines:
            line = axes.lines[0]
            axes.lines.remove(line)
            try:
                curve = self.line2Curve[line]
                curve.line = False
                if curve.getAxes() not in newAxes.values():
                    curve.setAxes(None)
            except KeyError:
                pass
            del line

    def addCurve(self, curveConf):

        new_curve = Curve(self, curveConf)
        axes = self.getAxes(new_curve.type)

        if isinstance(axes, int):
            idAxes = axes
            self.customize.allAxes[idAxes].checkbox.setChecked(2)
            axes = self.allAxes[idAxes]

        new_curve.setAxes(axes)
        self.appendCurve(new_curve)
        self.graph.plotCurves(new_curve)

        return new_curve

    def appendCurve(self, new_curve):

        self.curveList.append(new_curve)
        self.customize.appendRow(new_curve)

    def switchCurve(self, axeId, curve):
        ax = self.allAxes[axeId] if axeId is not None else None
        self.graph.switchCurve(ax, curve)

    def removeCurve(self, curve):
        self.curveList.remove(curve)
        self.graph.removeCurve(curve)

        try:
            checkbox = curve.checkbox
            checkbox.setCheckable(True)
            checkbox.setChecked(0)
        except RuntimeError:
            pass  # Checkbox could have been already deleted

    def constructGroupbox(self, config):

        while self.tabGBActor.count():
            widget = self.tabGBActor.widget(0)
            self.clearLayout(widget.layout())
            self.tabGBActor.removeTab(0)
            widget.close()
            widget.deleteLater()

        sortedModule = self.sortCfg(config)

        for actorname in sorted(sortedModule):
            config = sortedModule[actorname]
            if config:
                t = TabActor(self, config)
                self.tabGBActor.addTab(t, actorname)

    def showhideConfig(self, button_arrow):

        if not self.tabGBActor.isHidden():
            self.tabGBActor.hide()
            self.dateplot.hide()
            self.customize.hide()
            self.button_del_graph.hide()
            button_arrow.setIcon(self.mainwindow.icon_arrow_left)
        else:
            self.tabGBActor.show()
            self.button_del_graph.show()
            self.dateplot.show()
            self.customize.show()
            button_arrow.setIcon(self.mainwindow.icon_arrow_right)

    def ButtonDelete(self):
        button = QPushButton('Remove Graph')
        button.clicked.connect(partial(self.removeGraph, self.layout))
        return button

    def ButtonArrow(self):

        button_arrow = QPushButton()
        button_arrow.setIcon(self.mainwindow.icon_arrow_right)
        button_arrow.clicked.connect(partial(self.showhideConfig, button_arrow))
        button_arrow.setStyleSheet('border: 0px')

        return button_arrow

    def removeGraph(self, layout):
        self.clearLayout(layout)
        self.tab.removeGraph(self)

    def clearLayout(self, layout):

        if layout is not None:
            while layout.count():
                item = layout.takeAt(0)
                widget = item.widget()
                if widget is not None:
                    widget.deleteLater()
                else:
                    self.clearLayout(item.layout())

    def table2label(self, tablename, mergeAIT=False):
        for key, label in self.mainwindow.cuArms.items():
            if key in tablename:
                return label
        if mergeAIT:
            return 'AIT'
        else:
            return tablename.split('__')[0].upper()

    def sortCfg(self, config):
        sortedDict = {}
        for dev in config:
            label = self.table2label(tablename=dev.tablename, mergeAIT=False)
            try:
                sortedDict[label].append(dev)
            except KeyError:
                sortedDict[label] = [dev]
        return sortedDict
コード例 #44
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])
コード例 #45
0
class SettingsWidget(QWidget, MooseWidget):
    """
    A very simple widget to modify settings.
    This widget actually doesn't do anything, it just holds
    various tabs.
    Other widgets are responsible for creating their own settings
    widget and adding it here.
    """
    def __init__(self, **kwds):
        """
        Constructor.
        """
        super(SettingsWidget, self).__init__(**kwds)

        self.top_layout = WidgetUtils.addLayout(vertical=True)
        self.setLayout(self.top_layout)
        self.tabs = QTabWidget(parent=self)
        self.top_layout.addWidget(self.tabs)
        self.button_layout = WidgetUtils.addLayout()
        self.top_layout.addLayout(self.button_layout)
        self.save_button = WidgetUtils.addButton(self.button_layout, self, "&Save", self._save)
        self.cancel_button = WidgetUtils.addButton(self.button_layout, self, "&Cancel", self._cancel)
        self.setup()

    def addTab(self, name, widget, index=-1):
        """
        Add a new tab for settings.
        Input:
            name: name of the tab
            widget: widget of settings
            index: index of where to put the tab. Default is at the beginning.
        """
        self.removeTab(name)
        self.tabs.insertTab(index, widget, name)

    def removeTab(self, name):
        """
        Remove a tab with a given name.
        Input:
            name: name of the tab. If it doesn't exist, nothing happens.
        """
        for i in range(self.tabs.count()):
            if self.tabs.tabText(i) == name:
                self.tabs.removeTab(i)
                break

    def load(self):
        """
        Loads all the settings from the different widgets.
        """
        settings = QSettings()
        for i in range(self.tabs.count()):
            w = self.tabs.widget(i)
            w.load(settings)

    def _save(self):
        """
        Saves all the settings from the different widgets.
        """
        settings = QSettings()
        for i in range(self.tabs.count()):
            w = self.tabs.widget(i)
            w.save(settings)
        settings.sync()
        self.close()

    def _cancel(self):
        """
        They didn't want to save.
        """
        self.close()