Exemple #1
0
class dailyTab(QWidget):
    def __init__(self):
        super().__init__()
        # Виджет для дейлков
        # Содержит содержит главный таб виджет для дейликов
        self.tab = QTabWidget()

        self.vbox = QVBoxLayout()
        self.vbox.addWidget(self.tab)
        self.setLayout(self.vbox)

        self.threads = []
        # При ините создаём тред для получения дейликов
        self.loadDataThread = loadDataThread(r'https://api.guildwars2.com/v2/achievements/daily')
        self.loadDataThread.signal.connect(self.getEvent, Qt.QueuedConnection)
        self.loadDataThread.start()

    def getEvent(self, signal):
        signal = json.loads(signal)
        for metaEvent in signal.keys():
            setattr(self,metaEvent,frame())
            self.tab.addTab(getattr(self,metaEvent),metaEvent)
            for event in signal[metaEvent]:
                if (event['level']['max'] == 80 and metaEvent == 'pve') or metaEvent != 'pve':
                    getattr(self,metaEvent).getEvent(event)

    def addTab(self, event, metaEvent):
        getattr(self,'{}Tab'.format(metaEvent)).addEvent(event)

        self.resize(self.grid.sizeHint())
    def dialogExtract2csv(self):
        d = QDialog(self)
        d.setFixedWidth(450)
        d.setWindowTitle("Extract data to Csv")
        d.setVisible(True)
        vbox = QVBoxLayout()
        tabWidget = QTabWidget()
        for name, mod in list(self.moduleDict.items()):
            wid = QWidget()
            grid = QGridLayout()
            grid.setSpacing(20)
            wid.dateStart = QLineEdit('%s00:00' % dt.datetime.now().strftime("%Y-%m-%dT"))
            wid.dateEnd = QLineEdit("Now")
            grid.addWidget(QLabel("From"), 0, 0)
            grid.addWidget(wid.dateStart, 0, 1)
            grid.addWidget(QLabel("To"), 0, 2)
            grid.addWidget(wid.dateEnd, 0, 3)
            for i, device in enumerate(mod.devices):
                checkbox = QCheckBox(device.deviceLabel)
                checkbox.stateChanged.connect(partial(self.csvUpdateTab, name, checkbox, device))
                checkbox.setCheckState(2)
                grid.addWidget(checkbox, 1 + i, 0, 1, 3)

            wid.setLayout(grid)
            tabWidget.addTab(wid, name)

        buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        buttonBox.button(QDialogButtonBox.Ok).clicked.connect(partial(self.extract2csv, tabWidget, d))
        buttonBox.button(QDialogButtonBox.Cancel).clicked.connect(d.close)

        vbox.addWidget(tabWidget)
        vbox.addWidget(buttonBox)
        d.setLayout(vbox)
class PluginErrorDialog(QDialog):
    """
    Dialog with tabs each tab is a python traceback
    """
    def __init__(self):
        super(PluginErrorDialog, self).__init__()
        self.setWindowTitle(translations.TR_PLUGIN_ERROR_REPORT)
        self.resize(600, 400)
        vbox = QVBoxLayout(self)
        label = QLabel(translations.TR_SOME_PLUGINS_REMOVED)
        vbox.addWidget(label)
        self._tabs = QTabWidget()
        vbox.addWidget(self._tabs)
        hbox = QHBoxLayout()
        btnAccept = QPushButton(translations.TR_ACCEPT)
        btnAccept.setMaximumWidth(100)
        hbox.addWidget(btnAccept)
        vbox.addLayout(hbox)
        #signals
        btnAccept.clicked['bool'].connect(self.close)

    def add_traceback(self, plugin_name, traceback_msg):
        """Add a Traceback to the widget on a new tab"""
        traceback_widget = TracebackWidget(traceback_msg)
        self._tabs.addTab(traceback_widget, plugin_name)
Exemple #4
0
class RosConfigDialog(QDialog):
    configChanged = pyqtSignal()

    # use this for editable filtering of message types http://www.qtcentre.org/threads/23143-Combobox-entries-filter-as-I-type

    def __init__(self, name):
        super(QDialog, self).__init__()
        self.setWindowTitle(name)
        self.tabWidget = None

        self.config = None
        self.packageTab = None
        self.topicsTab = None

        self.tabWidget = QTabWidget()
        mainLayout = QFormLayout()
        mainLayout.addWidget(self.tabWidget)
        self.packageTab = PackageTab()
        self.packageTab.configChanged.connect(self.configChangedHandler)
        self.tabWidget.addTab(self.packageTab, 'Package')
        self.topicsTab = TopicsTab()
        self.topicsTab.configChanged.connect(self.configChangedHandler)
        self.tabWidget.addTab(self.topicsTab, 'Topics')
        self.resize(700, 100)
        self.setLayout(mainLayout)

    def setConfig(self, config):
        self.config = config
        self.packageTab.setConfig(self.config)
        self.topicsTab.setConfig(self.config)

    def configChangedHandler(self):
        self.configChanged.emit()
Exemple #5
0
 def __init__(self, parent):
     QTabWidget.__init__(self, parent)
     self.addTab(PaveNumerique(parent), ' Pavé numérique ')
     self.addTab(Options(parent), 'Options')
     self.addTab(Avance(parent), 'Avancé')
     self.setTabPosition(QTabWidget.South)
     self.setStyleSheet("""
     QTabBar::tab:selected {
     background: white;
     border: 1px solid #C4C4C3;
     border-top-color: white; /* same as the pane color */
     border-bottom-left-radius: 4px;
     border-bottom-right-radius: 4px;
     border-top-left-radius: 0px;
     border-top-right-radius: 0px;
     min-width: 8ex;
     padding: 7px;
     }
     QStackedWidget {background:white}
     QTabBar QToolButton {
     background:white;
     border: 1px solid #C4C4C3;
     border-top-color: white; /* same as the pane color */
     border-bottom-left-radius: 4px;
     border-bottom-right-radius: 4px;
     border-top-left-radius: 0px;
     border-top-right-radius: 0px;
     }
     """)
	def __init__(self,index):
		QTabWidget.__init__(self)

		self.index=index
		lines=[]

		if inp_load_file(lines,"pulse"+str(self.index)+".inp")==True:
			self.tab_name=inp_search_token_value(lines, "#sim_menu_name")
		else:
			self.tab_name=""


		self.setTabsClosable(True)
		self.setMovable(True)

		self.tmesh = tab_time_mesh(self.index)
		self.addTab(self.tmesh,_("time mesh"))


		self.circuit=circuit(self.index)

		self.addTab(self.circuit,_("Circuit"))

		tab=tab_class()
		tab.init("pulse"+str(self.index)+".inp","Configure")
		self.addTab(tab,"Configure")
Exemple #7
0
 def __init__ (self):
     super().__init__()
     
     FlGlob.mainwindow = self
     self.activeChanged.connect(self.loadnode)
     self.selectedChanged.connect(self.filteractions)
     self.viewChanged.connect(self.filterglobactions)
     
     self.style = FlNodeStyle(QFont())
     self.initactions()
     self.initmenus()
     self.inittoolbars()
     
     tabs = QTabWidget(parent=self)
     tabs.setTabsClosable(True)
     tabs.setTabBarAutoHide(True)
     tabs.tabCloseRequested.connect(self.closetab)
     tabs.tabBarDoubleClicked.connect(self.nametab)
     tabs.currentChanged.connect(self.tabswitched)
     self.tabs = tabs
     
     self.setCentralWidget(tabs)
     self.initdocks()
     self.filterglobactions()
     self.filteractions()
Exemple #8
0
class T_window(QWidget):
    def __init__(self):
        super().__init__()
        self.tabs = QTabWidget()
        self.com = T_communication()
        self.pbar = QProgressBar()
        self.pbar.setFormat("Battery : %p%")
        self.grid = QGridLayout()

        self.setLayout(self.grid)
        self.grid.addWidget(self.pbar)
        self.grid.addWidget(self.tabs)

        self.dpi = T_dpi()
        self.com.getDpi(self.dpi)
        self.dpi.dataHasBeenSent()
        self.t = []
        for i in range(0, 4):
            self.t.append(T_tab(i, self.dpi, self.com))
            self.tabs.addTab(self.t[i], "Mode " + str(i + 1))

        self.data = T_data(self.pbar, self.tabs, self.dpi, self.com)
        for i in range(0, 4):
            self.t[i].sendButton.clicked.connect(self.data.sendDpi)
            self.t[i].resetButton.clicked.connect(self.com.resetDpi)
        self.timer = QBasicTimer()
        self.timer.start(100, self.data)
        self.tabs.currentChanged.connect(self.com.sendMode)
Exemple #9
0
 def __init__(self, parent):
     QTabWidget.__init__(self, parent)
     self.addTab(APropos(parent), 'À propos')
     self.addTab(Licence(parent), 'Licence')
     self.addTab(Notes(parent), 'Notes de version')
     self.addTab(Credits(parent), 'Crédits')
     self.setTabPosition(QTabWidget.South)
     self.setStyleSheet("""
     QTabBar::tab:selected {
     background: white;
     border: 1px solid #C4C4C3;
     border-top-color: white; /* same as the pane color */
     border-bottom-left-radius: 4px;
     border-bottom-right-radius: 4px;
     border-top-left-radius: 0px;
     border-top-right-radius: 0px;
     min-width: 8ex;
     padding: 7px;
     }
     QStackedWidget {background:white}
     QTabBar QToolButton {
     background:white;
     border: 1px solid #C4C4C3;
     border-top-color: white; /* same as the pane color */
     border-bottom-left-radius: 4px;
     border-bottom-right-radius: 4px;
     border-top-left-radius: 0px;
     border-top-right-radius: 0px;
     }
     """)
class TabWidgets(QTabWidget):
    def __init__(self, parent):
        super(TabWidgets, self).__init__(parent)
        self.wdg1 = QWidget(self)
        self.lay_wdg1 = QVBoxLayout(self.wdg1)
        self.wdg2 = QWidget(self)
        self.lay_wdg2 = QVBoxLayout(self.wdg2)
        #self.wdg1.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)
        #self.wdg2.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
        self.wdg1.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
        self.wdg2.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
        
        self._construct_UI()
#------------------------------------------------------------------------------
    def _construct_UI(self):
        """ Initialize UI with tabbed subplots """
        self.tabWidget = QTabWidget(self)
        self.tabWidget.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)
        self.tabWidget.addTab(self.wdg1, 'Wdg 1')
        self.tabWidget.addTab(self.wdg2, 'Wdg 2')

        layVMain = QVBoxLayout()
        layVMain.addWidget(self.tabWidget)
        self.setLayout(layVMain)
        # When user has switched the tab, call self.current_tab_redraw
        print('size wdg1: {0}'.format(self.wdg1.size()))
        print('size wdg2: {0}'.format(self.wdg2.size()))
        self.tabWidget.currentChanged.connect(self.current_tab_redraw)
#------------------------------------------------------------------------------
        
    def current_tab_redraw(self):
        pass
Exemple #11
0
    def initialize(self):
        tab_widget = QTabWidget()
        tab1 = QWidget()
        tab2 = QWidget()

        juggle_button = QPushButton("Juggle")
        juggle_button.clicked.connect(self.start_simulation)

        hbox = QHBoxLayout()
        hbox.addStretch(1)
        hbox.addWidget(juggle_button)

        vbox = QVBoxLayout(tab1)
        vbox.addStretch(1)
        vbox.addLayout(hbox)

        hbox2 = QHBoxLayout(tab2)

        tab_widget.addTab(tab1, "Main")
        tab_widget.addTab(tab2, "Other")

        self.setCentralWidget(tab_widget)

        menubar = self.menuBar()
        file_menu = menubar.addMenu('&File')
        help_menu = menubar.addMenu('&Help')
        about = help_menu.addMenu('&About')
        exit_action = QAction(QIcon('exit.png'), '&Exit', self)
        exit_action.triggered.connect(qApp.quit)
        file_menu.addAction(exit_action)

        self.setGeometry(300, 300, 350, 300)
        self.setWindowTitle('Juggling Simulator')
        self.show()
Exemple #12
0
 def __init__(self, title, text, image, contributors, parent=None):
     super(AboutDialog, self).__init__(parent)
     layout = QVBoxLayout()
     titleLayout = QHBoxLayout()
     name_versionLabel = QLabel(title)
     contentsLayout = QHBoxLayout()
     aboutBrowser = QTextBrowser()
     aboutBrowser.append(text)
     aboutBrowser.setOpenExternalLinks(True)
     creditsBrowser = QTextBrowser()
     creditsBrowser.append(contributors)
     creditsBrowser.setOpenExternalLinks(True)
     TabWidget = QTabWidget()
     TabWidget.addTab(aboutBrowser, self.tr('About'))
     TabWidget.addTab(creditsBrowser, self.tr('Contributors'))
     aboutBrowser.moveCursor(QTextCursor.Start)
     creditsBrowser.moveCursor(QTextCursor.Start)
     imageLabel = QLabel()
     imageLabel.setPixmap(QPixmap(image))
     titleLayout.addWidget(imageLabel)
     titleLayout.addWidget(name_versionLabel)
     titleLayout.addStretch()
     contentsLayout.addWidget(TabWidget)
     buttonLayout = QHBoxLayout()
     buttonBox = QDialogButtonBox(QDialogButtonBox.Ok)
     buttonLayout.addWidget(buttonBox)
     layout.addLayout(titleLayout)
     layout.addLayout(contentsLayout)
     layout.addLayout(buttonLayout)
     self.setLayout(layout)
     buttonBox.clicked.connect(self.accept)
     self.setMinimumSize(QSize(380, 400))
     self.setWindowTitle(self.tr('About Onkyo QT'))
Exemple #13
0
	def __init__(self,index):
		QTabWidget.__init__(self)
		lines=[]
		self.index=index

		if inp_load_file(lines,"fit"+str(self.index)+".inp")==True:
			self.tab_name=inp_search_token_value(lines, "#fit_name")
		else:
			self.tab_name=""

		self.setTabsClosable(True)
		self.setMovable(True)

		self.tmesh = fit_window_plot(self.index)
		self.addTab(self.tmesh,_("Fit error"))

		self.tmesh_real = fit_window_plot_real(self.index)
		self.addTab(self.tmesh_real,_("Experimental data"))

		self.fit_patch = fit_patch(self.index)
		self.addTab(self.fit_patch, _("Fit patch"))

		config=tab_class()
		config.init("fit"+str(self.index)+".inp",self.tab_name)
		self.addTab(config,_("Configure fit"))
class MyTabWidget(QWidget):

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

        # Initialize tab screen
        self.tabs = QTabWidget()
        self.tabs.resize(300, 200)

        tab1 = QWidget()
        tab2 = QWidget()

        # Add tabs
        self.tabs.addTab(tab1, "Tab 1")
        self.tabs.addTab(tab2, "Tab 2")

        # Populate the first tab
        button1 = QPushButton("PyQt5 button")
        tab1_layout = QVBoxLayout()
        tab1_layout.addWidget(button1)
        tab1.setLayout(tab1_layout)

        # Set the layout
        layout = QVBoxLayout()
        layout.addWidget(self.tabs)
        self.setLayout(layout)
Exemple #15
0
 def __init__(self, parent):
     self.parent = parent
     self.feuille = parent.feuille
     QTabWidget.__init__(self, parent)
     self.description = ProprietesDescription(self)
     self.addTab(self.description, "Description")
     self.statistiques = ProprietesStatistiques(self)
     self.addTab(self.statistiques, "Statistiques")
class class_config_window(QWidget):


	def init(self):
		self.setFixedSize(900, 600)
		self.setWindowIcon(QIcon(os.path.join(get_image_file_path(),"cog.png")))

		self.setWindowTitle(_("Configure (www.gpvdm.com)")) 
		

		self.main_vbox = QVBoxLayout()

		toolbar=QToolBar()
		toolbar.setIconSize(QSize(48, 48))

		spacer = QWidget()
		spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
		toolbar.addWidget(spacer)


		self.undo = QAction(QIcon(os.path.join(get_image_file_path(),"help.png")), 'Hide', self)
		self.undo.setStatusTip(_("Close"))
		self.undo.triggered.connect(self.callback_help)
		toolbar.addAction(self.undo)

		self.main_vbox.addWidget(toolbar)

		

		self.notebook = QTabWidget()

		self.notebook.setMovable(True)

		self.main_vbox.addWidget(self.notebook)

		files=["math.inp","dump.inp","thermal.inp","led.inp","config.inp"]
		description=["Math","Dump","Thermal","LED","GUI  config"]

		for i in range(0,len(files)):
			tab=tab_class()
			tab.init(files[i],description[i])
			self.notebook.addTab(tab,description[i])


		self.setLayout(self.main_vbox)
		self.win_list=windows()
		self.win_list.load()
		self.win_list.set_window(self,"config_window")

		#self.connect("delete-event", self.callback_close_window) 

		#self.hide()

	def callback_help(self,widget):
		webbrowser.open('http://www.gpvdm.com/man/index.html')

	def closeEvent(self, event):
		self.win_list.update(self,"config_window")
    def __init__(self, mainwindow):
        QTabWidget.__init__(self)
        self.mainwindow = mainwindow
        self.activeTab = False
        self.tabCloseRequested.connect(self.delTab)
        self.currentChanged.connect(self.changeTab)
        # self.setTabsClosable(True)

        self.createTabBar()
Exemple #18
0
 def __init__(self, parent):
     self.parent = parent
     self.objets = parent.objets
     QTabWidget.__init__(self, parent)
     self.affichage = ProprietesAffichage(self)
     self.addTab(self.affichage, "Affichage")
     self.infos = ProprietesInfos(self)
     self.addTab(self.infos, "Informations")
     self.avance = ProprietesAvance(self)
     self.addTab(self.avance, "Avancé")
Exemple #19
0
    def __init__(self):
        super(Window, self).__init__()
        self.setWindowTitle("Ledger visualizer")

        # Create a layout Object, attached to the window.
        layout = QVBoxLayout(self)

        self.options = Options(self)
        layout.addWidget(self.options)

        tabs = QTabWidget()
        layout.addWidget(tabs)

        graph = GraphTab(self.options)
        tabs.addTab(graph, "Time series")

        graph = AccountTab(self.options)
        tabs.addTab(graph, "Account breakdown")

        graph = BarTab(self.options)
        tabs.addTab(graph, "Timed breakdown")

        text = PieTab(self.options)
        tabs.addTab(text, "Pie charts")

        button = QPushButton("Quit", self)
        layout.addWidget(button)

        button.clicked.connect(app.quit)
Exemple #20
0
class AboutDialog(QDialog):
    def __init__(self, parent=None):
        super(AboutDialog, self).__init__(parent)
        self.create()
        
        title = QLabel()
        title.setText('Pulppy Software\nLinear Programming Software')
        title.setAlignment(Qt.AlignLeft)
        title.setStyleSheet("font-weight: bold")
        
        icon = QLabel()
        imagen = QPixmap('pulppy.ico')
        icon.setPixmap(imagen)
        
        topLayout = QHBoxLayout()
        topLayout.addWidget(icon)
        topLayout.addWidget(title)
        mainLayout = QVBoxLayout()
        mainLayout.addLayout(topLayout)
        mainLayout.addWidget(self.tabWidget)

        self.setLayout(mainLayout)
        self.setGeometry(500, 200, 350, 250)
        self.setWindowTitle('About')
        self.setWindowIcon(QIcon('pulppy.ico'))

    def create(self):
        self.tabWidget = QTabWidget()

        tab1 = QWidget()
        labelDescription = QLabel()
        labelDescription.setText("Linear Programming Software for optimizing\n"
                              "various practical problems of Operations Research.\n"
                              "\n"
                              "Repository:\n"
                              "https://github.com/bruino/pulppy\n")
        tab1hbox = QHBoxLayout()
        tab1hbox.addWidget(labelDescription)
        tab1.setLayout(tab1hbox)

        tab2 = QWidget()        
        labelAutors = QLabel()
        labelAutors.setText("+ Danert, Maldonado Jessica\n"
                              "+ Gutierrez, Mariano\n"
                              "+ Moreno, Victor Ricardo\n"
                              "+ Sarverry, Bruno Alejandro\n")
        tab2hbox = QHBoxLayout()
        tab2hbox.setContentsMargins(5, 5, 5, 5)
        tab2hbox.addWidget(labelAutors)
        tab2.setLayout(tab2hbox)

        self.tabWidget.addTab(tab1, "&About")
        self.tabWidget.addTab(tab2, "&Autors")
Exemple #21
0
    async def search_and_show_pubkey(cls, parent, app, pubkey):
        dialog = QDialog(parent)
        dialog.setWindowTitle("Informations")
        layout = QVBoxLayout(dialog)
        tabwidget = QTabWidget(dialog)
        layout.addWidget(tabwidget)

        identities = await app.identities_service.lookup(pubkey)
        for i in identities:
            user_info = cls.create(parent, app, i)
            user_info.refresh()
            tabwidget.addTab(user_info.view, i.uid)
        return await dialog_async_exec(dialog)
Exemple #22
0
    def __init__(self, parent=None):
        super(FenetreCentrale,
              self).__init__(parent)

        tabWidget = QTabWidget()
        tabWidget.addTab(ModaliteEvaluation(),"Modalite d'evaluation")
        tabWidget.addTab(GestionEleve(),"Gestion des eleves")
        #tabWidget.addTab(Essai(),"Lolilol")

        layout = QVBoxLayout()
        layout.addWidget(tabWidget)
        
        self.setLayout(layout)
 def create_tab_widget(self):
     tab_widget = QTabWidget()
     tab_widget.setStyleSheet("QTabWidget::pane {border: 0;}")
     tab_widget.setTabPosition(QTabWidget.East)
     tab_widget.setMovable(True)
     tab_widget.setDocumentMode(True)
     tabBar = tab_widget.tabBar()
     tabBar.hide()
     tabBar.setContextMenuPolicy(Qt.CustomContextMenu)
     self.addWidget(tab_widget)
     index = self.indexOf(tab_widget)
     tabBar.customContextMenuRequested['const QPoint&'].connect(
         lambda point: self.show_tab_context_menu(index, point))
     return tab_widget
Exemple #24
0
class mainWindow(QWidget):
    def __init__(self):
        super().__init__()
        # Виджет для главного таб виджета
        # Содержит вкладки для дейликов и т.д.
        self.vbox = QVBoxLayout()

        self.dailyTab = dailyTab()

        self.tab = QTabWidget()
        self.tab.addTab(self.dailyTab,'Daily events')

        self.vbox.addWidget(self.tab)
        self.setLayout(self.vbox)
Exemple #25
0
 def show_about_referentials(self, referentials):
     dialog = QDialog(self)
     layout = QVBoxLayout(dialog)
     tabwidget = QTabWidget(dialog)
     layout.addWidget(tabwidget)
     for ref in referentials:
         widget = QWidget()
         layout = QVBoxLayout(widget)
         label = QLabel()
         label.setText(self.text_referential(ref))
         layout.addWidget(label)
         tabwidget.addTab(widget, ref.translated_name())
     dialog.setWindowTitle(self.tr("Referentials"))
     dialog.exec()
Exemple #26
0
class MyTableWidget(QWidget):

    def __init__(self, parent):
        super(QWidget, self).__init__(parent)
        self.layout = QVBoxLayout(self)

        # Initialize tab screen
        self.tabs = QTabWidget()
        #  self.tabs.tabBar().hide()
        self.tabs.setTabPosition(QTabWidget.West)
        self.tab1 = QWidget()
        self.tab2 = QWidget()
        self.tabs.resize(300,200)

        # Add tabs
        self.tabs.addTab(self.tab1, QIcon('./liveSEC/icones/app.jpg'), "Tab 1")
        self.tabs.addTab(self.tab2,"Tab 2")

        # Create first tab
        self.tab1.layout = QVBoxLayout(self)
        self.pushButton1 = QPushButton("PyQt5 button")
        self.tab1.layout.addWidget(self.pushButton1)
        self.tab1.setLayout(self.tab1.layout)

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

    @pyqtSlot()
    def on_click(self):
        print("\n")
        for currentQTableWidgetItem in self.tableWidget.selectedItems():
            print(currentQTableWidgetItem.row(), currentQTableWidgetItem.column(), currentQTableWidgetItem.text())
 def __init__(self, parent=None):
     QMainWindow.__init__(self, parent)
     self.ui = Ui_ScriptEditor()
     self.ui.setupUi(self)
     #self.ui.actionExit.triggered.connect(self.exit)
     self.splitter = QSplitter(Qt.Vertical, self)
     self.setCentralWidget(self.splitter)
     self.edit_tab = QTabWidget(self.splitter)
     self.console_tab = QTabWidget(self.splitter)
     self.py_console = PythonConsole(self.console_tab)
     self.console_tab.addTab(self.py_console, "&Python console")
     self.js_console = QtQmlConsole(self.console_tab)
     self.console_tab.addTab(self.js_console, "&QtQml console")
     self.editors = []
     self.on_actionNewPython_triggered()
Exemple #28
0
    def createBottomLeftTabWidget(self):
        self.bottomLeftTabWidget = QTabWidget()
        self.bottomLeftTabWidget.setSizePolicy(QSizePolicy.Preferred,
                QSizePolicy.Ignored)

        tab1 = QWidget()
        tableWidget = QTableWidget(10, 10)

        tab1hbox = QHBoxLayout()
        tab1hbox.setContentsMargins(5, 5, 5, 5)
        tab1hbox.addWidget(tableWidget)
        tab1.setLayout(tab1hbox)

        tab2 = QWidget()
        textEdit = QTextEdit()

        textEdit.setPlainText("Twinkle, twinkle, little star,\n"
                              "How I wonder what you are.\n" 
                              "Up above the world so high,\n"
                              "Like a diamond in the sky.\n"
                              "Twinkle, twinkle, little star,\n" 
                              "How I wonder what you are!\n")

        tab2hbox = QHBoxLayout()
        tab2hbox.setContentsMargins(5, 5, 5, 5)
        tab2hbox.addWidget(textEdit)
        tab2.setLayout(tab2hbox)

        self.bottomLeftTabWidget.addTab(tab1, "&Table")
        self.bottomLeftTabWidget.addTab(tab2, "Text &Edit")
 def _createElectronicsControl(self):
     """Creates a tabbed widget of voltage clamp and current clamp controls"""
     self._electronicsTab = QTabWidget(self)
     self._electronicsTab.addTab(self._getIClampCtrlBox(), 'Current clamp')
     self._electronicsTab.addTab(self._getVClampCtrlBox(), 'Voltage clamp')
     self._electronicsDock = QDockWidget(self)
     self._electronicsDock.setWidget(self._electronicsTab)
Exemple #30
0
    def __init__(self, parent, cli_iface, iface_name):
        super(ControlPanelWindow, self).__init__(parent)
        self.setWindowTitle('SLCAN Adapter Control Panel')
        self.setAttribute(Qt.WA_DeleteOnClose)              # This is required to stop background timers!

        self._cli_iface = cli_iface
        self._iface_name = iface_name

        self._state_widget = StateWidget(self, self._cli_iface)
        self._config_widget = ConfigWidget(self, self._cli_iface)
        self._cli_widget = CLIWidget(self, self._cli_iface)

        self._tab_widget = QTabWidget(self)
        self._tab_widget.addTab(self._state_widget, get_icon('dashboard'), 'Adapter State')
        self._tab_widget.addTab(self._config_widget, get_icon('wrench'), 'Configuration')
        self._tab_widget.addTab(self._cli_widget, get_icon('terminal'), 'Command Line')

        self._status_bar = QStatusBar(self)
        self._status_bar.setSizeGripEnabled(False)

        iface_name_label = QLabel(iface_name.split('/')[-1], self)
        iface_name_label.setFont(get_monospace_font())

        layout = QVBoxLayout(self)
        layout.addWidget(iface_name_label)
        layout.addWidget(self._tab_widget)
        layout.addWidget(self._status_bar)

        left, top, right, bottom = layout.getContentsMargins()
        bottom = 0
        layout.setContentsMargins(left, top, right, bottom)

        self.setLayout(layout)
        self.resize(400, 400)
Exemple #31
0
    def __init__(self, parent):
        super(QWidget, self).__init__(parent)
        self.layout = QVBoxLayout(self)
        #self.setStyleSheet("background-color:grey")
        self.setAutoFillBackground(True)
        
        # Initialize tab screen
        self.tabs = QTabWidget()
        self.tab1 = QWidget()
        self.tab2 = QWidget()
        self.tabs.resize(300,200)
        
        # Add tabs
        self.tabs.addTab(self.tab1,"Main")
        self.tabs.addTab(self.tab2,"Config")
        
        # Create first tab
        self.tab1.layout = QGridLayout(self)
        
        # Create Load button
        self.loadButton = QPushButton("Load Gcode")
        self.loadButton.clicked.connect(self.loadGcode)
        self.tab1.layout.addWidget(self.loadButton,0,0)
        # Create Gcode File Dir textbox
        self.gcodeDirTextBox = QLabel("Load Gcode file")
        self.gcodeDirTextBox.setAlignment(Qt.Qt.AlignCenter)
        self.tab1.layout.addWidget(self.gcodeDirTextBox,0,1,1,2)
        
        # Create Connect button
        self.connectButton = QPushButton("Connect")
        self.tab1.layout.addWidget(self.connectButton,1,0)
        self.connectButton.clicked.connect(self.connect)
        # Create Print button
        self.Print = QPushButton("Print")
        self.tab1.layout.addWidget(self.Print,1,1)
        self.Print.clicked.connect(self.machinePrint)
        
        #create pause button
        self.pauseButton = QPushButton("Pause")
        self.tab1.layout.addWidget(self.pauseButton,1,2)
        self.pauseButton.clicked.connect(self.pause)
#create machine group box
        hBox = QGridLayout()
        groupBox = QGroupBox()
#create input command for both machine
        #both input group box
        generalInputGroupBox = QGroupBox("Send To Both")
        generalInputGroupBoxLayout = QGridLayout()
        #command input box
        self.generalInputCommandBox = QLineEdit("SEND TO BOTH")
        #Send button
        generalInputSendButton = QPushButton("SEND")
        generalInputSendButton.clicked.connect(self.sendToALL)

        generalInputGroupBoxLayout.addWidget(self.generalInputCommandBox,0,0,1,2)
        generalInputGroupBoxLayout.addWidget(generalInputSendButton,0,2)
        generalInputGroupBox.setLayout(generalInputGroupBoxLayout)

#create machine one group
        groupBox1 = QGroupBox("Machine One")
        hBox1 = QGridLayout()
        #create machine one port8
        self.portOneButton = QLineEdit("COM7")
        self.portOne = "COM7"
        self.portOneButton.textChanged.connect(self.updatePortName)
        #create machine one baudrate
        baudrateOneButton = QLineEdit("115200")
        self.baudrateOne = 115200
        #create machine one send comman box
        self.oneInputCommandBox = QLineEdit("SEND TO ONE")
        oneInputSendButton = QPushButton("SEND")
        oneInputSendButton.clicked.connect(self.sendToOne)

        hBox1.addWidget(self.portOneButton,0,0)
        hBox1.addWidget(baudrateOneButton,0,1)
        hBox1.addWidget(self.oneInputCommandBox,1,0,1,2)
        hBox1.addWidget(oneInputSendButton,1,3)
        groupBox1.setLayout(hBox1)
#create machine two group
        groupBox2 = QGroupBox("Machine Two")
        hBox2 = QGridLayout()
        #create machine two port
        self.portTwoButton = QLineEdit("COM8")
        self.portTwo = "COM8"
        self.portTwoButton.textChanged.connect(self.updatePortName)
        
        #create machine two baudrate
        baudrateTwoButton = QLineEdit("115200")
        self.baudrateTwo = 115200
        #create machine one send comman box
        self.twoInputCommandBox = QLineEdit("SEND TO TWO")
        twoInputSendButton = QPushButton("SEND")
        twoInputSendButton.clicked.connect(self.sendToTwo)


        hBox2.addWidget(self.portTwoButton,0,0)
        hBox2.addWidget(baudrateTwoButton,0,1)
        hBox2.addWidget(self.twoInputCommandBox,1,0,1,2)
        hBox2.addWidget(twoInputSendButton,1,3)
        groupBox2.setLayout(hBox2)


        hBox.addWidget(generalInputGroupBox,0,0,1,2)
        hBox.addWidget(groupBox1,1,0)
        hBox.addWidget(groupBox2,1,1)
        groupBox.setLayout(hBox)
        self.tab1.layout.addWidget(groupBox,2,0,1,3)
        #################
        self.tab1.setLayout(self.tab1.layout)
        
        # Add tabs to widget
        self.layout.addWidget(self.tabs)
        self.setLayout(self.layout)
Exemple #32
0
    def __init__(self):
        super(QWidget, self).__init__()

        globalFont = QFont("Times New Roman", 11)
        globalFont.setWeight(18)
        QApplication.setFont(globalFont)

        # Creating tabs and layouts
        self.layout = QVBoxLayout(self)
        self.Hlayout = QHBoxLayout(self)
        self.HDBlayout = QVBoxLayout(self)
        self.tabs = QTabWidget()
        self.MainTab = QWidget()
        self.DBTab = QWidget()
        self.tabs.addTab(self.MainTab, "Translate")
        self.tabs.addTab(self.DBTab, "Saved Words")

        self.MainTab.layout = QVBoxLayout(self)
        self.MainTab.layout.addLayout(self.Hlayout)
        self.DBTab.layout = QGridLayout()

        # Defining QLabels
        self.insertionBox = QLineEdit()
        self.romajiBox = QLabel()
        self.romajiBox.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self.katakanaBox = QLabel()
        self.katakanaBox.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self.hiraganaBox = QLabel()
        self.hiraganaBox.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self.furiganaBox = QLabel()
        self.furiganaBox.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self.entriesBox = QLabel()
        self.entriesBox.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self.entriesBox.setWordWrap(True)
        self.charsBox = QLabel()
        self.charsBox.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self.charsBox.setWordWrap(True)

        recordFont = QFont("Times New Roman", 15)
        recordFont.setWeight(18)
        self.romajiLabel = QLabel("Romaji")
        self.romajiLabel.setFont(recordFont)
        self.katakanaLabel = QLabel("Katakana")
        self.katakanaLabel.setFont(recordFont)
        self.hiraganaLabel = QLabel("Hiragana")
        self.hiraganaLabel.setFont(recordFont)
        self.furiganaLabel = QLabel("Furigana")
        self.furiganaLabel.setFont(recordFont)
        self.entriesLabel = QLabel("Entries")
        self.entriesLabel.setFont(recordFont)
        self.charsLabel = QLabel("Characters")
        self.charsLabel.setFont(recordFont)
        self.romajiLabelDB = QLabel("Romaji")
        self.romajiLabelDB.setFont(recordFont)
        self.katakanaLabelDB = QLabel("Katakana")
        self.katakanaLabelDB.setFont(recordFont)
        self.hiraganaLabelDB = QLabel("Hiragana")
        self.hiraganaLabelDB.setFont(recordFont)
        self.furiganaLabelDB = QLabel("Furigana")
        self.furiganaLabelDB.setFont(recordFont)
        self.entriesLabelDB = QLabel("Entries")
        self.entriesLabelDB.setFont(recordFont)
        self.charsLabelDB = QLabel("Characters")
        self.charsLabelDB.setFont(recordFont)

        self.romajiBoxDB = QLabel()
        self.romajiBoxDB.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self.katakanaBoxDB = QLabel()
        self.katakanaBoxDB.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self.hiraganaBoxDB = QLabel()
        self.hiraganaBoxDB.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self.furiganaBoxDB = QLabel()
        self.furiganaBoxDB.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self.entriesBoxDB = QLabel()
        self.entriesBoxDB.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self.entriesBoxDB.setWordWrap(True)
        self.charsBoxDB = QLabel()
        self.charsBoxDB.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self.charsBoxDB.setWordWrap(True)

        # Globally accessible text from insertionBox in MainTab
        global text
        text = self.insertionBox.text

        # For switching tables in DBTab
        self.tableDropDown = QComboBox()
        self.tableDropDown.setDuplicatesEnabled(False)
        for item in getTables(self.con):
            self.tableDropDown.addItem(repr(item).strip("('',)"))
        self.DBTab.layout.addWidget(self.tableDropDown)

        # List of saved words in selected table in DBTab
        self.listWords = QListWidget()
        self.listWords.setFixedWidth(145)
        self.listWords.itemSelectionChanged.connect(self.selectionView)
        self.DBTab.layout.addWidget(self.listWords)
        self.listWordsAdd()
        self.tableDropDown.currentTextChanged.connect(
            lambda: self.listWordsAdd())

        # Adding widgets to tab layouts
        self.MainTab.layout.addWidget(self.insertionBox)
        self.MainTab.layout.addWidget(self.romajiLabel)
        self.MainTab.layout.addWidget(self.romajiBox)
        self.MainTab.layout.addWidget(self.katakanaLabel)
        self.MainTab.layout.addWidget(self.katakanaBox)
        self.MainTab.layout.addWidget(self.hiraganaLabel)
        self.MainTab.layout.addWidget(self.hiraganaBox)
        self.MainTab.layout.addWidget(self.furiganaLabel)
        self.MainTab.layout.addWidget(self.furiganaBox)
        self.MainTab.layout.addWidget(self.entriesLabel)
        self.MainTab.layout.addWidget(self.entriesBox)
        self.MainTab.layout.addWidget(self.charsLabel)
        self.MainTab.layout.addWidget(self.charsBox)

        self.DBTab.layout.addWidget(self.entriesLabelDB, 0, 1)
        self.DBTab.layout.addWidget(self.entriesBoxDB, 1, 1)
        self.DBTab.layout.addWidget(self.katakanaLabelDB, 2, 1)
        self.DBTab.layout.addWidget(self.katakanaBoxDB, 3, 1)
        self.DBTab.layout.addWidget(self.hiraganaLabelDB, 4, 1)
        self.DBTab.layout.addWidget(self.hiraganaBoxDB, 5, 1)
        self.DBTab.layout.addWidget(self.furiganaLabelDB, 6, 1)
        self.DBTab.layout.addWidget(self.furiganaBoxDB, 7, 1)
        self.DBTab.layout.addWidget(self.romajiLabelDB, 8, 1)
        self.DBTab.layout.addWidget(self.romajiBoxDB, 9, 1)
        self.DBTab.layout.addWidget(self.charsLabelDB, 10, 1)
        self.DBTab.layout.addWidget(self.charsBoxDB, 11, 1)

        # Creating buttons, connecting them to functions
        newTableButton = QPushButton("New List", self)
        newTableButton.setFixedWidth(145)
        self.DBTab.layout.addWidget(newTableButton)
        newTableButton.clicked.connect(self.newTableButtonClicked)

        deleteButton = QPushButton("Delete", self)
        deleteButton.setFixedWidth(145)
        self.DBTab.layout.addWidget(deleteButton)
        deleteButton.clicked.connect(self.deleteItemClicked)

        deleteTableButton = QPushButton("Delete List", self)
        deleteTableButton.setFixedWidth(145)
        self.DBTab.layout.addWidget(deleteTableButton)
        deleteTableButton.clicked.connect(self.deleteTableClicked)

        exportButton = QPushButton("Export to CSV", self)
        exportButton.setFixedWidth(145)
        self.DBTab.layout.addWidget(exportButton)
        exportButton.clicked.connect(self.clickExportCSV)

        translationButton = QPushButton("Translate", self)
        translationButton.setFixedWidth(145)

        saveButton = QPushButton("Save Word", self)
        saveButton.setFixedWidth(145)

        self.Hlayout.addWidget(translationButton)
        self.Hlayout.addWidget(saveButton)
        translationButton.clicked.connect(self.translationButtonClicked)
        saveButton.clicked.connect(self.saveButtonClicked)

        # Window setup
        self.widget = QWidget()
        self.widget.setWindowTitle("Japanese Lookup Tool")

        self.MainTab.setLayout(self.MainTab.layout)
        self.DBTab.setLayout(self.DBTab.layout)
        self.layout.addWidget(self.tabs)
        self.widget.setLayout(self.layout)
        self.widget.setMinimumSize(400, 700)
        self.widget.show()
Exemple #33
0
class Window(QMainWindow):
    sys.excepthook = new_excepthook

    con = connectDB()

    Rtext, Ktext, Htext, Ftext = [None for _ in range(4)]

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

        globalFont = QFont("Times New Roman", 11)
        globalFont.setWeight(18)
        QApplication.setFont(globalFont)

        # Creating tabs and layouts
        self.layout = QVBoxLayout(self)
        self.Hlayout = QHBoxLayout(self)
        self.HDBlayout = QVBoxLayout(self)
        self.tabs = QTabWidget()
        self.MainTab = QWidget()
        self.DBTab = QWidget()
        self.tabs.addTab(self.MainTab, "Translate")
        self.tabs.addTab(self.DBTab, "Saved Words")

        self.MainTab.layout = QVBoxLayout(self)
        self.MainTab.layout.addLayout(self.Hlayout)
        self.DBTab.layout = QGridLayout()

        # Defining QLabels
        self.insertionBox = QLineEdit()
        self.romajiBox = QLabel()
        self.romajiBox.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self.katakanaBox = QLabel()
        self.katakanaBox.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self.hiraganaBox = QLabel()
        self.hiraganaBox.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self.furiganaBox = QLabel()
        self.furiganaBox.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self.entriesBox = QLabel()
        self.entriesBox.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self.entriesBox.setWordWrap(True)
        self.charsBox = QLabel()
        self.charsBox.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self.charsBox.setWordWrap(True)

        recordFont = QFont("Times New Roman", 15)
        recordFont.setWeight(18)
        self.romajiLabel = QLabel("Romaji")
        self.romajiLabel.setFont(recordFont)
        self.katakanaLabel = QLabel("Katakana")
        self.katakanaLabel.setFont(recordFont)
        self.hiraganaLabel = QLabel("Hiragana")
        self.hiraganaLabel.setFont(recordFont)
        self.furiganaLabel = QLabel("Furigana")
        self.furiganaLabel.setFont(recordFont)
        self.entriesLabel = QLabel("Entries")
        self.entriesLabel.setFont(recordFont)
        self.charsLabel = QLabel("Characters")
        self.charsLabel.setFont(recordFont)
        self.romajiLabelDB = QLabel("Romaji")
        self.romajiLabelDB.setFont(recordFont)
        self.katakanaLabelDB = QLabel("Katakana")
        self.katakanaLabelDB.setFont(recordFont)
        self.hiraganaLabelDB = QLabel("Hiragana")
        self.hiraganaLabelDB.setFont(recordFont)
        self.furiganaLabelDB = QLabel("Furigana")
        self.furiganaLabelDB.setFont(recordFont)
        self.entriesLabelDB = QLabel("Entries")
        self.entriesLabelDB.setFont(recordFont)
        self.charsLabelDB = QLabel("Characters")
        self.charsLabelDB.setFont(recordFont)

        self.romajiBoxDB = QLabel()
        self.romajiBoxDB.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self.katakanaBoxDB = QLabel()
        self.katakanaBoxDB.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self.hiraganaBoxDB = QLabel()
        self.hiraganaBoxDB.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self.furiganaBoxDB = QLabel()
        self.furiganaBoxDB.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self.entriesBoxDB = QLabel()
        self.entriesBoxDB.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self.entriesBoxDB.setWordWrap(True)
        self.charsBoxDB = QLabel()
        self.charsBoxDB.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self.charsBoxDB.setWordWrap(True)

        # Globally accessible text from insertionBox in MainTab
        global text
        text = self.insertionBox.text

        # For switching tables in DBTab
        self.tableDropDown = QComboBox()
        self.tableDropDown.setDuplicatesEnabled(False)
        for item in getTables(self.con):
            self.tableDropDown.addItem(repr(item).strip("('',)"))
        self.DBTab.layout.addWidget(self.tableDropDown)

        # List of saved words in selected table in DBTab
        self.listWords = QListWidget()
        self.listWords.setFixedWidth(145)
        self.listWords.itemSelectionChanged.connect(self.selectionView)
        self.DBTab.layout.addWidget(self.listWords)
        self.listWordsAdd()
        self.tableDropDown.currentTextChanged.connect(
            lambda: self.listWordsAdd())

        # Adding widgets to tab layouts
        self.MainTab.layout.addWidget(self.insertionBox)
        self.MainTab.layout.addWidget(self.romajiLabel)
        self.MainTab.layout.addWidget(self.romajiBox)
        self.MainTab.layout.addWidget(self.katakanaLabel)
        self.MainTab.layout.addWidget(self.katakanaBox)
        self.MainTab.layout.addWidget(self.hiraganaLabel)
        self.MainTab.layout.addWidget(self.hiraganaBox)
        self.MainTab.layout.addWidget(self.furiganaLabel)
        self.MainTab.layout.addWidget(self.furiganaBox)
        self.MainTab.layout.addWidget(self.entriesLabel)
        self.MainTab.layout.addWidget(self.entriesBox)
        self.MainTab.layout.addWidget(self.charsLabel)
        self.MainTab.layout.addWidget(self.charsBox)

        self.DBTab.layout.addWidget(self.entriesLabelDB, 0, 1)
        self.DBTab.layout.addWidget(self.entriesBoxDB, 1, 1)
        self.DBTab.layout.addWidget(self.katakanaLabelDB, 2, 1)
        self.DBTab.layout.addWidget(self.katakanaBoxDB, 3, 1)
        self.DBTab.layout.addWidget(self.hiraganaLabelDB, 4, 1)
        self.DBTab.layout.addWidget(self.hiraganaBoxDB, 5, 1)
        self.DBTab.layout.addWidget(self.furiganaLabelDB, 6, 1)
        self.DBTab.layout.addWidget(self.furiganaBoxDB, 7, 1)
        self.DBTab.layout.addWidget(self.romajiLabelDB, 8, 1)
        self.DBTab.layout.addWidget(self.romajiBoxDB, 9, 1)
        self.DBTab.layout.addWidget(self.charsLabelDB, 10, 1)
        self.DBTab.layout.addWidget(self.charsBoxDB, 11, 1)

        # Creating buttons, connecting them to functions
        newTableButton = QPushButton("New List", self)
        newTableButton.setFixedWidth(145)
        self.DBTab.layout.addWidget(newTableButton)
        newTableButton.clicked.connect(self.newTableButtonClicked)

        deleteButton = QPushButton("Delete", self)
        deleteButton.setFixedWidth(145)
        self.DBTab.layout.addWidget(deleteButton)
        deleteButton.clicked.connect(self.deleteItemClicked)

        deleteTableButton = QPushButton("Delete List", self)
        deleteTableButton.setFixedWidth(145)
        self.DBTab.layout.addWidget(deleteTableButton)
        deleteTableButton.clicked.connect(self.deleteTableClicked)

        exportButton = QPushButton("Export to CSV", self)
        exportButton.setFixedWidth(145)
        self.DBTab.layout.addWidget(exportButton)
        exportButton.clicked.connect(self.clickExportCSV)

        translationButton = QPushButton("Translate", self)
        translationButton.setFixedWidth(145)

        saveButton = QPushButton("Save Word", self)
        saveButton.setFixedWidth(145)

        self.Hlayout.addWidget(translationButton)
        self.Hlayout.addWidget(saveButton)
        translationButton.clicked.connect(self.translationButtonClicked)
        saveButton.clicked.connect(self.saveButtonClicked)

        # Window setup
        self.widget = QWidget()
        self.widget.setWindowTitle("Japanese Lookup Tool")

        self.MainTab.setLayout(self.MainTab.layout)
        self.DBTab.setLayout(self.DBTab.layout)
        self.layout.addWidget(self.tabs)
        self.widget.setLayout(self.layout)
        self.widget.setMinimumSize(400, 700)
        self.widget.show()

    def translationButtonClicked(self, text):
        if self.insertionBox.text() == "":
            msg = QMessageBox()
            msg.setWindowTitle("Error")
            msg.setText("There is no word to translate!")
            msg.exec_()
        else:
            jmd = Jamdict()
            text = self.insertionBox.text()

            Window.Rtext = toRomaji(text)
            Window.Ktext = toKatakana(text)
            Window.Htext = toHiragana(text)
            result = jmd.lookup(text)

            text = toTokensDictionary(text)

            separater = ""
            Window.Ftext = toFurigana(text)
            Window.Ftext = separater.join(Window.Ftext)

            if result == None:
                result = jmd.lookup(Window.Ktext)
            if result == None:
                result = jmd.lookup(Window.Htext)

            Window.Etext = repr(result.entries).strip("[]")
            Window.Ctext = repr(result.chars).strip("[]")

            self.romajiBox.setText(Window.Rtext)
            self.katakanaBox.setText(Window.Ktext)
            self.hiraganaBox.setText(Window.Htext)
            self.furiganaBox.setText(Window.Ftext)
            self.entriesBox.setText(Window.Etext)
            self.charsBox.setText(Window.Ctext)

            return Window.Rtext, Window.Ktext, Window.Htext, Window.Ftext

    def saveButtonClicked(self):
        if len(getTables(self.con)) == 0:
            msg = QMessageBox()
            msg.setText("No lists to save to!")
            msg.exec_()
            return
        if Window.Rtext:
            tables = getTables(self.con)
            tables = [t[0] for t in tables]
            table, ok = QInputDialog.getItem(self, "List option",
                                             "Choose list to save to:", tables,
                                             0, False)
            if ok and table:
                msg = QMessageBox()
                insertWord(self.con, table, self.Rtext, self.Ktext, self.Htext,
                           self.Ftext, self.Etext, self.Ctext)
                msg.setText("Word saved to " + table)
                msg.exec_()
                if self.currentTable().strip("''") == table:
                    self.listWords.addItem(repr(self.Rtext).strip("''"))
        else:
            msg = QMessageBox()
            msg.setText("There is no translated word to save!")
            msg.exec_()

    def newTableButtonClicked(self):
        nameNewTable, ok = QInputDialog.getText(self, 'New list',
                                                'Enter new list name:')
        if self.tableDropDown.findText(nameNewTable) == -1:
            self.tableDropDown.addItem(nameNewTable)
            newTable(self.con, nameNewTable)
        else:
            msg = QMessageBox()
            msg.setWindowTitle("Error")
            msg.setText("Error creating list")
            msg.exec_()

    def deleteItemClicked(self):
        if self.listWords.selectedItems() != 0:
            for item in self.listWords.selectedItems():
                deleteWord(self.con,
                           self.listWords.currentItem().text(),
                           self.currentTable())
                self.listWords.takeItem(self.listWords.row(item))
        else:
            msg = QMessageBox()
            msg.setWindowTitle("Error")
            msg.setText("There is no word selected to delete!")
            msg.exec_()

    def deleteTableClicked(self):
        table = self.currentTable()
        confirm = QMessageBox.question(
            self, "Confirmation",
            "Are you sure you want to delete " + table + "?", QMessageBox.Yes,
            QMessageBox.Cancel)
        if confirm == QMessageBox.Yes:
            index = self.tableDropDown.findText(table.strip("''"))
            self.tableDropDown.removeItem(index)
            dropTable(self.con, table)

    def updateDBTabList(self, input):
        if type(input) is list:
            self.romajiBoxDB.setText(input[0])
            self.katakanaBoxDB.setText(input[1])
            self.hiraganaBoxDB.setText(input[2])
            self.furiganaBoxDB.setText(input[3])
            self.entriesBoxDB.setText(input[4])
            self.charsBoxDB.setText(input[5])
        else:
            self.romajiBoxDB.setText(input)
            self.katakanaBoxDB.setText(input)
            self.hiraganaBoxDB.setText(input)
            self.furiganaBoxDB.setText(input)
            self.entriesBoxDB.setText(input)
            self.charsBoxDB.setText(input)

    def selectionView(self):
        if self.listWords.selectedItems() != 0 and self.listWords.currentItem(
        ) is not None and self.currentTable() is not None:
            list = selectWord(self.con,
                              self.listWords.currentItem().text(),
                              self.currentTable())
            if list:
                self.updateDBTabList(list)

    def currentTable(self):
        if self.tableDropDown.currentText() is not None:
            return repr(self.tableDropDown.currentText())
        else:
            msg = QMessageBox()
            msg.setWindowTitle("Error")
            msg.setText("Create a list to be able to save words")
            msg.exec_()
            return None

    def listWordsAdd(self):
        self.updateDBTabList("")
        if len(getTables(self.con)) != 0 and self.currentTable() is not None:
            wordList = listTable(self.con, self.currentTable())
            self.listWords.clear()
            for word in wordList:
                self.listWords.addItem(repr(word).strip("'()',"))

    def clickExportCSV(self):
        exportCSV(self.con, self.currentTable())
        msg = QMessageBox()
        msg.setWindowTitle("Export successful")
        msg.setText("Exported as " + self.currentTable().strip("''") + ".csv")
        msg.exec_()
Exemple #34
0
    def __init__(self, statusBar):
        super().__init__()

        # store active image ID
        self.active_image_id = str()

        # Saves multiple duplicate windows references:
        self.duplicateRefs = {}

        # Gets status bar from QMainWindow:
        self.statusBar = statusBar

        # Initializes all window elements:
        self.folderField = QLineEdit()
        self.folderButton = QPushButton()
        self.folderTreeCheckbox = QCheckBox("Include sub-folders")
        self.processButton = QPushButton("Process media files")
        self.duplicateButton = QPushButton("Find duplicates")
        self.reindexButton = QPushButton("Reindex database files")
        self.tableTabs = QTabWidget()
        # init main images list table
        self.imageListTable = QTableWidget()
        # set main images list table fields unchanged
        self.imageListTable.setEditTriggers(QTableWidget.NoEditTriggers)
        # init main videos list table
        self.videoListTable = QTableWidget()
        # set main videos list table fields unchanged
        self.videoListTable.setEditTriggers(QTableWidget.NoEditTriggers)

        # set up image fields and elements
        self.imageField = QLabel()
        self.imageNameField = QLabel()
        self.imageParamsField = QLabel()

        self.imageCopyButton = QPushButton("Copy image")
        self.imageCopyButton.setIcon(QIcon("gui/static/icon_copy.png"))
        self.imageCopyButton.clicked.connect(self.copy_image_path)
        self.imageViewButton = QPushButton("View image")
        self.imageViewButton.setIcon(QIcon("gui/static/icon_open_image.svg"))
        self.imageViewButton.clicked.connect(self.open_image_file)
        self.imageOpenDirButton = QPushButton("Open dir")
        self.imageOpenDirButton.setIcon(
            QIcon("gui/static/icon_open_folder.svg"))
        self.imageOpenDirButton.clicked.connect(self.open_image_path)
        self.imageDeleteButton = QPushButton("Delete")
        self.imageDeleteButton.setIcon(
            QIcon("gui/static/icon_delete_file.png"))
        self.imageDeleteButton.clicked.connect(self.delete_image)

        self.videoField = QVideoWidget()
        self.videoPlayer = QMediaPlayer()

        # Adjusts settings for the window elements:
        self.folderField.setDisabled(True)

        self.folderButton.setIcon(QIcon("gui/static/icon_process_folder.png"))
        self.folderButton.clicked.connect(self.set_folder)

        self.processButton.clicked.connect(self.process_files)
        self.processButton.setFixedWidth(160)
        self.processButton.setDisabled(True)

        self.duplicateButton.clicked.connect(self.find_duplicates)
        self.duplicateButton.setFixedWidth(160)

        self.reindexButton.clicked.connect(self.reindex_db_data)
        self.reindexButton.setFixedWidth(160)

        # prepare tables for images and videos
        self.imagesTab = self.tableTabs.insertTab(0, self.imageListTable,
                                                  "Images")
        self.videosTab = self.tableTabs.insertTab(1, self.videoListTable,
                                                  "Videos")

        # images list table setup
        self.imageListTable.setColumnCount(len(self.COLUMNS_DICT.keys()))
        self.imageListTable.setHorizontalHeaderLabels(self.COLUMNS_DICT.keys())
        self.imageListTable.verticalHeader().setVisible(False)
        self.imageListTable.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.imageListTable.setSortingEnabled(True)
        self.imageListTable.cellClicked.connect(self.show_image)

        # videos list table setup
        self.videoListTable.setColumnCount(len(self.COLUMNS_DICT.keys()))
        self.videoListTable.setHorizontalHeaderLabels(self.COLUMNS_DICT.keys())
        self.videoListTable.verticalHeader().setVisible(False)
        self.videoListTable.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.videoListTable.setSortingEnabled(True)
        self.videoListTable.cellClicked.connect(self.show_video)

        # set images and videos duplicates columns width
        self.set_columns_width()

        # Places the window elements on the window:
        # Top-left cell of main grid box:
        subGridBox = QWidget()
        subGrid = QGridLayout()
        subGrid.addWidget(self.folderField, 0, 0)
        subGrid.addWidget(self.folderButton, 0, 1)
        subGrid.addWidget(self.folderTreeCheckbox, 1, 0)
        subGrid.addWidget(self.processButton, 2, 0, 1, 2, Qt.AlignCenter)
        subGrid.addWidget(self.duplicateButton, 3, 0, 1, 2, Qt.AlignCenter)
        subGrid.addWidget(self.reindexButton, 4, 0, 1, 2, Qt.AlignCenter)
        subGridBox.setLayout(subGrid)

        # image data grid box
        imageGridBox = QWidget()
        imageGrid = QGridLayout()
        imageGrid.addWidget(self.imageField, 0, 0, 1, 4, Qt.AlignCenter)
        # add image buttons
        imageGrid.addWidget(self.imageCopyButton, 1, 0, 1, 1)
        imageGrid.addWidget(self.imageViewButton, 1, 1, 1, 1)
        imageGrid.addWidget(self.imageOpenDirButton, 1, 2, 1, 1)
        imageGrid.addWidget(self.imageDeleteButton, 1, 3, 1, 1)

        imageGrid.addWidget(self.imageNameField, 2, 0, 1, 1)
        imageGrid.addWidget(self.imageParamsField, 2, 3, 1, 1)
        imageGridBox.setLayout(imageGrid)

        # Main grid box:
        self.mainGrid = QGridLayout()
        self.mainGrid.addWidget(subGridBox, 0, 0)
        self.mainGrid.addWidget(self.tableTabs, 1, 0)
        self.mainGrid.addWidget(imageGridBox, 1, 1)
        self.mainGrid.addWidget(self.videoField, 0, 1, 2, 1)
        self.mainGrid.setColumnMinimumWidth(0, 400)
        self.mainGrid.setRowMinimumHeight(1, 600)
        self.mainGrid.setColumnStretch(1, 1)

        self.setLayout(self.mainGrid)

        # Creates a QThread instance:
        self.thread = ProcessingThread(self.folderField, self.imageListTable,
                                       self.videoListTable,
                                       self.folderTreeCheckbox)

        self.thread.finishedTrigger.connect(self.finish_thread)

        # filling table while first run
        self.reindex_db_data()
        # hide image interface
        self.hide_active_image()
Exemple #35
0
class App(QMainWindow):
    def __init__(self):
        super().__init__()
        self.player = QMediaPlayer()
        self.playlist = QMediaPlaylist()
        self.playlist.setPlaybackMode(QMediaPlaylist.Sequential)
        self.title = 'JPR Reader GUI version2'
        self.left = 50
        self.top = 100
        self.width = 1200
        self.height = 800
        self.fileReady = False
        self.tableRow = 5
        self.tableCol = 15
        self.row = 2
        self.audiolist = []
        self.configFile = ".//configurationFile.xlsx"
        self.dict = {
            'num': None,
            'partner': None,
            'parcel': None,
            'exception': None,
            'box': None
        }
        self.initUI()

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        # menu
        menubar = self.menuBar()
        filemenu = menubar.addMenu('File')
        fileAct = QAction('Open File', self)
        fileAct.setShortcut('Ctrl+O')
        filemenu.addAction(fileAct)
        fileAct.triggered.connect(self.openFileNameDialog)

        # status_bar
        self.statusbar = self.statusBar()

        # tabs
        self.tabs = QTabWidget()
        self.tab1 = QWidget(self)
        self.tab2 = QWidget(self)
        self.tabs.addTab(self.tab1, "조작")
        self.tabs.addTab(self.tab2, "설정")
        self.setCentralWidget(self.tabs)

        # tab1 gui
        self.ButtonGroupBox = self.createButtonGroupBox()
        self.createLogTable()
        self.tab1.layout = QVBoxLayout()
        self.tab1.layout.addWidget(self.ButtonGroupBox)
        self.tab1.layout.addWidget(self.logTable)
        self.tab1.setLayout(self.tab1.layout)

        # tab2 gui
        self.explanation = QLabel()
        self.explanation.setText("""<<< JPR reader 설정 테이블 >>>    
            이곳에서 JPR reader가 읽어주는 항목과 아이템을 설정할 수 있습니다.
            항목과 아이템의 설정 방법은 셀을 더블 클릭한 후 이름을 입력하는 방식으로진행됩니다.
            그 후 떠오른 파일 탐색기에서 지정할 mp3파일을 선택해 주세요.
            설정의 확인은 셀의 색으로 확인 가능합니다. 지정이 완료된 항목은 노란색, 아이템은 하늘색으로 표시됩니다.
            지정이 되지 않은 셀은 빨간색으로 표시됩니다. 행과 열 버튼으로 테이블의 크기를 조절할 수 있으며
            초기화시 모든 설정은 사라지며 테이블은 5by5로 초기화 됩니다.

            <<<주의사항>>>
            1. 첫번째 열은 반드시 항목을 입력해 주세요.
            2. 입력되는 이름은 엑셀파일에서 표현된 명칭과 완벽히 일치해야 합니다.(엔터나 스페이스, 오타 주의!)
            3. 초기화를 누르면 처음부터 모든 항목과 아이템을 지정해야 합니다.
            4. 엑셀 파일의 ()나 /을 통해 구분한 아이템은 따로 입력해 주세요.
            5. 사용하는 엑셀파일의 구조를 유지해 주세요. 변경시 프로그램의 수정이 필요할 수 있습니다.(예: '박스'항목은 항상 있을 것으로 간주됩니다.)

            제작자 정보: 김현우([email protected])""")
        self.explanation.setAlignment(Qt.AlignCenter)
        self.createConfigTable()
        self.createHorizontalButtons2()
        self.tab2.layout = QVBoxLayout()
        self.tab2.layout.addWidget(self.explanation)
        self.tab2.layout.addWidget(self.configTable)
        self.tab2.layout.addWidget(self.horizontalButtons2)
        self.tab2.setLayout(self.tab2.layout)

        # Show widget
        self.show()

    def openFileNameDialog(self):
        fileName, _ = QFileDialog.getOpenFileName(self, "Open file", "",
                                                  "All Files (*)")
        if not fileName:
            self.statusbar.showMessage('Fail to load file...')

        else:
            self.wb = load_workbook(fileName.strip())
            self.ws = self.wb.active
            self.fileReady = True
            self.row = 2
            self.statusbar.showMessage('succeed to load file...')
            self.logTable.clear()

            # set logTable's horizontal header
            self.logTable.setHorizontalHeaderItem(0, QTableWidgetItem("포장순번"))
            self.logTable.setHorizontalHeaderItem(1, QTableWidgetItem("거래처명"))
            self.logTable.setHorizontalHeaderItem(2, QTableWidgetItem("배송센터"))
            self.logTable.setHorizontalHeaderItem(3, QTableWidgetItem("특이사항"))
            self.logTable.setHorizontalHeaderItem(4, QTableWidgetItem("박스"))

            # initialize dictionary
            self.dict = {
                'num': None,
                'partner': None,
                'parcel': None,
                'exception': None,
                'box': None
            }
            col = 6
            num = 0
            header = str(self.ws.cell(row=1, column=col + 1).value).strip()
            while header != 'None':
                self.dict[header] = None
                col = col + 1
                num = num + 1
                header = str(self.ws.cell(row=1, column=col + 1).value).strip()

            self.tableCol = 5 + num
            self.logTable.setColumnCount(self.tableCol)

            for c in range(5, self.tableCol):
                self.logTable.setHorizontalHeaderItem(
                    c, QTableWidgetItem(list(self.dict.keys())[c]))

    def createButtonGroupBox(self):
        buttonGroupBox = QGroupBox("Controller")
        vLayout = QVBoxLayout()

        pre_button = QPushButton('w', self)
        pre_button.clicked.connect(self.pre_click)
        pre_button.setIcon(QIcon('.\\img\\up-arrow.png'))
        pre_button.setIconSize(QSize(600, 100))
        pre_button.setShortcut('w')
        vLayout.addWidget(pre_button)

        hBottensWidget = self.createHButtons()
        vLayout.addWidget(hBottensWidget)

        next_button = QPushButton('x', self)
        next_button.clicked.connect(self.next_click)
        next_button.setIcon(QIcon('.\\img\\down-arrow.png'))
        next_button.setIconSize(QSize(600, 100))
        next_button.setShortcut('x')
        vLayout.addWidget(next_button)

        buttonGroupBox.setLayout(vLayout)

        return buttonGroupBox

    def createHButtons(self):
        hBottensWidget = QWidget()
        hLayout = QHBoxLayout()

        back_button = QPushButton('a', self)
        back_button.clicked.connect(self.back_click)
        back_button.setIcon(QIcon('.\\img\\left-arrow.png'))
        back_button.setIconSize(QSize(200, 150))
        back_button.setShortcut('a')
        hLayout.addWidget(back_button)

        cur_button = QPushButton('s', self)
        cur_button.clicked.connect(self.cur_click)
        cur_button.setIcon(QIcon('.\\img\\reload.png'))
        cur_button.setIconSize(QSize(200, 150))
        cur_button.setShortcut('s')
        hLayout.addWidget(cur_button)

        forward_button = QPushButton('d', self)
        forward_button.clicked.connect(self.forward_click)
        forward_button.setIcon(QIcon('.\\img\\right-arrow.png'))
        forward_button.setIconSize(QSize(200, 150))
        forward_button.setShortcut('d')
        hLayout.addWidget(forward_button)

        hBottensWidget.setLayout(hLayout)

        return hBottensWidget

    def createHorizontalButtons2(self):
        self.horizontalButtons2 = QGroupBox("설정 변경")
        layout = QHBoxLayout()

        plusRowButton = QPushButton('행+', self)
        plusRowButton.clicked.connect(self.plus_row)
        layout.addWidget(plusRowButton)

        plusColButton = QPushButton('열+', self)
        plusColButton.clicked.connect(self.plus_col)
        layout.addWidget(plusColButton)

        init_button = QPushButton('초기화', self)
        init_button.clicked.connect(self.initialize)
        layout.addWidget(init_button)

        self.horizontalButtons2.setLayout(layout)

    def createLogTable(self):
        # Create table
        self.logTable = QTableWidget()
        self.logTable.setRowCount(self.tableRow)
        self.logTable.setColumnCount(self.tableCol)
        self.logTable.move(0, 0)

    def createConfigTable(self):
        self.configTable = QTableWidget()

        try:
            # load configurationFile
            cwb = load_workbook(self.configFile.strip())
        except:
            # message box
            string = "설정파일을 불러올 수 없습니다."
            QMessageBox.question(self, 'Error', string, QMessageBox.Ok,
                                 QMessageBox.Ok)

        else:
            # Get matadata
            cws = cwb.active
            self.crow = cws.cell(row=1, column=1).value
            self.ccol = cws.cell(row=1, column=2).value

            # Configure table
            self.configTable.setRowCount(self.crow)
            self.configTable.setColumnCount(self.ccol)
            self.configTable.move(0, 0)

            # Load data from configFile
            for i in range(self.crow):
                for j in range(self.ccol):
                    item = str(cws.cell(row=i + 2, column=j + 1).value).strip()
                    if item == 'None':
                        item = ''
                    self.configTable.setItem(i, j, QTableWidgetItem(item))

            # check if files exist
            arr = listdir('./audio_clips')
            for row in range(self.crow):
                for col in range(self.ccol):
                    # if 박스(0,0)
                    if row == 0 and col == 0:
                        continue

                    # reset backgound color
                    self.configTable.item(row,
                                          col).setBackground(QColor(255, 0, 0))

                    # if file exist, change background color
                    fname = str(row) + '_' + str(col) + '.mp3'
                    if fname in arr:
                        if row == 0:
                            self.configTable.item(row, col).setBackground(
                                QColor(255, 255, 0))
                        else:
                            self.configTable.item(row, col).setBackground(
                                QColor(0, 255, 255))

            # 박스(0,0)
            self.configTable.setItem(0, 0, QTableWidgetItem('박스'))
            self.configTable.item(0, 0).setBackground(QColor(255, 255, 255))

            # link the callback function
            self.configTable.itemDoubleClicked.connect(self.item_doubleClicked)
            self.configTable.itemChanged.connect(self.item_changed)

    def setLogTable(self):
        # shifting other rows
        for r in range(1, self.tableRow):
            for c in range(self.tableCol):
                try:
                    self.logTable.item(r,
                                       c).setBackground(QColor(255, 255, 255))
                    self.logTable.setItem(r - 1, c,
                                          self.logTable.item(r, c).clone())
                except:
                    pass

        # set current row
        for idx, key in enumerate(list(self.dict.keys())):
            if type(self.dict[key]) is list:
                self.logTable.setItem(
                    self.tableRow - 1, idx,
                    QTableWidgetItem(' '.join(self.dict[key])))
                self.logTable.item(self.tableRow - 1,
                                   idx).setBackground(QColor(255, 255, 0))
            else:
                self.logTable.setItem(self.tableRow - 1, idx,
                                      QTableWidgetItem(self.dict[key]))
                self.logTable.item(self.tableRow - 1,
                                   idx).setBackground(QColor(255, 255, 0))

    def read(self):

        # 포장 순번
        self.dict['num'] = str(self.ws.cell(row=self.row,
                                            column=3).value[2:]).strip()

        # 거래처명
        self.dict['partner'] = str(self.ws.cell(row=self.row,
                                                column=5).value).strip()

        # 배송센터
        self.dict['parcel'] = str(self.ws.cell(row=self.row,
                                               column=4).value).strip()

        # 특이사항
        self.dict['exception'] = str(
            self.ws.cell(row=self.row, column=6).value).strip()

        # 박스
        self.dict['box'] = str(self.ws.cell(row=self.row,
                                            column=2).value).strip()

        # left things
        print(len(self.dict))
        for i in range(5, len(self.dict)):
            header = str(self.ws.cell(row=1, column=i + 2).value).strip()
            self.dict[header] = str(
                self.ws.cell(row=self.row, column=i + 2).value).strip()
            self.parsing(header, self.dict[header])

        print(self.dict)
        self.setLogTable()

    def parsing(self, key, val):
        if val == 'None' or val == '':
            self.dict[key] = None

        else:
            if '(' in val or '/' in val:
                arr = re.split('[(/]', val)
                for i in range(len(arr)):
                    if ')' in arr[i]:
                        arr[i] = arr[i][:arr[i].index(')')]
                    arr[i] = arr[i].strip()
                self.dict[key] = arr

            else:
                self.dict[key] = val

    def itemFromKeyVal(self, key, val):
        items = self.configTable.findItems(val, Qt.MatchExactly)
        if len(items) <= 0:
            # Error
            string = '(' + key + ', ' + val + ') ' + '아이템을 찾을 수 없습니다.'
            QMessageBox.question(self, 'Error', string, QMessageBox.Ok,
                                 QMessageBox.Ok)
        else:
            for item in items:
                if self.configTable.item(0, item.column()).data(0) == key:
                    return item

    def load_audiolist(self):
        for key, val in self.dict.items():

            # 포장순번
            if key == 'num':
                for i in range(len(self.dict['num'])):
                    self.audiolist.append('_' + val[i])

                # beep
                self.audiolist.append('_beep')

            # 택배발송
            elif key == 'parcel':
                if val == '택배발송':
                    self.audiolist.append('_택배발송')

                    # beep
                    self.audiolist.append('_beep')

            # 박스
            elif key == 'box':
                item = self.itemFromKeyVal('박스', val)
                if item:
                    self.audiolist.append(
                        str(item.row()) + '_' + str(item.column()))

                    # beep
                    self.audiolist.append('_beep')

            elif key in ['partner', 'exception']:
                pass

            # general case
            else:
                # The case(val == None) will be ignored
                if val == None:
                    pass

                # when val is list
                elif type(val) == list:
                    for idx, eachVal in enumerate(val):
                        item = self.itemFromKeyVal(key, eachVal)
                        if item:
                            if idx == 0:
                                self.audiolist.append(
                                    '0_' + str(item.column()))  # key
                            self.audiolist.append(
                                str(item.row()) + '_' +
                                str(item.column()))  # val

                    # beep
                    self.audiolist.append('_beep')

                # when val is not list
                else:
                    item = self.itemFromKeyVal(key, val)
                    if item:
                        if val == '1' or key == val:
                            self.audiolist.append('0_' +
                                                  str(item.column()))  # key
                        else:
                            self.audiolist.append('0_' +
                                                  str(item.column()))  # key
                            self.audiolist.append(
                                str(item.row()) + '_' +
                                str(item.column()))  # val

                        # beep
                        self.audiolist.append('_beep')

        print(self.audiolist)

    def speak(self):
        self.playlist.clear()
        for clip in self.audiolist:
            url = QUrl.fromLocalFile('./audio_clips/' + clip + '.mp3')
            #print(url)
            self.playlist.addMedia(QMediaContent(url))
        self.player.setPlaylist(self.playlist)
        self.player.play()

#----------------------- Control button callback -----------------------#

    @pyqtSlot()
    def pre_click(self):
        if not self.fileReady:
            self.cur_click()

        else:
            if self.row == 2:
                self.statusbar.showMessage("Can't be previous.")
            else:
                self.row -= 1

            self.dict = self.dict.fromkeys(self.dict, None)
            del self.audiolist[:]
            self.read()
            self.load_audiolist()
            self.speak()

    @pyqtSlot()
    def cur_click(self):
        if not self.fileReady:
            string = '파일이 준비되어 있지 않습니다.'
            QMessageBox.question(self, '경고', string, QMessageBox.Ok,
                                 QMessageBox.Ok)
            self.openFileNameDialog()
        else:

            self.dict = self.dict.fromkeys(self.dict, None)
            del self.audiolist[:]
            self.read()
            self.load_audiolist()
            self.speak()

    @pyqtSlot()
    def next_click(self):
        if not self.fileReady:
            self.cur_click()

        else:
            if self.row == self.ws.max_row:
                self.statusbar.showMessage("It's over.")
            else:
                self.row += 1

            self.dict = self.dict.fromkeys(self.dict, None)
            del self.audiolist[:]
            self.read()
            self.load_audiolist()
            self.speak()

    @pyqtSlot()
    def back_click(self):
        if self.playlist.mediaCount() == 0:
            self.cur_click()
        elif self.playlist.mediaCount() != 0:
            p = re.compile('.+_beep.+')
            cnt = 0
            for i in range(self.playlist.mediaCount()):
                # if it's start point, start at here
                if self.playlist.currentIndex() == 0:
                    break
                # go backward
                self.playlist.setCurrentIndex(self.playlist.previousIndex(1))

                # start at previous beep point
                if p.match(str(self.playlist.currentMedia().canonicalUrl())):
                    cnt = cnt + 1
                    if cnt == 2:
                        print(self.playlist.currentIndex())
                        if self.player.state() == QMediaPlayer.StoppedState:
                            self.player.play()
                        break

    @pyqtSlot()
    def forward_click(self):
        if self.playlist.mediaCount() == 0:
            self.cur_click()
        elif self.playlist.mediaCount() != 0:
            p = re.compile('.+_beep.+')
            for i in range(self.playlist.mediaCount()):
                # don't go further from end point
                if self.playlist.currentIndex() < 0:
                    break

                # go forward
                self.playlist.setCurrentIndex(self.playlist.nextIndex(1))

                # start at next beep point
                if p.match(str(self.playlist.currentMedia().canonicalUrl())):
                    print(self.playlist.currentIndex())
                    break

#----------------------- Configuration button callback -----------------------#

    @pyqtSlot()
    def plus_row(self):
        # change configTable
        self.crow = self.crow + 1
        self.configTable.setRowCount(self.crow)

        # fill the generated cell
        self.configTable.itemChanged.disconnect(self.item_changed)
        for col in range(self.ccol):
            self.configTable.setItem(self.crow - 1, col, QTableWidgetItem(''))
            self.configTable.item(self.crow - 1,
                                  col).setBackground(QColor(255, 0, 0))
        self.configTable.itemChanged.connect(self.item_changed)

    @pyqtSlot()
    def plus_col(self):
        # change configTable
        self.ccol = self.ccol + 1
        self.configTable.setColumnCount(self.ccol)

        # fill the generated cell
        self.configTable.itemChanged.disconnect(self.item_changed)
        for row in range(self.crow):
            self.configTable.setItem(row, self.ccol - 1, QTableWidgetItem(''))
            self.configTable.item(row, self.ccol - 1).setBackground(
                QColor(255, 0, 0))
        self.configTable.itemChanged.connect(self.item_changed)

    @pyqtSlot()
    def initialize(self):
        # remove configurable audio files
        arr = listdir('./audio_clips')
        p = re.compile('_.+')
        for file in arr:
            if p.match(file):
                continue
            remove('./audio_clips/' + file)

        # init configTable
        self.configTable.itemChanged.disconnect(self.item_changed)  # lock

        self.configTable.clear()
        self.crow = 5
        self.ccol = 5
        self.configTable.setRowCount(self.crow)
        self.configTable.setColumnCount(self.ccol)

        # reset configTable item
        for row in range(self.crow):
            for col in range(self.ccol):
                self.configTable.setItem(row, col, QTableWidgetItem(''))
                self.configTable.item(row,
                                      col).setBackground(QColor(255, 0, 0))
        self.configTable.setItem(0, 0, QTableWidgetItem('박스'))
        self.configTable.item(0, 0).setBackground(QColor(255, 255, 255))

        self.configTable.itemChanged.connect(self.item_changed)  # unlock

        # init configFile
        self.update_configFile()


#---------------------- ConfigTable signal callback ------------------------#

    def item_doubleClicked(self, item):
        self.previousItem = item.data(0)
        print(self.previousItem)

    def update_configFile(self):
        cwb_w = Workbook(write_only=True)
        cws_w = cwb_w.create_sheet()

        cws_w.append([self.crow, self.ccol])

        for row in range(self.crow):
            itemList = []
            for col in range(self.ccol):
                itemList.append(self.configTable.item(row, col).data(0))
            cws_w.append(itemList)
        try:
            cwb_w.save(self.configFile)
        except:
            string = """설정파일이 열려있을 수 있습니다.
                            설정파일을 닫은 후에 다시 시도하세요."""
            QMessageBox.question(self, 'Error', string, QMessageBox.Ok,
                                 QMessageBox.Ok)

    def item_changed(self, item):
        self.configTable.itemChanged.disconnect(self.item_changed)  # lock

        if item.row() == 0 and item.column() == 0:
            string = "이 항목은 바꿀 수 없습니다."
            QMessageBox.question(self, 'Error', string, QMessageBox.Ok,
                                 QMessageBox.Ok)
            self.configTable.setItem(item.row(), item.column(),
                                     QTableWidgetItem(self.previousItem))

        else:
            # get file name
            fileName, _ = QFileDialog.getOpenFileName(self, "Open file", "",
                                                      "All Files (*)")

            # count the number of key that has same name
            keys = self.configTable.findItems(item.data(0), Qt.MatchExactly)
            kcnt = 0
            for key in keys:
                if key.row() == 0:
                    kcnt = kcnt + 1

            # count the number of atribute that has same name
            atributes = self.configTable.findItems(item.data(0),
                                                   Qt.MatchExactly)
            acnt = 0
            for atribute in atributes:
                if atribute.row() == 0:
                    pass
                elif atribute.column() == item.column():
                    acnt = acnt + 1

            # change is accepted only in case of uniqueness and existence and it is not 박스(0,0)
            if kcnt >= 2:
                string = "항목명이 같을 수 없습니다."
                QMessageBox.question(self, 'Error', string, QMessageBox.Ok,
                                     QMessageBox.Ok)
                self.configTable.setItem(item.row(), item.column(),
                                         QTableWidgetItem(self.previousItem))

            elif acnt >= 2:
                string = "같은 항목에 같은 이름의 아이템을 둘 수 없습니다."
                QMessageBox.question(self, 'Error', string, QMessageBox.Ok,
                                     QMessageBox.Ok)
                self.configTable.setItem(item.row(), item.column(),
                                         QTableWidgetItem(self.previousItem))

            elif fileName:
                # copy file to local dir
                dst = "./audio_clips./" + str(item.row()) + '_' + str(
                    item.column()) + '.mp3'
                copyfile(fileName, dst)

                # change cell color
                if item.row() == 0:
                    self.configTable.item(item.row(),
                                          item.column()).setBackground(
                                              QColor(255, 255, 0))
                else:
                    self.configTable.item(item.row(),
                                          item.column()).setBackground(
                                              QColor(0, 255, 255))

                # update configFile
                self.update_configFile()

            else:
                string = "선택이 취소됨."
                QMessageBox.question(self, 'Error', string, QMessageBox.Ok,
                                     QMessageBox.Ok)
                self.configTable.setItem(item.row(), item.column(),
                                         QTableWidgetItem(self.previousItem))

        self.configTable.itemChanged.connect(self.item_changed)  # unlock
Exemple #36
0
    def __init__(self, parent: 'ElectrumWindow', config: 'SimpleConfig'):
        WindowModalDialog.__init__(self, parent, _('Preferences'))
        self.config = config
        self.window = parent
        self.need_restart = False
        self.fx = self.window.fx
        self.wallet = self.window.wallet

        vbox = QVBoxLayout()
        tabs = QTabWidget()
        gui_widgets = []
        tx_widgets = []
        oa_widgets = []

        # language
        lang_help = _(
            'Select which language is used in the GUI (after restart).')
        lang_label = HelpLabel(_('Language') + ':', lang_help)
        lang_combo = QComboBox()
        lang_combo.addItems(list(languages.values()))
        lang_keys = list(languages.keys())
        lang_cur_setting = self.config.get("language", '')
        try:
            index = lang_keys.index(lang_cur_setting)
        except ValueError:  # not in list
            index = 0
        lang_combo.setCurrentIndex(index)
        if not self.config.is_modifiable('language'):
            for w in [lang_combo, lang_label]:
                w.setEnabled(False)

        def on_lang(x):
            lang_request = list(languages.keys())[lang_combo.currentIndex()]
            if lang_request != self.config.get('language'):
                self.config.set_key("language", lang_request, True)
                self.need_restart = True

        lang_combo.currentIndexChanged.connect(on_lang)
        gui_widgets.append((lang_label, lang_combo))

        nz_help = _(
            'Number of zeros displayed after the decimal point. For example, if this is set to 2, "1." will be displayed as "1.00"'
        )
        nz_label = HelpLabel(_('Zeros after decimal point') + ':', nz_help)
        nz = QSpinBox()
        nz.setMinimum(0)
        nz.setMaximum(self.config.decimal_point)
        nz.setValue(self.config.num_zeros)
        if not self.config.is_modifiable('num_zeros'):
            for w in [nz, nz_label]:
                w.setEnabled(False)

        def on_nz():
            value = nz.value()
            if self.config.num_zeros != value:
                self.config.num_zeros = value
                self.config.set_key('num_zeros', value, True)
                self.window.history_list.update()
                self.window.address_list.update()

        nz.valueChanged.connect(on_nz)
        gui_widgets.append((nz_label, nz))

        use_rbf = bool(self.config.get('use_rbf', True))
        use_rbf_cb = QCheckBox(_('Use Replace-By-Fee'))
        use_rbf_cb.setChecked(use_rbf)
        use_rbf_cb.setToolTip(
            _('If you check this box, your transactions will be marked as non-final,') + '\n' + \
            _('and you will have the possibility, while they are unconfirmed, to replace them with transactions that pay higher fees.') + '\n' + \
            _('Note that some merchants do not accept non-final transactions until they are confirmed.'))

        def on_use_rbf(x):
            self.config.set_key('use_rbf', bool(x))
            batch_rbf_cb.setEnabled(bool(x))

        use_rbf_cb.stateChanged.connect(on_use_rbf)
        tx_widgets.append((use_rbf_cb, None))

        batch_rbf_cb = QCheckBox(_('Batch RBF transactions'))
        batch_rbf_cb.setChecked(bool(self.config.get('batch_rbf', False)))
        batch_rbf_cb.setEnabled(use_rbf)
        batch_rbf_cb.setToolTip(
            _('If you check this box, your unconfirmed transactions will be consolidated into a single transaction.') + '\n' + \
            _('This will save fees.'))

        def on_batch_rbf(x):
            self.config.set_key('batch_rbf', bool(x))

        batch_rbf_cb.stateChanged.connect(on_batch_rbf)
        tx_widgets.append((batch_rbf_cb, None))

        # lightning
        lightning_widgets = []

        help_gossip = _(
            """If this option is enabled, Electrum will download the network
channels graph and compute payment path locally, instead of using trampoline payments. """
        )
        gossip_cb = QCheckBox(_("Download network graph"))
        gossip_cb.setToolTip(help_gossip)
        gossip_cb.setChecked(bool(self.config.get('use_gossip', False)))

        def on_gossip_checked(x):
            use_gossip = bool(x)
            self.config.set_key('use_gossip', use_gossip)
            if use_gossip:
                self.window.network.start_gossip()
            else:
                self.window.network.stop_gossip()
            util.trigger_callback('ln_gossip_sync_progress')
            # FIXME: update all wallet windows
            util.trigger_callback('channels_updated', self.wallet)

        gossip_cb.stateChanged.connect(on_gossip_checked)
        lightning_widgets.append((gossip_cb, None))

        help_local_wt = _("""If this option is checked, Electrum will
run a local watchtower and protect your channels even if your wallet is not
open. For this to work, your computer needs to be online regularly.""")
        local_wt_cb = QCheckBox(_("Run a local watchtower"))
        local_wt_cb.setToolTip(help_local_wt)
        local_wt_cb.setChecked(
            bool(self.config.get('run_local_watchtower', False)))

        def on_local_wt_checked(x):
            self.config.set_key('run_local_watchtower', bool(x))

        local_wt_cb.stateChanged.connect(on_local_wt_checked)
        lightning_widgets.append((local_wt_cb, None))

        help_persist = _(
            """If this option is checked, Electrum will persist after
you close all your wallet windows, and the Electrum icon will be visible in the taskbar.
Use this if you want your local watchtower to keep running after you close your wallet."""
        )
        persist_cb = QCheckBox(_("Persist after all windows are closed"))
        persist_cb.setToolTip(help_persist)
        persist_cb.setChecked(bool(self.config.get('persist_daemon', False)))

        def on_persist_checked(x):
            self.config.set_key('persist_daemon', bool(x))

        persist_cb.stateChanged.connect(on_persist_checked)
        lightning_widgets.append((persist_cb, None))

        help_remote_wt = _(
            """To use a remote watchtower, enter the corresponding URL here""")
        remote_wt_cb = QCheckBox(_("Use a remote watchtower"))
        remote_wt_cb.setToolTip(help_remote_wt)
        remote_wt_cb.setChecked(bool(self.config.get('use_watchtower', False)))

        def on_remote_wt_checked(x):
            self.config.set_key('use_watchtower', bool(x))
            self.watchtower_url_e.setEnabled(bool(x))

        remote_wt_cb.stateChanged.connect(on_remote_wt_checked)
        watchtower_url = self.config.get('watchtower_url')
        self.watchtower_url_e = QLineEdit(watchtower_url)
        self.watchtower_url_e.setEnabled(
            self.config.get('use_watchtower', False))

        def on_wt_url():
            url = self.watchtower_url_e.text() or None
            watchtower_url = self.config.set_key('watchtower_url', url)

        self.watchtower_url_e.editingFinished.connect(on_wt_url)
        lightning_widgets.append((remote_wt_cb, self.watchtower_url_e))

        msg = _('OpenAlias record, used to receive coins and to sign payment requests.') + '\n\n'\
              + _('The following alias providers are available:') + '\n'\
              + '\n'.join(['https://cryptoname.co/', 'http://xmr.link']) + '\n\n'\
              + 'For more information, see https://openalias.org'
        alias_label = HelpLabel(_('OpenAlias') + ':', msg)
        alias = self.config.get('alias', '')
        self.alias_e = QLineEdit(alias)
        self.set_alias_color()
        self.alias_e.editingFinished.connect(self.on_alias_edit)
        oa_widgets.append((alias_label, self.alias_e))

        # units
        units = base_units_list
        msg = (_(
            'Base unit of your wallet.'
        ) + '\n1 LTC = 1000 mLTC. 1 mLTC = 1000 uLTC. 1 uLTC = 100 sat.\n' + _(
            'This setting affects the Send tab, and all balance related fields.'
        ))
        unit_label = HelpLabel(_('Base unit') + ':', msg)
        unit_combo = QComboBox()
        unit_combo.addItems(units)
        unit_combo.setCurrentIndex(units.index(self.window.base_unit()))

        def on_unit(x, nz):
            unit_result = units[unit_combo.currentIndex()]
            if self.window.base_unit() == unit_result:
                return
            edits = self.window.amount_e, self.window.receive_amount_e
            amounts = [edit.get_amount() for edit in edits]
            self.config.set_base_unit(unit_result)
            nz.setMaximum(self.config.decimal_point)
            self.window.history_list.update()
            self.window.request_list.update()
            self.window.address_list.update()
            for edit, amount in zip(edits, amounts):
                edit.setAmount(amount)
            self.window.update_status()

        unit_combo.currentIndexChanged.connect(lambda x: on_unit(x, nz))
        gui_widgets.append((unit_label, unit_combo))

        system_cameras = qrscanner._find_system_cameras()
        qr_combo = QComboBox()
        qr_combo.addItem("Default", "default")
        for camera, device in system_cameras.items():
            qr_combo.addItem(camera, device)
        #combo.addItem("Manually specify a device", config.get("video_device"))
        index = qr_combo.findData(self.config.get("video_device"))
        qr_combo.setCurrentIndex(index)
        msg = _("Install the zbar package to enable this.")
        qr_label = HelpLabel(_('Video Device') + ':', msg)
        qr_combo.setEnabled(qrscanner.libzbar is not None)
        on_video_device = lambda x: self.config.set_key(
            "video_device", qr_combo.itemData(x), True)
        qr_combo.currentIndexChanged.connect(on_video_device)
        gui_widgets.append((qr_label, qr_combo))

        colortheme_combo = QComboBox()
        colortheme_combo.addItem(_('Light'), 'default')
        colortheme_combo.addItem(_('Dark'), 'dark')
        index = colortheme_combo.findData(
            self.config.get('qt_gui_color_theme', 'default'))
        colortheme_combo.setCurrentIndex(index)
        colortheme_label = QLabel(_('Color theme') + ':')

        def on_colortheme(x):
            self.config.set_key('qt_gui_color_theme',
                                colortheme_combo.itemData(x), True)
            self.need_restart = True

        colortheme_combo.currentIndexChanged.connect(on_colortheme)
        gui_widgets.append((colortheme_label, colortheme_combo))

        updatecheck_cb = QCheckBox(
            _("Automatically check for software updates"))
        updatecheck_cb.setChecked(bool(self.config.get('check_updates',
                                                       False)))

        def on_set_updatecheck(v):
            self.config.set_key('check_updates', v == Qt.Checked, save=True)

        updatecheck_cb.stateChanged.connect(on_set_updatecheck)
        gui_widgets.append((updatecheck_cb, None))

        filelogging_cb = QCheckBox(_("Write logs to file"))
        filelogging_cb.setChecked(bool(self.config.get('log_to_file', False)))

        def on_set_filelogging(v):
            self.config.set_key('log_to_file', v == Qt.Checked, save=True)
            self.need_restart = True

        filelogging_cb.stateChanged.connect(on_set_filelogging)
        filelogging_cb.setToolTip(
            _('Debug logs can be persisted to disk. These are useful for troubleshooting.'
              ))
        gui_widgets.append((filelogging_cb, None))

        preview_cb = QCheckBox(_('Advanced preview'))
        preview_cb.setChecked(bool(self.config.get('advanced_preview', False)))
        preview_cb.setToolTip(
            _("Open advanced transaction preview dialog when 'Pay' is clicked."
              ))

        def on_preview(x):
            self.config.set_key('advanced_preview', x == Qt.Checked)

        preview_cb.stateChanged.connect(on_preview)
        tx_widgets.append((preview_cb, None))

        usechange_cb = QCheckBox(_('Use change addresses'))
        usechange_cb.setChecked(self.window.wallet.use_change)
        if not self.config.is_modifiable('use_change'):
            usechange_cb.setEnabled(False)

        def on_usechange(x):
            usechange_result = x == Qt.Checked
            if self.window.wallet.use_change != usechange_result:
                self.window.wallet.use_change = usechange_result
                self.window.wallet.db.put('use_change',
                                          self.window.wallet.use_change)
                multiple_cb.setEnabled(self.window.wallet.use_change)

        usechange_cb.stateChanged.connect(on_usechange)
        usechange_cb.setToolTip(
            _('Using change addresses makes it more difficult for other people to track your transactions.'
              ))
        tx_widgets.append((usechange_cb, None))

        def on_multiple(x):
            multiple = x == Qt.Checked
            if self.wallet.multiple_change != multiple:
                self.wallet.multiple_change = multiple
                self.wallet.db.put('multiple_change', multiple)

        multiple_change = self.wallet.multiple_change
        multiple_cb = QCheckBox(_('Use multiple change addresses'))
        multiple_cb.setEnabled(self.wallet.use_change)
        multiple_cb.setToolTip('\n'.join([
            _('In some cases, use up to 3 change addresses in order to break '
              'up large coin amounts and obfuscate the recipient address.'),
            _('This may result in higher transactions fees.')
        ]))
        multiple_cb.setChecked(multiple_change)
        multiple_cb.stateChanged.connect(on_multiple)
        tx_widgets.append((multiple_cb, None))

        def fmt_docs(key, klass):
            lines = [ln.lstrip(" ") for ln in klass.__doc__.split("\n")]
            return '\n'.join([key, "", " ".join(lines)])

        choosers = sorted(coinchooser.COIN_CHOOSERS.keys())
        if len(choosers) > 1:
            chooser_name = coinchooser.get_name(self.config)
            msg = _(
                'Choose coin (UTXO) selection method.  The following are available:\n\n'
            )
            msg += '\n\n'.join(
                fmt_docs(*item) for item in coinchooser.COIN_CHOOSERS.items())
            chooser_label = HelpLabel(_('Coin selection') + ':', msg)
            chooser_combo = QComboBox()
            chooser_combo.addItems(choosers)
            i = choosers.index(chooser_name) if chooser_name in choosers else 0
            chooser_combo.setCurrentIndex(i)

            def on_chooser(x):
                chooser_name = choosers[chooser_combo.currentIndex()]
                self.config.set_key('coin_chooser', chooser_name)

            chooser_combo.currentIndexChanged.connect(on_chooser)
            tx_widgets.append((chooser_label, chooser_combo))

        def on_unconf(x):
            self.config.set_key('confirmed_only', bool(x))

        conf_only = bool(self.config.get('confirmed_only', False))
        unconf_cb = QCheckBox(_('Spend only confirmed coins'))
        unconf_cb.setToolTip(_('Spend only confirmed inputs.'))
        unconf_cb.setChecked(conf_only)
        unconf_cb.stateChanged.connect(on_unconf)
        tx_widgets.append((unconf_cb, None))

        def on_outrounding(x):
            self.config.set_key('coin_chooser_output_rounding', bool(x))

        enable_outrounding = bool(
            self.config.get('coin_chooser_output_rounding', True))
        outrounding_cb = QCheckBox(_('Enable output value rounding'))
        outrounding_cb.setToolTip(
            _('Set the value of the change output so that it has similar precision to the other outputs.'
              ) + '\n' + _('This might improve your privacy somewhat.') +
            '\n' +
            _('If enabled, at most 100 satoshis might be lost due to this, per transaction.'
              ))
        outrounding_cb.setChecked(enable_outrounding)
        outrounding_cb.stateChanged.connect(on_outrounding)
        tx_widgets.append((outrounding_cb, None))

        block_explorers = sorted(util.block_explorer_info().keys())
        BLOCK_EX_CUSTOM_ITEM = _("Custom URL")
        if BLOCK_EX_CUSTOM_ITEM in block_explorers:  # malicious translation?
            block_explorers.remove(BLOCK_EX_CUSTOM_ITEM)
        block_explorers.append(BLOCK_EX_CUSTOM_ITEM)
        msg = _(
            'Choose which online block explorer to use for functions that open a web browser'
        )
        block_ex_label = HelpLabel(_('Online Block Explorer') + ':', msg)
        block_ex_combo = QComboBox()
        block_ex_custom_e = QLineEdit(
            self.config.get('block_explorer_custom') or '')
        block_ex_combo.addItems(block_explorers)
        block_ex_combo.setCurrentIndex(
            block_ex_combo.findText(
                util.block_explorer(self.config) or BLOCK_EX_CUSTOM_ITEM))

        def showhide_block_ex_custom_e():
            block_ex_custom_e.setVisible(
                block_ex_combo.currentText() == BLOCK_EX_CUSTOM_ITEM)

        showhide_block_ex_custom_e()

        def on_be_combo(x):
            if block_ex_combo.currentText() == BLOCK_EX_CUSTOM_ITEM:
                on_be_edit()
            else:
                be_result = block_explorers[block_ex_combo.currentIndex()]
                self.config.set_key('block_explorer_custom', None, False)
                self.config.set_key('block_explorer', be_result, True)
            showhide_block_ex_custom_e()

        block_ex_combo.currentIndexChanged.connect(on_be_combo)

        def on_be_edit():
            val = block_ex_custom_e.text()
            try:
                val = ast.literal_eval(val)  # to also accept tuples
            except:
                pass
            self.config.set_key('block_explorer_custom', val)

        block_ex_custom_e.editingFinished.connect(on_be_edit)
        block_ex_hbox = QHBoxLayout()
        block_ex_hbox.setContentsMargins(0, 0, 0, 0)
        block_ex_hbox.setSpacing(0)
        block_ex_hbox.addWidget(block_ex_combo)
        block_ex_hbox.addWidget(block_ex_custom_e)
        block_ex_hbox_w = QWidget()
        block_ex_hbox_w.setLayout(block_ex_hbox)
        tx_widgets.append((block_ex_label, block_ex_hbox_w))

        # Fiat Currency
        hist_checkbox = QCheckBox()
        hist_capgains_checkbox = QCheckBox()
        fiat_address_checkbox = QCheckBox()
        ccy_combo = QComboBox()
        ex_combo = QComboBox()

        def update_currencies():
            if not self.window.fx: return
            currencies = sorted(
                self.fx.get_currencies(self.fx.get_history_config()))
            ccy_combo.clear()
            ccy_combo.addItems([_('None')] + currencies)
            if self.fx.is_enabled():
                ccy_combo.setCurrentIndex(
                    ccy_combo.findText(self.fx.get_currency()))

        def update_history_cb():
            if not self.fx: return
            hist_checkbox.setChecked(self.fx.get_history_config())
            hist_checkbox.setEnabled(self.fx.is_enabled())

        def update_fiat_address_cb():
            if not self.fx: return
            fiat_address_checkbox.setChecked(self.fx.get_fiat_address_config())

        def update_history_capgains_cb():
            if not self.fx: return
            hist_capgains_checkbox.setChecked(
                self.fx.get_history_capital_gains_config())
            hist_capgains_checkbox.setEnabled(hist_checkbox.isChecked())

        def update_exchanges():
            if not self.fx: return
            b = self.fx.is_enabled()
            ex_combo.setEnabled(b)
            if b:
                h = self.fx.get_history_config()
                c = self.fx.get_currency()
                exchanges = self.fx.get_exchanges_by_ccy(c, h)
            else:
                exchanges = self.fx.get_exchanges_by_ccy('USD', False)
            ex_combo.blockSignals(True)
            ex_combo.clear()
            ex_combo.addItems(sorted(exchanges))
            ex_combo.setCurrentIndex(
                ex_combo.findText(self.fx.config_exchange()))
            ex_combo.blockSignals(False)

        def on_currency(hh):
            if not self.fx: return
            b = bool(ccy_combo.currentIndex())
            ccy = str(ccy_combo.currentText()) if b else None
            self.fx.set_enabled(b)
            if b and ccy != self.fx.ccy:
                self.fx.set_currency(ccy)
            update_history_cb()
            update_exchanges()
            self.window.update_fiat()

        def on_exchange(idx):
            exchange = str(ex_combo.currentText())
            if self.fx and self.fx.is_enabled(
            ) and exchange and exchange != self.fx.exchange.name():
                self.fx.set_exchange(exchange)

        def on_history(checked):
            if not self.fx: return
            self.fx.set_history_config(checked)
            update_exchanges()
            self.window.history_model.refresh('on_history')
            if self.fx.is_enabled() and checked:
                self.fx.trigger_update()
            update_history_capgains_cb()

        def on_history_capgains(checked):
            if not self.fx: return
            self.fx.set_history_capital_gains_config(checked)
            self.window.history_model.refresh('on_history_capgains')

        def on_fiat_address(checked):
            if not self.fx: return
            self.fx.set_fiat_address_config(checked)
            self.window.address_list.refresh_headers()
            self.window.address_list.update()

        update_currencies()
        update_history_cb()
        update_history_capgains_cb()
        update_fiat_address_cb()
        update_exchanges()
        ccy_combo.currentIndexChanged.connect(on_currency)
        hist_checkbox.stateChanged.connect(on_history)
        hist_capgains_checkbox.stateChanged.connect(on_history_capgains)
        fiat_address_checkbox.stateChanged.connect(on_fiat_address)
        ex_combo.currentIndexChanged.connect(on_exchange)

        fiat_widgets = []
        fiat_widgets.append((QLabel(_('Fiat currency')), ccy_combo))
        fiat_widgets.append((QLabel(_('Source')), ex_combo))
        fiat_widgets.append((QLabel(_('Show history rates')), hist_checkbox))
        fiat_widgets.append((QLabel(_('Show capital gains in history')),
                             hist_capgains_checkbox))
        fiat_widgets.append((QLabel(_('Show Fiat balance for addresses')),
                             fiat_address_checkbox))

        tabs_info = [
            (gui_widgets, _('General')),
            (tx_widgets, _('Transactions')),
            (lightning_widgets, _('Lightning')),
            (fiat_widgets, _('Fiat')),
            (oa_widgets, _('OpenAlias')),
        ]
        for widgets, name in tabs_info:
            tab = QWidget()
            tab_vbox = QVBoxLayout(tab)
            grid = QGridLayout()
            for a, b in widgets:
                i = grid.rowCount()
                if b:
                    if a:
                        grid.addWidget(a, i, 0)
                    grid.addWidget(b, i, 1)
                else:
                    grid.addWidget(a, i, 0, 1, 2)
            tab_vbox.addLayout(grid)
            tab_vbox.addStretch(1)
            tabs.addTab(tab, name)

        vbox.addWidget(tabs)
        vbox.addStretch(1)
        vbox.addLayout(Buttons(CloseButton(self)))
        self.setLayout(vbox)
Exemple #37
0
class MainWindow(QMainWindow):
    """
    MainWindow class. It stores database.
    """
    switch_window = pyqtSignal()
    show_login_window = pyqtSignal(object)
    show_data_loading_window = pyqtSignal(str, object)
    show_data_saving_window = pyqtSignal(str, object)
    show_measurement_adding_window = pyqtSignal(object)
    show_conv_rule_adding_window = pyqtSignal(object)

    def __init__(self, username: str, tab_name: str = "add_data"):
        """
        Using the main window the user can add new data and plot a figure
        :param username: logged-in user name.
        :param tab_name: tab that must be opened.
        """
        QMainWindow.__init__(self)
        self.setWindowTitle(_("QS Dashboard: %s") % username)

        self.username = username
        self.db = DataBase(username=username)
        print(self.db.DB_FOLDER)

        self.resize(800, 600)
        self.tabs = QTabWidget()
        self.tabs.currentChanged.connect(self.tab_click)
        self.init_add_data_tab()

        self.figure = CreateFigure(self)
        self.tabs.addTab(self.figure, _("---> Plots <---"))

        if tab_name not in TABNAME2IDX:
            raise ValueError(f"Invalid name of tab: '{tab_name}'")

        QTabWidget.setCurrentIndex(self.tabs, TABNAME2IDX[tab_name])
        self.setCentralWidget(self.tabs)

    def tab_click(self, i: int):
        if IDX2TABNAME[i] == "create_figure":
            self.figure.update_list()

    # @property
    # def db(self):
    #     return DataBase(self.username)
    #
    # @db.setter
    # def db(self, database):
    #     """If database is changed you need to update it on disk"""
    #     raise NotImplementedError()

    def init_add_data_tab(self):
        self.add_data_tab = QWidget()
        self.tabs.addTab(self.add_data_tab, _("---> Data <---"))

        # self.widget = QWidget(self.add_data_tab)

        self.hbox = QHBoxLayout(self.add_data_tab)

        lwidget, lvbox = QWidget(), QVBoxLayout()
        self.list_widget = QListWidget()
        self.list_widget_conv_rules = QListWidget()
        self.update_metrics_list()
        lvbox.addWidget(self.list_widget)
        lvbox.addWidget(self.list_widget_conv_rules)

        lwidget.setLayout(lvbox)
        self.hbox.addWidget(lwidget)

        rwidget, grid_layout = QWidget(), QGridLayout()
        button = QPushButton(_("Load Data"))
        button.setGeometry(QRect(10, 200, 150, 50))
        button.clicked.connect(self.handle_data_loading)
        grid_layout.addWidget(button, 0, 0)

        button = QPushButton(_("Add Measurement"))
        button.setGeometry(QRect(10, 200, 150, 50))
        button.clicked.connect(self.handle_measurement_adding)
        grid_layout.addWidget(button, 1, 0)

        button = QPushButton(_("Add metrics convertation rule"))
        button.setGeometry(QRect(10, 200, 150, 50))
        button.clicked.connect(self.handle_conv_rule_adding)
        grid_layout.addWidget(button, 2, 0)

        button = QPushButton(_("Save Data"))
        button.setGeometry(QRect(10, 200, 150, 50))
        button.clicked.connect(self.handle_data_saving)
        grid_layout.addWidget(button, 3, 0)

        button = QPushButton(_("Logout"))
        button.setEnabled(True)
        button.setGeometry(QRect(10, 200, 150, 50))
        button.clicked.connect(self.handle_logout)
        grid_layout.addWidget(button, 4, 0)

        rwidget.setLayout(grid_layout)
        self.hbox.addWidget(rwidget)

    @property
    def user_df(self):
        return self.db.to_dataframe()

    def update_metrics_list(self):
        self.list_widget.clear()
        self.list_widget_conv_rules.clear()
        df = self.user_df
        if "measurement_name" in df.columns:
            metrics = ([_("Added measurements:")] +
                       list(df.measurement_name.unique()))
            for metric in metrics:
                QListWidgetItem(metric, self.list_widget)
        converter_rules = self.db.metrics_converter
        QListWidgetItem(_("Added convertation rules:"),
                        self.list_widget_conv_rules)
        for (from_metric, to_metric), val in converter_rules.items():
            QListWidgetItem(f'{from_metric} / {to_metric} = {round(val, 5)}',
                            self.list_widget_conv_rules)

    @staticmethod
    def on_click(self):
        print('Simple Button was pushed')

    def handle_logout(self):
        self.show_login_window.emit(self)

    def handle_data_loading(self):
        print('loading data')
        self.show_data_loading_window.emit(self.username, self)

    def handle_data_saving(self):
        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        filename, trash = QFileDialog.getSaveFileName(
            self,
            _("Save file"),
            "",
            _("All Files (*);;Text Files (*.txt)"),
            options=options)
        if filename:
            print('saving data to', filename)
            self.db.save_to_dataframe(filename)

    def handle_measurement_adding(self):
        print('adding measurement data')
        self.show_measurement_adding_window.emit(self)

    def handle_conv_rule_adding(self):
        self.show_conv_rule_adding_window.emit(self)
    def initUI(self):
        # 读取配置文件
        global config_dic
        global twolineflag
        try:
            with open('config.json', 'r') as load_f:
                config_dic = json.load(load_f)
        except:
            config_dic = config_dic
            QMessageBox.information(
                self,  # 使用infomation信息框
                "注意",
                "未找到配置文件 请手动选择")
            self.read_json()
            # 初始化连接
        self.IPbox = QLineEdit()
        #self.IPbox.setText("192.168.201.129")
        self.re_num = 1
        self.usernamebox = QLineEdit()
        self.ethbox = QLineEdit()
        self.passwordbox = QLineEdit()
        self.connect_button = QPushButton("测试连接")
        self.update_button = QPushButton("更新配置")
        hbox1 = QHBoxLayout()
        hbox1.addWidget(QLabel("被测试IP:"))
        hbox1.addWidget(self.IPbox)
        hbox1.addWidget(self.connect_button)
        hbox1.addWidget(QLabel("      "))
        hbox1.addWidget(QLabel("本机用户名:"))
        hbox1.addWidget(self.usernamebox)
        hbox1.addWidget(QLabel("本机密码:"))
        hbox1.addWidget(self.passwordbox)
        hbox1.addWidget(QLabel("网口号:"))
        hbox1.addWidget(self.ethbox)

        hbox1.addWidget(self.update_button)

        self.connect_button.clicked.connect(self.connect)
        self.update_button.clicked.connect(self.read_json)

        # 中间

        self.topFiller = QWidget()
        self.topFiller.setMinimumSize(2500, 2000)  #######设置滚动条的尺寸
        self.tab = QTabWidget()
        for test_type in config_dic.keys():
            send_list[test_type] = []
            tab_name.append(test_type)

            self.tab.test_type = Checkboxlist(test_type)
            l = int(len(test_type) / 2)
            s = test_type[0:l] + '\n' * twolineflag + test_type[l:]
            self.tab.addTab(self.tab.test_type, s)
        # tab.tabBar().setFixedHeight(48)
        hbox2 = QHBoxLayout(self.topFiller)
        hbox2.addWidget(self.tab)
        #hbox2.addWidget(self.scroll)
        self.scroll = QScrollArea()
        self.scroll.setWidget(self.topFiller)

        # 辅助功能
        hbox3 = QHBoxLayout()
        hbox4 = QHBoxLayout()
        self.re_timebox = QSlider(Qt.Horizontal, self)
        self.re_timebox.setMinimum(1)
        self.re_timebox.setMaximum(1000)
        self.re_timebox.valueChanged[int].connect(self.changeValue)
        self.num = QLabel("1")
        self.fullspeed = QCheckBox("全速发送")
        hbox3.addWidget(self.fullspeed)  # -R

        hbox4.addWidget(QLabel("  重复次数:"))
        hbox4.addWidget(self.num)
        hbox4.addWidget(self.re_timebox)

        hbox3.addWidget(QLabel("  最大发包数量:"))
        self.maxpacknumbox = QLineEdit()  # -L
        hbox3.addWidget(self.maxpacknumbox)
        hbox3.addWidget(QLabel("  每秒发送报文数:"))
        self.packpsbox = QLineEdit()  # -p
        hbox3.addWidget(self.packpsbox)
        '''hbox3.addWidget(QLabel("  指定MTU:"))
        self.MTUbox = QLineEdit()  # -t
        hbox3.addWidget(self.MTUbox)'''

        hbox3.addWidget(QLabel("发包速度/Mbps:"))
        self.Mbpsbox = QLineEdit()
        hbox3.addWidget(self.Mbpsbox)

        # 开始测试
        self.start_button = QPushButton("开始发送数据包")
        self.start_button.clicked.connect(self.start_test)
        self.stop_button = QPushButton("停止发送数据包")
        self.stop_button.clicked.connect(self.stop_test)
        hbox5 = QHBoxLayout()
        hbox5.addWidget(self.start_button)
        hbox5.addWidget(self.stop_button)
        #        hbox5.addWidget(QLabel("                            time:"))
        #        self.timebox = QLineEdit()
        #        hbox5.addWidget(self.timebox)
        # 显示输出结果
        self.resultbox = QTextBrowser()

        vbox = QVBoxLayout()
        vbox.addLayout(hbox1)
        vbox.addWidget(QLabel("选择测试模式:"))

        #vbox.addLayout(hbox2)
        vbox.addWidget(self.scroll)
        vbox.addWidget(QLabel("可选项:"))
        vbox.addLayout(hbox3)
        vbox.addLayout(hbox4)

        vbox.addLayout(hbox5)
        vbox.addWidget(QLabel("状态提示信息:"))
        vbox.addWidget(self.resultbox)
        self.setLayout(vbox)
        # self.setGeometry(300, 300, 290, 150)
        self.setWindowTitle('tcpreplay_gui')
        self.show()
Exemple #39
0
    def __init__(self, window, plugin, keystore, device_id):
        title = _("{} Settings").format(plugin.device)
        super(SettingsDialog, self).__init__(window, title)
        self.setMaximumWidth(540)

        devmgr = plugin.device_manager()
        config = devmgr.config
        handler = keystore.handler
        thread = keystore.thread
        hs_cols, hs_rows = (128, 64)

        def invoke_client(method, *args, **kw_args):
            unpair_after = kw_args.pop('unpair_after', False)

            def task():
                client = devmgr.client_by_id(device_id)
                if not client:
                    raise RuntimeError("Device not connected")
                if method:
                    getattr(client, method)(*args, **kw_args)
                if unpair_after:
                    devmgr.unpair_id(device_id)
                return client.features

            thread.add(task, on_success=update)

        def update(features):
            self.features = features
            set_label_enabled()
            if features.bootloader_hash:
                bl_hash = bh2u(features.bootloader_hash)
                bl_hash = "\n".join([bl_hash[:32], bl_hash[32:]])
            else:
                bl_hash = "N/A"
            noyes = [_("No"), _("Yes")]
            endis = [_("Enable Passphrases"), _("Disable Passphrases")]
            disen = [_("Disabled"), _("Enabled")]
            setchange = [_("Set a PIN"), _("Change PIN")]

            version = "%d.%d.%d" % (features.major_version,
                                    features.minor_version,
                                    features.patch_version)

            device_label.setText(features.label)
            pin_set_label.setText(noyes[features.pin_protection])
            passphrases_label.setText(disen[features.passphrase_protection])
            bl_hash_label.setText(bl_hash)
            label_edit.setText(features.label)
            device_id_label.setText(features.device_id)
            initialized_label.setText(noyes[features.initialized])
            version_label.setText(version)
            clear_pin_button.setVisible(features.pin_protection)
            clear_pin_warning.setVisible(features.pin_protection)
            pin_button.setText(setchange[features.pin_protection])
            pin_msg.setVisible(not features.pin_protection)
            passphrase_button.setText(endis[features.passphrase_protection])
            language_label.setText(features.language)

        def set_label_enabled():
            label_apply.setEnabled(label_edit.text() != self.features.label)

        def rename():
            invoke_client('change_label', label_edit.text())

        def toggle_passphrase():
            title = _("Confirm Toggle Passphrase Protection")
            currently_enabled = self.features.passphrase_protection
            if currently_enabled:
                msg = _("After disabling passphrases, you can only pair this "
                        "Electrum-NMC wallet if it had an empty passphrase.  "
                        "If its passphrase was not empty, you will need to "
                        "create a new wallet with the install wizard.  You "
                        "can use this wallet again at any time by re-enabling "
                        "passphrases and entering its passphrase.")
            else:
                msg = _("Your current Electrum-NMC wallet can only be used with "
                        "an empty passphrase.  You must create a separate "
                        "wallet with the install wizard for other passphrases "
                        "as each one generates a new set of addresses.")
            msg += "\n\n" + _("Are you sure you want to proceed?")
            if not self.question(msg, title=title):
                return
            invoke_client('toggle_passphrase', unpair_after=currently_enabled)

        def change_homescreen():
            dialog = QFileDialog(self, _("Choose Homescreen"))
            filename, __ = dialog.getOpenFileName()
            if not filename:
                return  # user cancelled

            if filename.endswith('.toif'):
                img = open(filename, 'rb').read()
                if img[:8] != b'TOIf\x90\x00\x90\x00':
                    handler.show_error('File is not a TOIF file with size of 144x144')
                    return
            else:
                from PIL import Image # FIXME
                im = Image.open(filename)
                if im.size != (128, 64):
                    handler.show_error('Image must be 128 x 64 pixels')
                    return
                im = im.convert('1')
                pix = im.load()
                img = bytearray(1024)
                for j in range(64):
                    for i in range(128):
                        if pix[i, j]:
                            o = (i + j * 128)
                            img[o // 8] |= (1 << (7 - o % 8))
                img = bytes(img)
            invoke_client('change_homescreen', img)

        def clear_homescreen():
            invoke_client('change_homescreen', b'\x00')

        def set_pin():
            invoke_client('set_pin', remove=False)

        def clear_pin():
            invoke_client('set_pin', remove=True)

        def wipe_device():
            wallet = window.wallet
            if wallet and sum(wallet.get_balance()):
                title = _("Confirm Device Wipe")
                msg = _("Are you SURE you want to wipe the device?\n"
                        "Your wallet still has namecoins in it!")
                if not self.question(msg, title=title,
                                     icon=QMessageBox.Critical):
                    return
            invoke_client('wipe_device', unpair_after=True)

        def slider_moved():
            mins = timeout_slider.sliderPosition()
            timeout_minutes.setText(_("{:2d} minutes").format(mins))

        def slider_released():
            config.set_session_timeout(timeout_slider.sliderPosition() * 60)

        # Information tab
        info_tab = QWidget()
        info_layout = QVBoxLayout(info_tab)
        info_glayout = QGridLayout()
        info_glayout.setColumnStretch(2, 1)
        device_label = QLabel()
        pin_set_label = QLabel()
        passphrases_label = QLabel()
        version_label = QLabel()
        device_id_label = QLabel()
        bl_hash_label = QLabel()
        bl_hash_label.setWordWrap(True)
        language_label = QLabel()
        initialized_label = QLabel()
        rows = [
            (_("Device Label"), device_label),
            (_("PIN set"), pin_set_label),
            (_("Passphrases"), passphrases_label),
            (_("Firmware Version"), version_label),
            (_("Device ID"), device_id_label),
            (_("Bootloader Hash"), bl_hash_label),
            (_("Language"), language_label),
            (_("Initialized"), initialized_label),
        ]
        for row_num, (label, widget) in enumerate(rows):
            info_glayout.addWidget(QLabel(label), row_num, 0)
            info_glayout.addWidget(widget, row_num, 1)
        info_layout.addLayout(info_glayout)

        # Settings tab
        settings_tab = QWidget()
        settings_layout = QVBoxLayout(settings_tab)
        settings_glayout = QGridLayout()

        # Settings tab - Label
        label_msg = QLabel(_("Name this {}.  If you have multiple devices "
                             "their labels help distinguish them.")
                           .format(plugin.device))
        label_msg.setWordWrap(True)
        label_label = QLabel(_("Device Label"))
        label_edit = QLineEdit()
        label_edit.setMinimumWidth(150)
        label_edit.setMaxLength(plugin.MAX_LABEL_LEN)
        label_apply = QPushButton(_("Apply"))
        label_apply.clicked.connect(rename)
        label_edit.textChanged.connect(set_label_enabled)
        settings_glayout.addWidget(label_label, 0, 0)
        settings_glayout.addWidget(label_edit, 0, 1, 1, 2)
        settings_glayout.addWidget(label_apply, 0, 3)
        settings_glayout.addWidget(label_msg, 1, 1, 1, -1)

        # Settings tab - PIN
        pin_label = QLabel(_("PIN Protection"))
        pin_button = QPushButton()
        pin_button.clicked.connect(set_pin)
        settings_glayout.addWidget(pin_label, 2, 0)
        settings_glayout.addWidget(pin_button, 2, 1)
        pin_msg = QLabel(_("PIN protection is strongly recommended.  "
                           "A PIN is your only protection against someone "
                           "stealing your namecoins if they obtain physical "
                           "access to your {}.").format(plugin.device))
        pin_msg.setWordWrap(True)
        pin_msg.setStyleSheet("color: red")
        settings_glayout.addWidget(pin_msg, 3, 1, 1, -1)

        # Settings tab - Homescreen
        homescreen_label = QLabel(_("Homescreen"))
        homescreen_change_button = QPushButton(_("Change..."))
        homescreen_clear_button = QPushButton(_("Reset"))
        homescreen_change_button.clicked.connect(change_homescreen)
        try:
            import PIL
        except ImportError:
            homescreen_change_button.setDisabled(True)
            homescreen_change_button.setToolTip(
                _("Required package 'PIL' is not available - Please install it.")
            )
        homescreen_clear_button.clicked.connect(clear_homescreen)
        homescreen_msg = QLabel(_("You can set the homescreen on your "
                                  "device to personalize it.  You must "
                                  "choose a {} x {} monochrome black and "
                                  "white image.").format(hs_cols, hs_rows))
        homescreen_msg.setWordWrap(True)
        settings_glayout.addWidget(homescreen_label, 4, 0)
        settings_glayout.addWidget(homescreen_change_button, 4, 1)
        settings_glayout.addWidget(homescreen_clear_button, 4, 2)
        settings_glayout.addWidget(homescreen_msg, 5, 1, 1, -1)

        # Settings tab - Session Timeout
        timeout_label = QLabel(_("Session Timeout"))
        timeout_minutes = QLabel()
        timeout_slider = QSlider(Qt.Horizontal)
        timeout_slider.setRange(1, 60)
        timeout_slider.setSingleStep(1)
        timeout_slider.setTickInterval(5)
        timeout_slider.setTickPosition(QSlider.TicksBelow)
        timeout_slider.setTracking(True)
        timeout_msg = QLabel(
            _("Clear the session after the specified period "
              "of inactivity.  Once a session has timed out, "
              "your PIN and passphrase (if enabled) must be "
              "re-entered to use the device."))
        timeout_msg.setWordWrap(True)
        timeout_slider.setSliderPosition(config.get_session_timeout() // 60)
        slider_moved()
        timeout_slider.valueChanged.connect(slider_moved)
        timeout_slider.sliderReleased.connect(slider_released)
        settings_glayout.addWidget(timeout_label, 6, 0)
        settings_glayout.addWidget(timeout_slider, 6, 1, 1, 3)
        settings_glayout.addWidget(timeout_minutes, 6, 4)
        settings_glayout.addWidget(timeout_msg, 7, 1, 1, -1)
        settings_layout.addLayout(settings_glayout)
        settings_layout.addStretch(1)

        # Advanced tab
        advanced_tab = QWidget()
        advanced_layout = QVBoxLayout(advanced_tab)
        advanced_glayout = QGridLayout()

        # Advanced tab - clear PIN
        clear_pin_button = QPushButton(_("Disable PIN"))
        clear_pin_button.clicked.connect(clear_pin)
        clear_pin_warning = QLabel(
            _("If you disable your PIN, anyone with physical access to your "
              "{} device can spend your namecoins.").format(plugin.device))
        clear_pin_warning.setWordWrap(True)
        clear_pin_warning.setStyleSheet("color: red")
        advanced_glayout.addWidget(clear_pin_button, 0, 2)
        advanced_glayout.addWidget(clear_pin_warning, 1, 0, 1, 5)

        # Advanced tab - toggle passphrase protection
        passphrase_button = QPushButton()
        passphrase_button.clicked.connect(toggle_passphrase)
        passphrase_msg = WWLabel(PASSPHRASE_HELP)
        passphrase_warning = WWLabel(PASSPHRASE_NOT_PIN)
        passphrase_warning.setStyleSheet("color: red")
        advanced_glayout.addWidget(passphrase_button, 3, 2)
        advanced_glayout.addWidget(passphrase_msg, 4, 0, 1, 5)
        advanced_glayout.addWidget(passphrase_warning, 5, 0, 1, 5)

        # Advanced tab - wipe device
        wipe_device_button = QPushButton(_("Wipe Device"))
        wipe_device_button.clicked.connect(wipe_device)
        wipe_device_msg = QLabel(
            _("Wipe the device, removing all data from it.  The firmware "
              "is left unchanged."))
        wipe_device_msg.setWordWrap(True)
        wipe_device_warning = QLabel(
            _("Only wipe a device if you have the recovery seed written down "
              "and the device wallet(s) are empty, otherwise the namecoins "
              "will be lost forever."))
        wipe_device_warning.setWordWrap(True)
        wipe_device_warning.setStyleSheet("color: red")
        advanced_glayout.addWidget(wipe_device_button, 6, 2)
        advanced_glayout.addWidget(wipe_device_msg, 7, 0, 1, 5)
        advanced_glayout.addWidget(wipe_device_warning, 8, 0, 1, 5)
        advanced_layout.addLayout(advanced_glayout)
        advanced_layout.addStretch(1)

        tabs = QTabWidget(self)
        tabs.addTab(info_tab, _("Information"))
        tabs.addTab(settings_tab, _("Settings"))
        tabs.addTab(advanced_tab, _("Advanced"))
        dialog_vbox = QVBoxLayout(self)
        dialog_vbox.addWidget(tabs)
        dialog_vbox.addLayout(Buttons(CloseButton(self)))

        # Update information
        invoke_client(None)
Exemple #40
0
    def __init__(self):
        QMainWindow.__init__(self)

        logger.debug("Initialising GUI ...")
        self.setObjectName("GuiMain")
        self.mainConf = nw.CONFIG
        self.threadPool = QThreadPool()

        # System Info
        # ===========

        logger.info("OS: %s" % self.mainConf.osType)
        logger.info("Kernel: %s" % self.mainConf.kernelVer)
        logger.info("Host: %s" % self.mainConf.hostName)
        logger.info("Qt5 Version: %s (%d)" % (
            self.mainConf.verQtString, self.mainConf.verQtValue)
        )
        logger.info("PyQt5 Version: %s (%d)" % (
            self.mainConf.verPyQtString, self.mainConf.verPyQtValue)
        )
        logger.info("Python Version: %s (0x%x)" % (
            self.mainConf.verPyString, self.mainConf.verPyHexVal)
        )

        # Core Classes
        # ============

        # Core Classes and Settings
        self.theTheme    = GuiTheme(self)
        self.theProject  = NWProject(self)
        self.theIndex    = NWIndex(self.theProject, self)
        self.hasProject  = False
        self.isFocusMode = False

        # Prepare Main Window
        self.resize(*self.mainConf.getWinSize())
        self._updateWindowTitle()
        self.setWindowIcon(QIcon(self.mainConf.appIcon))

        # Build the GUI
        # =============

        # Main GUI Elements
        self.statusBar = GuiMainStatus(self)
        self.treeView  = GuiProjectTree(self)
        self.docEditor = GuiDocEditor(self)
        self.viewMeta  = GuiDocViewDetails(self)
        self.docViewer = GuiDocViewer(self)
        self.treeMeta  = GuiItemDetails(self)
        self.projView  = GuiOutline(self)
        self.projMeta  = GuiOutlineDetails(self)
        self.mainMenu  = GuiMainMenu(self)

        # Minor Gui Elements
        self.statusIcons = []
        self.importIcons = []

        # Project Tree View
        self.treePane = QWidget()
        self.treeBox = QVBoxLayout()
        self.treeBox.setContentsMargins(0, 0, 0, 0)
        self.treeBox.addWidget(self.treeView)
        self.treeBox.addWidget(self.treeMeta)
        self.treePane.setLayout(self.treeBox)

        # Splitter : Document Viewer / Document Meta
        self.splitView = QSplitter(Qt.Vertical)
        self.splitView.addWidget(self.docViewer)
        self.splitView.addWidget(self.viewMeta)
        self.splitView.setSizes(self.mainConf.getViewPanePos())

        # Splitter : Document Editor / Document Viewer
        self.splitDocs = QSplitter(Qt.Horizontal)
        self.splitDocs.addWidget(self.docEditor)
        self.splitDocs.addWidget(self.splitView)

        # Splitter : Project Outlie / Outline Details
        self.splitOutline = QSplitter(Qt.Vertical)
        self.splitOutline.addWidget(self.projView)
        self.splitOutline.addWidget(self.projMeta)
        self.splitOutline.setSizes(self.mainConf.getOutlinePanePos())

        # Main Tabs : Edirot / Outline
        self.tabWidget = QTabWidget()
        self.tabWidget.setTabPosition(QTabWidget.East)
        self.tabWidget.setStyleSheet("QTabWidget::pane {border: 0;}")
        self.tabWidget.addTab(self.splitDocs, "Editor")
        self.tabWidget.addTab(self.splitOutline, "Outline")
        self.tabWidget.currentChanged.connect(self._mainTabChanged)

        # Splitter : Project Tree / Main Tabs
        xCM = self.mainConf.pxInt(4)
        self.splitMain = QSplitter(Qt.Horizontal)
        self.splitMain.setContentsMargins(xCM, xCM, xCM, xCM)
        self.splitMain.addWidget(self.treePane)
        self.splitMain.addWidget(self.tabWidget)
        self.splitMain.setSizes(self.mainConf.getMainPanePos())

        # Indices of All Splitter Widgets
        self.idxTree     = self.splitMain.indexOf(self.treePane)
        self.idxMain     = self.splitMain.indexOf(self.tabWidget)
        self.idxEditor   = self.splitDocs.indexOf(self.docEditor)
        self.idxViewer   = self.splitDocs.indexOf(self.splitView)
        self.idxViewDoc  = self.splitView.indexOf(self.docViewer)
        self.idxViewMeta = self.splitView.indexOf(self.viewMeta)
        self.idxTabEdit  = self.tabWidget.indexOf(self.splitDocs)
        self.idxTabProj  = self.tabWidget.indexOf(self.splitOutline)

        # Splitter Behaviour
        self.splitMain.setCollapsible(self.idxTree, False)
        self.splitMain.setCollapsible(self.idxMain, False)
        self.splitDocs.setCollapsible(self.idxEditor, False)
        self.splitDocs.setCollapsible(self.idxViewer, True)
        self.splitView.setCollapsible(self.idxViewDoc, False)
        self.splitView.setCollapsible(self.idxViewMeta, False)

        # Editor / Viewer Default State
        self.splitView.setVisible(False)
        self.docEditor.closeSearch()

        # Initialise the Project Tree
        self.treeView.itemSelectionChanged.connect(self._treeSingleClick)
        self.treeView.itemDoubleClicked.connect(self._treeDoubleClick)
        self.rebuildTree()

        # Set Main Window Elements
        self.setMenuBar(self.mainMenu)
        self.setCentralWidget(self.splitMain)
        self.setStatusBar(self.statusBar)

        # Finalise Initialisation
        # =======================

        # Set Up Auto-Save Project Timer
        self.asProjTimer = QTimer()
        self.asProjTimer.timeout.connect(self._autoSaveProject)

        # Set Up Auto-Save Document Timer
        self.asDocTimer = QTimer()
        self.asDocTimer.timeout.connect(self._autoSaveDocument)

        # Shortcuts and Actions
        self._connectMenuActions()

        keyReturn = QShortcut(self.treeView)
        keyReturn.setKey(QKeySequence(Qt.Key_Return))
        keyReturn.activated.connect(self._treeKeyPressReturn)

        keyEscape = QShortcut(self)
        keyEscape.setKey(QKeySequence(Qt.Key_Escape))
        keyEscape.activated.connect(self._keyPressEscape)

        # Forward Functions
        self.setStatus = self.statusBar.setStatus
        self.setProjectStatus = self.statusBar.setProjectStatus

        # Force a show of the GUI
        self.show()

        # Check that config loaded fine
        self.reportConfErr()

        # Initialise Main GUI
        self.initMain()
        self.asProjTimer.start()
        self.asDocTimer.start()
        self.statusBar.clearStatus()

        # Handle Windows Mode
        self.showNormal()
        if self.mainConf.isFullScreen:
            self.toggleFullScreenMode()

        logger.debug("GUI initialisation complete")

        # Check if a project path was provided at command line, and if
        # not, open the project manager instead.
        if self.mainConf.cmdOpen is not None:
            logger.debug("Opening project from additional command line option")
            self.openProject(self.mainConf.cmdOpen)
        else:
            if self.mainConf.showGUI:
                self.showProjectLoadDialog()

        # Show the latest release notes, if they haven't been shown before
        if hexToInt(self.mainConf.lastNotes) < hexToInt(nw.__hexversion__):
            if self.mainConf.showGUI:
                self.showAboutNWDialog(showNotes=True)
            self.mainConf.lastNotes = nw.__hexversion__

        logger.debug("novelWriter is ready ...")
        self.setStatus("novelWriter is ready ...")

        return
Exemple #41
0
class GuiMain(QMainWindow):

    def __init__(self):
        QMainWindow.__init__(self)

        logger.debug("Initialising GUI ...")
        self.setObjectName("GuiMain")
        self.mainConf = nw.CONFIG
        self.threadPool = QThreadPool()

        # System Info
        # ===========

        logger.info("OS: %s" % self.mainConf.osType)
        logger.info("Kernel: %s" % self.mainConf.kernelVer)
        logger.info("Host: %s" % self.mainConf.hostName)
        logger.info("Qt5 Version: %s (%d)" % (
            self.mainConf.verQtString, self.mainConf.verQtValue)
        )
        logger.info("PyQt5 Version: %s (%d)" % (
            self.mainConf.verPyQtString, self.mainConf.verPyQtValue)
        )
        logger.info("Python Version: %s (0x%x)" % (
            self.mainConf.verPyString, self.mainConf.verPyHexVal)
        )

        # Core Classes
        # ============

        # Core Classes and Settings
        self.theTheme    = GuiTheme(self)
        self.theProject  = NWProject(self)
        self.theIndex    = NWIndex(self.theProject, self)
        self.hasProject  = False
        self.isFocusMode = False

        # Prepare Main Window
        self.resize(*self.mainConf.getWinSize())
        self._updateWindowTitle()
        self.setWindowIcon(QIcon(self.mainConf.appIcon))

        # Build the GUI
        # =============

        # Main GUI Elements
        self.statusBar = GuiMainStatus(self)
        self.treeView  = GuiProjectTree(self)
        self.docEditor = GuiDocEditor(self)
        self.viewMeta  = GuiDocViewDetails(self)
        self.docViewer = GuiDocViewer(self)
        self.treeMeta  = GuiItemDetails(self)
        self.projView  = GuiOutline(self)
        self.projMeta  = GuiOutlineDetails(self)
        self.mainMenu  = GuiMainMenu(self)

        # Minor Gui Elements
        self.statusIcons = []
        self.importIcons = []

        # Project Tree View
        self.treePane = QWidget()
        self.treeBox = QVBoxLayout()
        self.treeBox.setContentsMargins(0, 0, 0, 0)
        self.treeBox.addWidget(self.treeView)
        self.treeBox.addWidget(self.treeMeta)
        self.treePane.setLayout(self.treeBox)

        # Splitter : Document Viewer / Document Meta
        self.splitView = QSplitter(Qt.Vertical)
        self.splitView.addWidget(self.docViewer)
        self.splitView.addWidget(self.viewMeta)
        self.splitView.setSizes(self.mainConf.getViewPanePos())

        # Splitter : Document Editor / Document Viewer
        self.splitDocs = QSplitter(Qt.Horizontal)
        self.splitDocs.addWidget(self.docEditor)
        self.splitDocs.addWidget(self.splitView)

        # Splitter : Project Outlie / Outline Details
        self.splitOutline = QSplitter(Qt.Vertical)
        self.splitOutline.addWidget(self.projView)
        self.splitOutline.addWidget(self.projMeta)
        self.splitOutline.setSizes(self.mainConf.getOutlinePanePos())

        # Main Tabs : Edirot / Outline
        self.tabWidget = QTabWidget()
        self.tabWidget.setTabPosition(QTabWidget.East)
        self.tabWidget.setStyleSheet("QTabWidget::pane {border: 0;}")
        self.tabWidget.addTab(self.splitDocs, "Editor")
        self.tabWidget.addTab(self.splitOutline, "Outline")
        self.tabWidget.currentChanged.connect(self._mainTabChanged)

        # Splitter : Project Tree / Main Tabs
        xCM = self.mainConf.pxInt(4)
        self.splitMain = QSplitter(Qt.Horizontal)
        self.splitMain.setContentsMargins(xCM, xCM, xCM, xCM)
        self.splitMain.addWidget(self.treePane)
        self.splitMain.addWidget(self.tabWidget)
        self.splitMain.setSizes(self.mainConf.getMainPanePos())

        # Indices of All Splitter Widgets
        self.idxTree     = self.splitMain.indexOf(self.treePane)
        self.idxMain     = self.splitMain.indexOf(self.tabWidget)
        self.idxEditor   = self.splitDocs.indexOf(self.docEditor)
        self.idxViewer   = self.splitDocs.indexOf(self.splitView)
        self.idxViewDoc  = self.splitView.indexOf(self.docViewer)
        self.idxViewMeta = self.splitView.indexOf(self.viewMeta)
        self.idxTabEdit  = self.tabWidget.indexOf(self.splitDocs)
        self.idxTabProj  = self.tabWidget.indexOf(self.splitOutline)

        # Splitter Behaviour
        self.splitMain.setCollapsible(self.idxTree, False)
        self.splitMain.setCollapsible(self.idxMain, False)
        self.splitDocs.setCollapsible(self.idxEditor, False)
        self.splitDocs.setCollapsible(self.idxViewer, True)
        self.splitView.setCollapsible(self.idxViewDoc, False)
        self.splitView.setCollapsible(self.idxViewMeta, False)

        # Editor / Viewer Default State
        self.splitView.setVisible(False)
        self.docEditor.closeSearch()

        # Initialise the Project Tree
        self.treeView.itemSelectionChanged.connect(self._treeSingleClick)
        self.treeView.itemDoubleClicked.connect(self._treeDoubleClick)
        self.rebuildTree()

        # Set Main Window Elements
        self.setMenuBar(self.mainMenu)
        self.setCentralWidget(self.splitMain)
        self.setStatusBar(self.statusBar)

        # Finalise Initialisation
        # =======================

        # Set Up Auto-Save Project Timer
        self.asProjTimer = QTimer()
        self.asProjTimer.timeout.connect(self._autoSaveProject)

        # Set Up Auto-Save Document Timer
        self.asDocTimer = QTimer()
        self.asDocTimer.timeout.connect(self._autoSaveDocument)

        # Shortcuts and Actions
        self._connectMenuActions()

        keyReturn = QShortcut(self.treeView)
        keyReturn.setKey(QKeySequence(Qt.Key_Return))
        keyReturn.activated.connect(self._treeKeyPressReturn)

        keyEscape = QShortcut(self)
        keyEscape.setKey(QKeySequence(Qt.Key_Escape))
        keyEscape.activated.connect(self._keyPressEscape)

        # Forward Functions
        self.setStatus = self.statusBar.setStatus
        self.setProjectStatus = self.statusBar.setProjectStatus

        # Force a show of the GUI
        self.show()

        # Check that config loaded fine
        self.reportConfErr()

        # Initialise Main GUI
        self.initMain()
        self.asProjTimer.start()
        self.asDocTimer.start()
        self.statusBar.clearStatus()

        # Handle Windows Mode
        self.showNormal()
        if self.mainConf.isFullScreen:
            self.toggleFullScreenMode()

        logger.debug("GUI initialisation complete")

        # Check if a project path was provided at command line, and if
        # not, open the project manager instead.
        if self.mainConf.cmdOpen is not None:
            logger.debug("Opening project from additional command line option")
            self.openProject(self.mainConf.cmdOpen)
        else:
            if self.mainConf.showGUI:
                self.showProjectLoadDialog()

        # Show the latest release notes, if they haven't been shown before
        if hexToInt(self.mainConf.lastNotes) < hexToInt(nw.__hexversion__):
            if self.mainConf.showGUI:
                self.showAboutNWDialog(showNotes=True)
            self.mainConf.lastNotes = nw.__hexversion__

        logger.debug("novelWriter is ready ...")
        self.setStatus("novelWriter is ready ...")

        return

    def clearGUI(self):
        """Wrapper function to clear all sub-elements of the main GUI.
        """
        # Project Area
        self.treeView.clearTree()
        self.treeMeta.clearDetails()

        # Work Area
        self.docEditor.clearEditor()
        self.docEditor.setDictionaries()
        self.closeDocViewer()
        self.projMeta.clearDetails()

        # General
        self.statusBar.clearStatus()
        self._updateWindowTitle()

        return True

    def initMain(self):
        """Initialise elements that depend on user settings.
        """
        self.asProjTimer.setInterval(int(self.mainConf.autoSaveProj*1000))
        self.asDocTimer.setInterval(int(self.mainConf.autoSaveDoc*1000))
        return True

    ##
    #  Project Actions
    ##

    def newProject(self, projData=None):
        """Create new project via the new project wizard.
        """
        if self.hasProject:
            if not self.closeProject():
                self.makeAlert(
                    "Cannot create new project when another project is open.",
                    nwAlert.ERROR
                )
                return False

        if projData is None:
            projData = self.showNewProjectDialog()

        if projData is None:
            return False

        projPath = projData.get("projPath", None)
        if projPath is None or projData is None:
            logger.error("No projData or projPath set")
            return False

        if os.path.isfile(os.path.join(projPath, self.theProject.projFile)):
            self.makeAlert(
                "A project already exists in that location. Please choose another folder.",
                nwAlert.ERROR
            )
            return False

        logger.info("Creating new project")
        if self.theProject.newProject(projData):
            self.rebuildTree()
            self.saveProject()
            self.hasProject = True
            self.docEditor.setDictionaries()
            self.rebuildIndex(beQuiet=True)
            self.statusBar.setRefTime(self.theProject.projOpened)
            self.statusBar.setProjectStatus(True)
            self.statusBar.setDocumentStatus(None)
            self.statusBar.setStatus("New project created ...")
            self._updateWindowTitle(self.theProject.projName)
        else:
            self.theProject.clearProject()
            return False

        return True

    def closeProject(self, isYes=False):
        """Closes the project if one is open. isYes is passed on from
        the close application event so the user doesn't get prompted
        twice to confirm.
        """
        if not self.hasProject:
            # There is no project loaded, everything OK
            return True

        if not isYes:
            msgYes = self.askQuestion(
                "Close Project",
                "Close the current project?<br>Changes are saved automatically."
            )
            if not msgYes:
                return False

        if self.docEditor.docChanged:
            self.saveDocument()

        if self.theProject.projAltered:
            saveOK   = self.saveProject()
            doBackup = False
            if self.theProject.doBackup and self.mainConf.backupOnClose:
                doBackup = True
                if self.mainConf.askBeforeBackup:
                    msgYes = self.askQuestion(
                        "Backup Project", "Backup the current project?"
                    )
                    if not msgYes:
                        doBackup = False
            if doBackup:
                self.theProject.zipIt(False)
        else:
            saveOK = True

        if saveOK:
            self.closeDocument()
            self.docViewer.clearNavHistory()
            self.projView.closeOutline()
            self.theProject.closeProject()
            self.theIndex.clearIndex()
            self.clearGUI()
            self.hasProject = False
            self.tabWidget.setCurrentWidget(self.splitDocs)

        return saveOK

    def openProject(self, projFile):
        """Open a project from a projFile path.
        """
        if projFile is None:
            return False

        # Make sure any open project is cleared out first before we load
        # another one
        if not self.closeProject():
            return False

        # Switch main tab to editor view
        self.tabWidget.setCurrentWidget(self.splitDocs)

        # Try to open the project
        if not self.theProject.openProject(projFile):
            # The project open failed.

            if self.theProject.lockedBy is None:
                # The project is not locked, so failed for some other
                # reason handled by the project class.
                return False

            try:
                lockDetails = (
                    "<br><br>The project was locked by the computer "
                    "'%s' (%s %s), last active on %s"
                ) % (
                    self.theProject.lockedBy[0],
                    self.theProject.lockedBy[1],
                    self.theProject.lockedBy[2],
                    datetime.fromtimestamp(
                        int(self.theProject.lockedBy[3])
                    ).strftime("%x %X")
                )
            except Exception:
                lockDetails = ""

            msgBox = QMessageBox()
            msgRes = msgBox.warning(
                self, "Project Locked", (
                    "The project is already open by another instance of novelWriter, and "
                    "is therefore locked. Override lock and continue anyway?<br><br>"
                    "Note: If the program or the computer previously crashed, the lock "
                    "can safely be overridden. If, however, another instance of "
                    "novelWriter has the project open, overriding the lock may corrupt "
                    "the project, and is not recommended.%s"
                ) % lockDetails,
                QMessageBox.Yes | QMessageBox.No, QMessageBox.No
            )
            if msgRes == QMessageBox.Yes:
                if not self.theProject.openProject(projFile, overrideLock=True):
                    return False
            else:
                return False

        # Project is loaded
        self.hasProject = True

        # Load the tag index
        self.theIndex.loadIndex()

        # Update GUI
        self._updateWindowTitle(self.theProject.projName)
        self.rebuildTree()
        self.docEditor.setDictionaries()
        self.docEditor.setSpellCheck(self.theProject.spellCheck)
        self.mainMenu.setAutoOutline(self.theProject.autoOutline)
        self.statusBar.setRefTime(self.theProject.projOpened)
        self.statusBar.setStats(self.theProject.currWCount, 0)

        # Restore previously open documents, if any
        if self.theProject.lastEdited is not None:
            self.openDocument(self.theProject.lastEdited, doScroll=True)

        if self.theProject.lastViewed is not None:
            self.viewDocument(self.theProject.lastViewed)

        # Check if we need to rebuild the index
        if self.theIndex.indexBroken:
            self.rebuildIndex()

        # Make sure the changed status is set to false on all that was
        # just opened
        qApp.processEvents()
        self.docEditor.setDocumentChanged(False)
        self.theProject.setProjectChanged(False)

        logger.debug("Project load complete")

        return True

    def saveProject(self, autoSave=False):
        """Save the current project.
        """
        if not self.hasProject:
            logger.error("No project open")
            return False

        # If the project is new, it may not have a path, so we need one
        if self.theProject.projPath is None:
            projPath = self.selectProjectPath()
            self.theProject.setProjectPath(projPath)

        if self.theProject.projPath is None:
            return False

        self.treeView.saveTreeOrder()
        self.theProject.saveProject(autoSave=autoSave)
        self.theIndex.saveIndex()

        return True

    ##
    #  Document Actions
    ##

    def closeDocument(self):
        """Close the document and clear the editor and title field.
        """
        if not self.hasProject:
            logger.error("No project open")
            return False

        self.docEditor.saveCursorPosition()
        if self.docEditor.docChanged:
            self.saveDocument()
        self.docEditor.clearEditor()

        return True

    def openDocument(self, tHandle, tLine=None, changeFocus=True, doScroll=False):
        """Open a specific document, optionally at a given line.
        """
        if not self.hasProject:
            logger.error("No project open")
            return False

        self.closeDocument()
        self.tabWidget.setCurrentWidget(self.splitDocs)
        if self.docEditor.loadText(tHandle, tLine):
            if changeFocus:
                self.docEditor.setFocus()
            self.theProject.setLastEdited(tHandle)
            self.treeView.setSelectedHandle(tHandle, doScroll=doScroll)
        else:
            return False

        return True

    def openNextDocument(self, tHandle, wrapAround=False):
        """Opens the next document in the project tree, following the
        document with the given handle. Stops when reaching the end.
        """
        if not self.hasProject:
            logger.error("No project open")
            return False

        self.treeView.flushTreeOrder()
        nHandle = None  # The next handle after tHandle
        fHandle = None  # The first file handle we encounter
        foundIt = False # We've found tHandle, pick the next we see
        for tItem in self.theProject.projTree:
            if tItem is None:
                continue
            if tItem.itemType != nwItemType.FILE:
                continue
            if fHandle is None:
                fHandle = tItem.itemHandle
            if tItem.itemHandle == tHandle:
                foundIt = True
            elif foundIt:
                nHandle = tItem.itemHandle
                break

        if nHandle is not None:
            self.openDocument(nHandle, tLine=0, doScroll=True)
            return True
        elif wrapAround:
            self.openDocument(fHandle, tLine=0, doScroll=True)
            return False

        return False

    def saveDocument(self):
        """Save the current documents.
        """
        if not self.hasProject:
            logger.error("No project open")
            return False

        self.docEditor.saveText()

        return True

    def viewDocument(self, tHandle=None, tAnchor=None):
        """Load a document for viewing in the view panel.
        """
        if not self.hasProject:
            logger.error("No project open")
            return False

        if tHandle is None:
            logger.debug("Viewing document, but no handle provided")

            if self.docEditor.hasFocus():
                logger.verbose("Trying editor document")
                tHandle = self.docEditor.theHandle

            if tHandle is not None:
                self.saveDocument()
            else:
                logger.verbose("Trying selected document")
                tHandle = self.treeView.getSelectedHandle()

            if tHandle is None:
                logger.verbose("Trying last viewed document")
                tHandle = self.theProject.lastViewed

            if tHandle is None:
                logger.verbose("No document to view, giving up")
                return False

        # Make sure main tab is in Editor view
        self.tabWidget.setCurrentWidget(self.splitDocs)

        logger.debug("Viewing document with handle %s" % tHandle)
        if self.docViewer.loadText(tHandle):
            if not self.splitView.isVisible():
                bPos = self.splitMain.sizes()
                self.splitView.setVisible(True)
                vPos = [0, 0]
                vPos[0] = int(bPos[1]/2)
                vPos[1] = bPos[1] - vPos[0]
                self.splitDocs.setSizes(vPos)
                self.viewMeta.setVisible(self.mainConf.showRefPanel)

            self.docViewer.navigateTo(tAnchor)

        return True

    def importDocument(self):
        """Import the text contained in an out-of-project text file, and
        insert the text into the currently open document.
        """
        if not self.hasProject:
            logger.error("No project open")
            return False

        lastPath = self.mainConf.lastPath
        extFilter = [
            "Text files (*.txt)",
            "Markdown files (*.md)",
            "novelWriter files (*.nwd)",
            "All files (*.*)",
        ]
        dlgOpt  = QFileDialog.Options()
        dlgOpt |= QFileDialog.DontUseNativeDialog
        loadFile, _ = QFileDialog.getOpenFileName(
            self, "Import File", lastPath, options=dlgOpt, filter=";;".join(extFilter)
        )
        if not loadFile:
            return False

        if loadFile.strip() == "":
            return False

        theText = None
        try:
            with open(loadFile, mode="rt", encoding="utf8") as inFile:
                theText = inFile.read()
            self.mainConf.setLastPath(loadFile)
        except Exception as e:
            self.makeAlert(
                ["Could not read file. The file must be an existing text file.", str(e)],
                nwAlert.ERROR
            )
            return False

        if self.docEditor.theHandle is None:
            self.makeAlert(
                "Please open a document to import the text file into.",
                nwAlert.ERROR
            )
            return False

        if not self.docEditor.isEmpty():
            msgYes = self.askQuestion("Import Document", (
                "Importing the file will overwrite the current content of the document. "
                "Do you want to proceed?"
            ))
            if not msgYes:
                return False

        self.docEditor.replaceText(theText)

        return True

    def mergeDocuments(self):
        """Merge multiple documents to one single new document.
        """
        if not self.hasProject:
            logger.error("No project open")
            return False

        dlgMerge = GuiDocMerge(self, self.theProject)
        dlgMerge.exec_()

        return True

    def splitDocument(self):
        """Split a single document into multiple documents.
        """
        if not self.hasProject:
            logger.error("No project open")
            return False

        dlgSplit = GuiDocSplit(self, self.theProject)
        dlgSplit.exec_()

        return True

    def passDocumentAction(self, theAction):
        """Pass on document action theAction to the document viewer if
        it has focus, otherwise pass it to the document editor.
        """
        if self.docViewer.hasFocus():
            self.docViewer.docAction(theAction)
        else:
            self.docEditor.docAction(theAction)
        return True

    ##
    #  Tree Item Actions
    ##

    def openSelectedItem(self):
        """Open the selected documents.
        """
        if not self.hasProject:
            logger.error("No project open")
            return False

        tHandle = self.treeView.getSelectedHandle()
        if tHandle is None:
            logger.warning("No item selected")
            return False

        logger.verbose("Opening item %s" % tHandle)
        nwItem = self.theProject.projTree[tHandle]
        if nwItem.itemType == nwItemType.FILE:
            logger.verbose("Requested item %s is a file" % tHandle)
            self.openDocument(tHandle, doScroll=False)
        else:
            logger.verbose("Requested item %s is not a file" % tHandle)

        return True

    def editItem(self, tHandle=None):
        """Open the edit item dialog.
        """
        if not self.hasProject:
            logger.error("No project open")
            return False

        if tHandle is None:
            tHandle = self.treeView.getSelectedHandle()
        if tHandle is None:
            logger.warning("No item selected")
            return

        tItem = self.theProject.projTree[tHandle]
        if tItem is None:
            return
        if tItem.itemType not in nwLists.REG_TYPES:
            return

        logger.verbose("Requesting change to item %s" % tHandle)
        dlgProj = GuiItemEditor(self, self.theProject, tHandle)
        dlgProj.exec_()
        if dlgProj.result() == QDialog.Accepted:
            self.treeView.setTreeItemValues(tHandle)
            self.treeMeta.updateViewBox(tHandle)
            self.docEditor.updateDocInfo(tHandle)
            self.docViewer.updateDocInfo(tHandle)

        return

    def rebuildTree(self):
        """Rebuild the project tree.
        """
        self._makeStatusIcons()
        self._makeImportIcons()
        self.treeView.clearTree()
        self.treeView.buildTree()
        return

    def rebuildIndex(self, beQuiet=False):
        """Rebuild the entire index.
        """
        if not self.hasProject:
            logger.error("No project open")
            return False

        logger.debug("Rebuilding index ...")
        qApp.setOverrideCursor(QCursor(Qt.WaitCursor))
        tStart = time()

        self.treeView.saveTreeOrder()
        self.theIndex.clearIndex()

        theDoc = NWDoc(self.theProject, self)
        for nDone, tItem in enumerate(self.theProject.projTree):

            if tItem is not None:
                self.setStatus("Indexing: '%s'" % tItem.itemName)
            else:
                self.setStatus("Indexing: Unknown item")

            if tItem is not None and tItem.itemType == nwItemType.FILE:
                logger.verbose("Scanning: %s" % tItem.itemName)
                theText = theDoc.openDocument(tItem.itemHandle, showStatus=False)

                # Build tag index
                self.theIndex.scanText(tItem.itemHandle, theText)

                # Get Word Counts
                cC, wC, pC = self.theIndex.getCounts(tItem.itemHandle)
                tItem.setCharCount(cC)
                tItem.setWordCount(wC)
                tItem.setParaCount(pC)
                self.treeView.propagateCount(tItem.itemHandle, wC)
                self.treeView.projectWordCount()

        tEnd = time()
        self.setStatus("Indexing completed in %.1f ms" % ((tEnd - tStart)*1000.0))
        self.docEditor.updateTagHighLighting()
        qApp.restoreOverrideCursor()

        if not beQuiet:
            self.makeAlert("The project index has been successfully rebuilt.", nwAlert.INFO)

        return True

    def rebuildOutline(self):
        """Force a rebuild of the Outline view.
        """
        if not self.hasProject:
            logger.error("No project open")
            return False

        logger.verbose("Forcing a rebuild of the Project Outline")
        self.tabWidget.setCurrentWidget(self.splitOutline)
        self.projView.refreshTree(overRide=True)

        return True

    ##
    #  Main Dialogs
    ##

    def selectProjectPath(self):
        """Select where to save project.
        """
        dlgOpt  = QFileDialog.Options()
        dlgOpt |= QFileDialog.ShowDirsOnly
        dlgOpt |= QFileDialog.DontUseNativeDialog
        projPath = QFileDialog.getExistingDirectory(
            self, "Save novelWriter Project", "", options=dlgOpt
        )
        if projPath:
            return projPath
        return None

    def showProjectLoadDialog(self):
        """Opens the projects dialog for selecting either existing
        projects from a cache of recently opened projects, or provide a
        browse button for projects not yet cached. Selecting to create a
        new project is forwarded to the new project wizard.
        """
        dlgProj = GuiProjectLoad(self)
        dlgProj.exec_()
        if dlgProj.result() == QDialog.Accepted:
            if dlgProj.openState == GuiProjectLoad.OPEN_STATE:
                self.openProject(dlgProj.openPath)
            elif dlgProj.openState == GuiProjectLoad.NEW_STATE:
                self.newProject()

        return True

    def showNewProjectDialog(self):
        """Open the wizard and assemble a project options dict.
        """
        newProj = GuiProjectWizard(self)
        newProj.exec_()

        if newProj.result() == QDialog.Accepted:
            return self._assembleProjectWizardData(newProj)

        return None

    def showPreferencesDialog(self):
        """Open the preferences dialog.
        """
        dlgConf = GuiPreferences(self, self.theProject)
        dlgConf.exec_()

        if dlgConf.result() == QDialog.Accepted:
            logger.debug("Applying new preferences")
            self.initMain()
            self.theTheme.updateTheme()
            self.saveDocument()
            self.docEditor.initEditor()
            self.docViewer.initViewer()
            self.treeView.initTree()
            self.projView.initOutline()
            self.projMeta.initDetails()

        return

    def showProjectSettingsDialog(self):
        """Open the project settings dialog.
        """
        if not self.hasProject:
            logger.error("No project open")
            return

        dlgProj = GuiProjectSettings(self, self.theProject)
        dlgProj.exec_()

        if dlgProj.result() == QDialog.Accepted:
            logger.debug("Applying new project settings")
            self.docEditor.setDictionaries()
            self._updateWindowTitle(self.theProject.projName)

        return

    def showBuildProjectDialog(self):
        """Open the build project dialog.
        """
        if not self.hasProject:
            logger.error("No project open")
            return

        dlgBuild = getGuiItem("GuiBuildNovel")
        if dlgBuild is None:
            dlgBuild = GuiBuildNovel(self, self.theProject)

        dlgBuild.setModal(False)
        dlgBuild.show()
        qApp.processEvents()
        dlgBuild.viewCachedDoc()

        return

    def showWritingStatsDialog(self):
        """Open the session log dialog.
        """
        if not self.hasProject:
            logger.error("No project open")
            return

        dlgStats = getGuiItem("GuiWritingStats")
        if dlgStats is None:
            dlgStats = GuiWritingStats(self, self.theProject)

        dlgStats.setModal(False)
        dlgStats.show()
        qApp.processEvents()
        dlgStats.populateGUI()

        return

    def showAboutNWDialog(self, showNotes=False):
        """Show the about dialog for novelWriter.
        """
        dlgAbout = GuiAbout(self)
        dlgAbout.setModal(True)
        dlgAbout.show()
        qApp.processEvents()
        dlgAbout.populateGUI()

        if showNotes:
            dlgAbout.showReleaseNotes()

        return

    def showAboutQtDialog(self):
        """Show the about dialog for Qt.
        """
        msgBox = QMessageBox()
        msgBox.aboutQt(self, "About Qt")
        return

    def makeAlert(self, theMessage, theLevel=nwAlert.INFO):
        """Alert both the user and the logger at the same time. Message
        can be either a string or an array of strings.
        """
        if isinstance(theMessage, list):
            popMsg = "<br>".join(theMessage)
            logMsg = theMessage
        else:
            popMsg = theMessage
            logMsg = [theMessage]

        # Write to Log
        if theLevel == nwAlert.INFO:
            for msgLine in logMsg:
                logger.info(msgLine)
        elif theLevel == nwAlert.WARN:
            for msgLine in logMsg:
                logger.warning(msgLine)
        elif theLevel == nwAlert.ERROR:
            for msgLine in logMsg:
                logger.error(msgLine)
        elif theLevel == nwAlert.BUG:
            for msgLine in logMsg:
                logger.error(msgLine)

        # Popup
        msgBox = QMessageBox()
        if theLevel == nwAlert.INFO:
            msgBox.information(self, "Information", popMsg)
        elif theLevel == nwAlert.WARN:
            msgBox.warning(self, "Warning", popMsg)
        elif theLevel == nwAlert.ERROR:
            msgBox.critical(self, "Error", popMsg)
        elif theLevel == nwAlert.BUG:
            popMsg += "<br>This is a bug!"
            msgBox.critical(self, "Internal Error", popMsg)

        return

    def askQuestion(self, theTitle, theQuestion):
        """Ask the user a Yes/No question.
        """
        msgBox = QMessageBox()
        msgRes = msgBox.question(self, theTitle, theQuestion)
        return msgRes == QMessageBox.Yes

    def reportConfErr(self):
        """Checks if the Config module has any errors to report, and let
        the user know if this is the case. The Config module caches
        errors since it is initialised before the GUI itself.
        """
        if self.mainConf.hasError:
            self.makeAlert(self.mainConf.getErrData(), nwAlert.ERROR)
            return True
        return False

    ##
    #  Main Window Actions
    ##

    def closeMain(self):
        """Save everything, and close novelWriter.
        """
        if self.hasProject:
            msgYes = self.askQuestion(
                "Exit",
                "Do you want to exit novelWriter?<br>Changes are saved automatically."
            )
            if not msgYes:
                return False

        logger.info("Exiting novelWriter")

        if not self.isFocusMode:
            self.mainConf.setMainPanePos(self.splitMain.sizes())
            self.mainConf.setDocPanePos(self.splitDocs.sizes())
            self.mainConf.setOutlinePanePos(self.splitOutline.sizes())
            if self.viewMeta.isVisible():
                self.mainConf.setViewPanePos(self.splitView.sizes())

        self.mainConf.setShowRefPanel(self.viewMeta.isVisible())
        self.mainConf.setTreeColWidths(self.treeView.getColumnSizes())
        if not self.mainConf.isFullScreen:
            self.mainConf.setWinSize(self.width(), self.height())

        if self.hasProject:
            self.closeProject(True)

        self.mainConf.saveConfig()
        self.reportConfErr()
        self.mainMenu.closeHelp()

        qApp.quit()

        return True

    def setFocus(self, paneNo):
        """Switch focus to one of the three main GUI panes.
        """
        if paneNo == 1:
            self.treeView.setFocus()
        elif paneNo == 2:
            self.docEditor.setFocus()
        elif paneNo == 3:
            self.docViewer.setFocus()
        return

    def closeDocEditor(self):
        """Close the document edit panel. This does not hide the editor.
        """
        self.closeDocument()
        self.theProject.setLastEdited(None)
        return

    def closeDocViewer(self):
        """Close the document view panel.
        """
        self.docViewer.clearViewer()
        self.theProject.setLastViewed(None)
        bPos = self.splitMain.sizes()
        self.splitView.setVisible(False)
        vPos = [bPos[1], 0]
        self.splitDocs.setSizes(vPos)
        return not self.splitView.isVisible()

    def toggleFocusMode(self):
        """Main GUI Focus Mode hides tree, view pane and optionally also
        statusbar and menu.
        """
        if self.docEditor.theHandle is None:
            logger.error("No document open, so not activating Focus Mode")
            self.mainMenu.aFocusMode.setChecked(self.isFocusMode)
            return False

        self.isFocusMode = not self.isFocusMode
        self.mainMenu.aFocusMode.setChecked(self.isFocusMode)
        if self.isFocusMode:
            logger.debug("Activating Focus Mode")
            self.tabWidget.setCurrentWidget(self.splitDocs)
        else:
            logger.debug("Deactivating Focus Mode")

        isVisible = not self.isFocusMode
        self.treePane.setVisible(isVisible)
        self.statusBar.setVisible(isVisible)
        self.mainMenu.setVisible(isVisible)
        self.tabWidget.tabBar().setVisible(isVisible)

        hideDocFooter = self.isFocusMode and self.mainConf.hideFocusFooter
        self.docEditor.docFooter.setVisible(not hideDocFooter)

        if self.splitView.isVisible():
            self.splitView.setVisible(False)
        elif self.docViewer.theHandle is not None:
            self.splitView.setVisible(True)

        return True

    def toggleFullScreenMode(self):
        """Main GUI full screen mode. The mode is tracked by the flag
        in config. This only tracks whether the window has been
        maximised using the internal commands, and may not be correct
        if the user uses the system window manager. Currently, Qt
        doesn't have access to the exact state of the window.
        """
        self.setWindowState(self.windowState() ^ Qt.WindowFullScreen)

        winState = self.windowState() & Qt.WindowFullScreen == Qt.WindowFullScreen
        if winState:
            logger.debug("Activated full screen mode")
        else:
            logger.debug("Deactivated full screen mode")

        self.mainConf.isFullScreen = winState

        return

    ##
    #  Internal Functions
    ##

    def _connectMenuActions(self):
        """Connect to the main window all menu actions that need to be
        available also when the main menu is hidden.
        """
        # Project
        self.addAction(self.mainMenu.aSaveProject)
        self.addAction(self.mainMenu.aExitNW)

        # Document
        self.addAction(self.mainMenu.aSaveDoc)
        self.addAction(self.mainMenu.aFileDetails)

        # Edit
        self.addAction(self.mainMenu.aEditUndo)
        self.addAction(self.mainMenu.aEditRedo)
        self.addAction(self.mainMenu.aEditCut)
        self.addAction(self.mainMenu.aEditCopy)
        self.addAction(self.mainMenu.aEditPaste)
        self.addAction(self.mainMenu.aSelectAll)
        self.addAction(self.mainMenu.aSelectPar)

        # View
        self.addAction(self.mainMenu.aFocusMode)
        self.addAction(self.mainMenu.aFullScreen)

        # Insert
        self.addAction(self.mainMenu.aInsENDash)
        self.addAction(self.mainMenu.aInsEMDash)
        self.addAction(self.mainMenu.aInsEllipsis)
        self.addAction(self.mainMenu.aInsQuoteLS)
        self.addAction(self.mainMenu.aInsQuoteRS)
        self.addAction(self.mainMenu.aInsQuoteLD)
        self.addAction(self.mainMenu.aInsQuoteRD)
        self.addAction(self.mainMenu.aInsMSApos)
        self.addAction(self.mainMenu.aInsHardBreak)
        self.addAction(self.mainMenu.aInsNBSpace)
        self.addAction(self.mainMenu.aInsThinSpace)
        self.addAction(self.mainMenu.aInsThinNBSpace)

        for mAction, _ in self.mainMenu.mInsKWItems.values():
            self.addAction(mAction)

        # Format
        self.addAction(self.mainMenu.aFmtEmph)
        self.addAction(self.mainMenu.aFmtStrong)
        self.addAction(self.mainMenu.aFmtStrike)
        self.addAction(self.mainMenu.aFmtDQuote)
        self.addAction(self.mainMenu.aFmtSQuote)
        self.addAction(self.mainMenu.aFmtHead1)
        self.addAction(self.mainMenu.aFmtHead2)
        self.addAction(self.mainMenu.aFmtHead3)
        self.addAction(self.mainMenu.aFmtHead4)
        self.addAction(self.mainMenu.aFmtComment)
        self.addAction(self.mainMenu.aFmtNoFormat)

        # Tools
        self.addAction(self.mainMenu.aSpellCheck)
        self.addAction(self.mainMenu.aReRunSpell)
        self.addAction(self.mainMenu.aPreferences)

        # Help
        if self.mainConf.hasHelp and self.mainConf.hasAssistant:
            self.addAction(self.mainMenu.aHelpLoc)
        self.addAction(self.mainMenu.aHelpWeb)

        return True

    def _updateWindowTitle(self, projName=None):
        """Set the window title and add the project's working title.
        """
        winTitle = self.mainConf.appName
        if projName is not None:
            winTitle += " - %s" % projName
        self.setWindowTitle(winTitle)
        return True

    def _autoSaveProject(self):
        """Triggered by the auto-save project timer to save the project.
        """
        doSave  = self.hasProject
        doSave &= self.theProject.projChanged
        doSave &= self.theProject.projPath is not None

        if doSave:
            logger.debug("Autosaving project")
            self.saveProject(autoSave=True)

        return

    def _autoSaveDocument(self):
        """Triggered by the auto-save document timer to save the
        document.
        """
        if self.hasProject and self.docEditor.docChanged:
            logger.debug("Autosaving document")
            self.saveDocument()
        return

    def _makeStatusIcons(self):
        """Generate all the item status icons based on project settings.
        """
        self.statusIcons = {}
        iPx = self.mainConf.pxInt(32)
        for sLabel, sCol, _ in self.theProject.statusItems:
            theIcon = QPixmap(iPx, iPx)
            theIcon.fill(QColor(*sCol))
            self.statusIcons[sLabel] = QIcon(theIcon)
        return

    def _makeImportIcons(self):
        """Generate all the item importance icons based on project
        settings.
        """
        self.importIcons = {}
        iPx = self.mainConf.pxInt(32)
        for sLabel, sCol, _ in self.theProject.importItems:
            theIcon = QPixmap(iPx, iPx)
            theIcon.fill(QColor(*sCol))
            self.importIcons[sLabel] = QIcon(theIcon)
        return

    def _assembleProjectWizardData(self, newProj):
        """Extract the user choices from the New Project Wizard and
        store them in a dictionary.
        """
        projData = {
            "projName": newProj.field("projName"),
            "projTitle": newProj.field("projTitle"),
            "projAuthors": newProj.field("projAuthors"),
            "projPath": newProj.field("projPath"),
            "popSample": newProj.field("popSample"),
            "popMinimal": newProj.field("popMinimal"),
            "popCustom": newProj.field("popCustom"),
            "addRoots": [],
            "numChapters": 0,
            "numScenes": 0,
            "chFolders": False,
        }
        if newProj.field("popCustom"):
            addRoots = []
            if newProj.field("addPlot"):
                addRoots.append(nwItemClass.PLOT)
            if newProj.field("addChar"):
                addRoots.append(nwItemClass.CHARACTER)
            if newProj.field("addWorld"):
                addRoots.append(nwItemClass.WORLD)
            if newProj.field("addTime"):
                addRoots.append(nwItemClass.TIMELINE)
            if newProj.field("addObject"):
                addRoots.append(nwItemClass.OBJECT)
            if newProj.field("addEntity"):
                addRoots.append(nwItemClass.ENTITY)
            projData["addRoots"] = addRoots
            projData["numChapters"] = newProj.field("numChapters")
            projData["numScenes"] = newProj.field("numScenes")
            projData["chFolders"] = newProj.field("chFolders")

        return projData

    ##
    #  Events
    ##

    def closeEvent(self, theEvent):
        """Capture the closing event of the GUI and call the close
        function to handle all the close process steps.
        """
        if self.closeMain():
            theEvent.accept()
        else:
            theEvent.ignore()
        return

    ##
    #  Signal Handlers
    ##

    def _treeSingleClick(self):
        """Single click on a project tree item just updates the details
        panel below the tree.
        """
        sHandle = self.treeView.getSelectedHandle()
        if sHandle is not None:
            self.treeMeta.updateViewBox(sHandle)
        return

    def _treeDoubleClick(self, tItem, colNo):
        """The user double-clicked an item in the tree. If it is a file,
        we open it. Otherwise, we do nothing.
        """
        tHandle = tItem.data(self.treeView.C_NAME, Qt.UserRole)
        logger.verbose("User double clicked tree item with handle %s" % tHandle)
        nwItem = self.theProject.projTree[tHandle]
        if nwItem is not None:
            if nwItem.itemType == nwItemType.FILE:
                logger.verbose("Requested item %s is a file" % tHandle)
                self.openDocument(tHandle, changeFocus=False, doScroll=False)
            else:
                logger.verbose("Requested item %s is a folder" % tHandle)

        return

    def _treeKeyPressReturn(self):
        """The user pressed return on an item in the tree. If it is a
        file, we open it. Otherwise, we do nothing. Pressing return does
        not change focus to the editor as double click does.
        """
        tHandle = self.treeView.getSelectedHandle()
        logger.verbose("User pressed return on tree item with handle %s" % tHandle)
        nwItem = self.theProject.projTree[tHandle]
        if nwItem is not None:
            if nwItem.itemType == nwItemType.FILE:
                logger.verbose("Requested item %s is a file" % tHandle)
                self.openDocument(tHandle, changeFocus=False, doScroll=False)
            else:
                logger.verbose("Requested item %s is a folder" % tHandle)
        return

    def _keyPressEscape(self):
        """When the escape key is pressed somewhere in the main window,
        do the following, in order:
        """
        if self.docEditor.docSearch.isVisible():
            self.docEditor.closeSearch()
        elif self.isFocusMode:
            self.toggleFocusMode()
        return

    def _mainTabChanged(self, tabIndex):
        """Activated when the main window tab is changed.
        """
        if tabIndex == self.idxTabEdit:
            logger.verbose("Editor tab activated")
        elif tabIndex == self.idxTabProj:
            logger.verbose("Project outline tab activated")
            if self.hasProject:
                self.projView.refreshTree()
        return
Exemple #42
0
 def resizeEvent(self, ev):
     size = self.tabBar().size()
     QTabWidget.resizeEvent(self, ev)
     self.tabBar().resize(size)
Exemple #43
0
 def __init__(self, parent=None):
     super(LicenseDialog, self).__init__(parent)
     self.resize(420, 320)
     self.setWindowTitle(tr("Credits & Licensing"))
     self.setWindowFlags(Qt.Dialog)
     self.readme = ""
     self.license = ""
     self.thanks = ""
     self.authors = ""
     self.tabWidget = QTabWidget(self)
     self.setCentralWidget(self.tabWidget)
     for folder in (app_folder, os.path.dirname(app_folder)):
         for fname in os.listdir(folder):
             if fname.startswith("LICENSE"):
                 try:
                     f = open(os.path.join(folder, fname), "r")
                 except:
                     pass
                 else:
                     self.license = f.read()
                     f.close()
             elif fname.startswith("THANKS"):
                 try:
                     f = open(os.path.join(folder, fname), "r")
                 except:
                     pass
                 else:
                     self.thanks = f.read()
                     f.close()
             elif fname.startswith("AUTHORS"):
                 try:
                     f = open(os.path.join(folder, fname), "r")
                 except:
                     pass
                 else:
                     self.authors = f.read()
                     f.close()
             elif fname.startswith("README"):
                 try:
                     f = open(os.path.join(folder, fname), "r")
                 except:
                     pass
                 else:
                     self.readme = f.read()
                     f.close()
     self.readmeView = ReadOnlyTextEdit(self)
     self.readmeView.setText(self.readme)
     self.tabWidget.addTab(self.readmeView, tr("&README"))
     self.authorsView = ReadOnlyTextEdit(self)
     self.authorsView.setText(self.authors)
     self.tabWidget.addTab(self.authorsView, tr("&Authors"))
     self.thanksView = ReadOnlyTextEdit(self)
     self.thanksView.setText(self.thanks)
     self.tabWidget.addTab(self.thanksView, tr("&Thanks"))
     self.licenseView = ReadOnlyTextEdit(self)
     self.licenseView.setText(self.license)
     self.tabWidget.addTab(self.licenseView, tr("&License"))
     closeAction = QAction(self)
     closeAction.setShortcuts(["Esc", "Ctrl+W"])
     closeAction.triggered.connect(self.hide)
     self.addAction(closeAction)
     self.toolBar = QToolBar(self)
     self.toolBar.setStyleSheet(blank_toolbar)
     self.toolBar.setMovable(False)
     self.toolBar.setContextMenuPolicy(Qt.CustomContextMenu)
     self.addToolBar(Qt.BottomToolBarArea, self.toolBar)
     self.toolBar.addWidget(HorizontalExpander(self))
     self.closeButton = QPushButton(tr("&OK"), self)
     self.closeButton.clicked.connect(self.close)
     self.toolBar.addWidget(self.closeButton)
     self.closeButton.setFocus()
Exemple #44
0
class AppWindow(QMainWindow):
    onRestart = pyqtSignal(name='onRestart')

    def __init__(self, dwarf_args, flags=None):
        super(AppWindow, self).__init__(flags)

        self.dwarf_args = dwarf_args

        self.session_manager = SessionManager(self)
        self.session_manager.sessionCreated.connect(self.session_created)
        self.session_manager.sessionStopped.connect(self.session_stopped)
        self.session_manager.sessionClosed.connect(self.session_closed)

        self._tab_order = [
            'memory', 'modules', 'ranges', 'jvm-inspector', 'jvm-debugger'
        ]

        self.menu = self.menuBar()
        self._is_newer_dwarf = False
        self.view_menu = None

        #dockwidgets
        self.watchers_dwidget = None
        self.hooks_dwiget = None
        self.bookmarks_dwiget = None
        self.registers_dock = None
        self.console_dock = None
        self.backtrace_dock = None
        self.threads_dock = None
        #panels
        self.asm_panel = None
        self.console_panel = None
        self.context_panel = None
        self.backtrace_panel = None
        self.contexts_list_panel = None
        self.data_panel = None
        self.emulator_panel = None
        self.ftrace_panel = None
        self.hooks_panel = None
        self.bookmarks_panel = None
        self.smali_panel = None
        self.java_inspector_panel = None
        self.java_explorer_panel = None
        self.java_trace_panel = None
        self.memory_panel = None
        self.modules_panel = None
        self.ranges_panel = None
        self.search_panel = None
        self.watchers_panel = None
        self.welcome_window = None

        self._ui_elems = []

        self.setWindowTitle(
            'Dwarf - A debugger for reverse engineers, crackers and security analyst'
        )

        # load external assets
        _app = QApplication.instance()

        self.remove_tmp_dir()

        # themes
        self.prefs = Prefs()
        self.set_theme(self.prefs.get('dwarf_ui_theme', 'black'))

        # load font
        if os.path.exists(utils.resource_path('assets/Anton.ttf')):
            QFontDatabase.addApplicationFont(
                utils.resource_path('assets/Anton.ttf'))
        if os.path.exists(utils.resource_path('assets/OpenSans-Regular.ttf')):
            QFontDatabase.addApplicationFont(
                utils.resource_path('assets/OpenSans-Regular.ttf'))
            font = QFont("OpenSans", 9, QFont.Normal)
            # TODO: add settingsdlg
            font_size = self.prefs.get('dwarf_ui_font_size', 12)
            font.setPixelSize(font_size)
            _app.setFont(font)
            if os.path.exists(utils.resource_path('assets/OpenSans-Bold.ttf')):
                QFontDatabase.addApplicationFont(
                    utils.resource_path('assets/OpenSans-Bold.ttf'))

        # mainwindow statusbar
        self.progressbar = QProgressBar()
        self.progressbar.setRange(0, 0)
        self.progressbar.setVisible(False)
        self.progressbar.setFixedHeight(15)
        self.progressbar.setFixedWidth(100)
        self.progressbar.setTextVisible(False)
        self.progressbar.setValue(30)
        self.statusbar = QStatusBar(self)
        self.statusbar.setAutoFillBackground(False)
        self.statusbar.addPermanentWidget(self.progressbar)
        self.statusbar.setObjectName("statusbar")
        self.setStatusBar(self.statusbar)

        self.main_tabs = QTabWidget(self)
        self.main_tabs.setMovable(False)
        self.main_tabs.setTabsClosable(True)
        self.main_tabs.setAutoFillBackground(True)
        self.main_tabs.tabCloseRequested.connect(self._on_close_tab)
        self.setCentralWidget(self.main_tabs)

        if self.dwarf_args.package is None:
            self.welcome_window = WelcomeDialog(self)
            self.welcome_window.setModal(True)
            self.welcome_window.onIsNewerVersion.connect(
                self._enable_update_menu)
            self.welcome_window.onUpdateComplete.connect(
                self._on_dwarf_updated)
            self.welcome_window.setWindowTitle(
                'Welcome to Dwarf - A debugger for reverse engineers, crackers and security analyst'
            )
            self.welcome_window.onSessionSelected.connect(self._start_session)
            # wait for welcome screen
            self.hide()
            self.welcome_window.show()
        else:
            if dwarf_args.package is not None:
                if dwarf_args.type is None:
                    # no device given check if package is local path
                    if os.path.exists(dwarf_args.package):
                        print('* Starting new LocalSession')
                        self._start_session('local')
                    else:
                        print('use -t to set sessiontype')
                        exit(0)
                else:
                    print('* Starting new Session')
                    self._start_session(dwarf_args.type)

    def _setup_main_menu(self):
        self.menu = self.menuBar()
        dwarf_menu = QMenu('Dwarf', self)
        theme = QMenu('Theme', dwarf_menu)
        theme.addAction('Black')
        theme.addAction('Dark')
        theme.addAction('Light')
        theme.triggered.connect(self._set_theme)
        dwarf_menu.addMenu(theme)
        dwarf_menu.addSeparator()
        if self._is_newer_dwarf:
            dwarf_menu.addAction('Update', self._update_dwarf)
        dwarf_menu.addAction('Close', self.session_manager.session.stop)
        self.menu.addMenu(dwarf_menu)

        session = self.session_manager.session
        if session is not None:
            session_menu = session.main_menu
            if isinstance(session_menu, list):
                for menu in session_menu:
                    self.menu.addMenu(menu)
            else:
                self.menu.addMenu(session_menu)

        self.view_menu = QMenu('View', self)
        subview_menu = QMenu('Subview', self.view_menu)
        subview_menu.addAction('Search',
                               lambda: self.show_main_tab('search'),
                               shortcut=QKeySequence(Qt.CTRL + Qt.Key_F3))
        subview_menu.addAction('Emulator',
                               lambda: self.show_main_tab('emulator'),
                               shortcut=QKeySequence(Qt.CTRL + Qt.Key_F2))
        subview_menu.addAction('Disassembly',
                               lambda: self.show_main_tab('disassembly'),
                               shortcut=QKeySequence(Qt.CTRL + Qt.Key_F5))
        self.view_menu.addMenu(subview_menu)
        self.view_menu.addSeparator()
        self.menu.addMenu(self.view_menu)

        if self.dwarf_args.debug_script:
            debug_menu = QMenu('Debug', self)
            debug_menu.addAction('Reload core', self._menu_reload_core)
            debug_menu.addAction('Debug dwarf js core',
                                 self._menu_debug_dwarf_js)
            self.menu.addMenu(debug_menu)

        about_menu = QMenu('About', self)
        about_menu.addAction('Dwarf on GitHub', self._menu_github)
        about_menu.addAction('Documention', self._menu_documentation)
        about_menu.addAction('Api', self._menu_api)
        about_menu.addAction('Slack', self._menu_slack)
        about_menu.addSeparator()
        about_menu.addAction('Info', self._show_about_dlg)
        self.menu.addMenu(about_menu)

    def _enable_update_menu(self):
        self._is_newer_dwarf = True

    def _update_dwarf(self):
        if self.welcome_window:
            self.welcome_window._update_dwarf()

    def _on_close_tab(self, index):
        tab_text = self.main_tabs.tabText(index)
        if tab_text:
            if tab_text.lower() in self.session_manager.session.non_closable:
                return
            try:
                self._ui_elems.remove(tab_text.lower())
            except ValueError:  # recheck ValueError: list.remove(x): x not in list
                pass
            self.main_tabs.removeTab(index)

    def _handle_tab_change(self):
        for index in range(self.main_tabs.count()):
            tab_name = self.main_tabs.tabText(index).lower().replace(' ', '-')
            if tab_name in self.session_manager.session.non_closable:
                self.main_tabs.tabBar().setTabButton(index, QTabBar.RightSide,
                                                     None)

                if tab_name in self._tab_order:
                    should_index = self._tab_order.index(tab_name)
                    if index != should_index:
                        self.main_tabs.tabBar().moveTab(index, should_index)

    def _on_dwarf_updated(self):
        self.onRestart.emit()

    def remove_tmp_dir(self):
        if os.path.exists('.tmp'):
            shutil.rmtree('.tmp', ignore_errors=True)

    def _set_theme(self, qaction):
        if qaction:
            self.set_theme(qaction.text())

    def _menu_reload_core(self):
        self.dwarf.load_script()

    def _menu_debug_dwarf_js(self):
        you_know_what_to_do = json.loads(
            self.dwarf._script.exports.debugdwarfjs())
        return you_know_what_to_do

    def show_main_tab(self, name):
        # elem doesnt exists? create it
        if name not in self._ui_elems:
            self._create_ui_elem(name)

        index = 0
        name = name.join(name.split()).lower()
        if name == 'memory':
            index = self.main_tabs.indexOf(self.memory_panel)
        elif name == 'ranges':
            index = self.main_tabs.indexOf(self.ranges_panel)
        elif name == 'search':
            index = self.main_tabs.indexOf(self.search_panel)
        elif name == 'modules':
            index = self.main_tabs.indexOf(self.modules_panel)
        elif name == 'disassembly':
            index = self.main_tabs.indexOf(self.asm_panel)
        elif name == 'data':
            index = self.main_tabs.indexOf(self.data_panel)
        elif name == 'emulator':
            index = self.main_tabs.indexOf(self.emulator_panel)
        elif name == 'java-trace':
            index = self.main_tabs.indexOf(self.java_trace_panel)
        elif name == 'jvm-inspector':
            index = self.main_tabs.indexOf(self.java_inspector_panel)
        elif name == 'jvm-debugger':
            index = self.main_tabs.indexOf(self.java_explorer_panel)
        elif name == 'smali':
            index = self.main_tabs.indexOf(self.smali_panel)

        self.main_tabs.setCurrentIndex(index)

    def jump_to_address(self, ptr, show_panel=True):
        if self.memory_panel is not None:
            if show_panel:
                self.show_main_tab('memory')
            self.memory_panel.read_memory(ptr)

    @pyqtSlot(name='mainMenuGitHub')
    def _menu_github(self):
        QDesktopServices.openUrl(QUrl('https://github.com/iGio90/Dwarf'))

    @pyqtSlot(name='mainMenuDocumentation')
    def _menu_api(self):
        QDesktopServices.openUrl(QUrl('https://igio90.github.io/Dwarf/'))

    @pyqtSlot(name='mainMenuApi')
    def _menu_documentation(self):
        QDesktopServices.openUrl(QUrl('https://igio90.github.io/Dwarf/api'))

    @pyqtSlot(name='mainMenuSlack')
    def _menu_slack(self):
        QDesktopServices.openUrl(
            QUrl('https://join.slack.com/t/resecret/shared_invite'
                 '/enQtMzc1NTg4MzE3NjA1LTlkNzYxNTIwYTc2ZTYyOWY1MT'
                 'Q1NzBiN2ZhYjQwYmY0ZmRhODQ0NDE3NmRmZjFiMmE1MDYwN'
                 'WJlNDVjZDcwNGE'))

    def _show_about_dlg(self):
        about_dlg = AboutDialog(self)
        about_dlg.show()

    def _create_ui_elem(self, elem):
        if not isinstance(elem, str):
            return

        if elem not in self._ui_elems:
            self._ui_elems.append(elem)

        if elem == 'watchers':
            from ui.panel_watchers import WatchersPanel
            self.watchers_dwidget = QDockWidget('Watchers', self)
            self.watchers_panel = WatchersPanel(self)
            # dont respond to dblclick mem cant be shown
            # self.watchers_panel.onItemDoubleClicked.connect(
            #    self._on_watcher_clicked)
            self.watchers_panel.onItemRemoved.connect(
                self._on_watcher_removeditem)
            self.watchers_panel.onItemAdded.connect(self._on_watcher_added)
            self.watchers_dwidget.setWidget(self.watchers_panel)
            self.watchers_dwidget.setObjectName('WatchersPanel')
            self.addDockWidget(Qt.LeftDockWidgetArea, self.watchers_dwidget)
            self.view_menu.addAction(self.watchers_dwidget.toggleViewAction())
        elif elem == 'hooks':
            from ui.panel_hooks import HooksPanel
            self.hooks_dwiget = QDockWidget('Breakpoints', self)
            self.hooks_panel = HooksPanel(self)
            self.hooks_panel.onShowMemoryRequest.connect(
                self._on_watcher_clicked)
            self.hooks_panel.onHookRemoved.connect(self._on_hook_removed)
            self.hooks_dwiget.setWidget(self.hooks_panel)
            self.hooks_dwiget.setObjectName('HooksPanel')
            self.addDockWidget(Qt.LeftDockWidgetArea, self.hooks_dwiget)
            self.view_menu.addAction(self.hooks_dwiget.toggleViewAction())
        elif elem == 'bookmarks':
            from ui.panel_bookmarks import BookmarksPanel
            self.bookmarks_dwiget = QDockWidget('Boomarks', self)
            self.bookmarks_panel = BookmarksPanel(self)
            self.bookmarks_panel.onShowMemoryRequest.connect(
                self._on_watcher_clicked)
            self.bookmarks_dwiget.setWidget(self.bookmarks_panel)
            self.bookmarks_dwiget.setObjectName('BookmarksPanel')
            self.addDockWidget(Qt.LeftDockWidgetArea, self.bookmarks_dwiget)
            self.view_menu.addAction(self.bookmarks_dwiget.toggleViewAction())
        elif elem == 'registers':
            from ui.panel_context import ContextPanel
            self.registers_dock = QDockWidget('Context', self)
            self.context_panel = ContextPanel(self)
            self.registers_dock.setWidget(self.context_panel)
            self.registers_dock.setObjectName('ContextsPanel')
            self.addDockWidget(Qt.RightDockWidgetArea, self.registers_dock)
            self.view_menu.addAction(self.registers_dock.toggleViewAction())
        elif elem == 'memory':
            from ui.panel_memory import MemoryPanel
            self.memory_panel = MemoryPanel(self)
            self.memory_panel.onShowDisassembly.connect(
                self._disassemble_range)
            self.memory_panel.dataChanged.connect(self._on_memory_modified)
            self.memory_panel.statusChanged.connect(self.set_status_text)
            self.main_tabs.addTab(self.memory_panel, 'Memory')
        elif elem == 'jvm-debugger':
            from ui.panel_java_explorer import JavaExplorerPanel
            self.java_explorer_panel = JavaExplorerPanel(self)
            self.main_tabs.addTab(self.java_explorer_panel, 'JVM debugger')
            self.main_tabs.tabBar().moveTab(
                self.main_tabs.indexOf(self.java_explorer_panel), 1)
        elif elem == 'jvm-inspector':
            from ui.panel_java_inspector import JavaInspector
            self.java_inspector_panel = JavaInspector(self)
            self.main_tabs.addTab(self.java_inspector_panel, 'JVM inspector')
        elif elem == 'console':
            from ui.panel_console import ConsolePanel
            self.console_dock = QDockWidget('Console', self)
            self.console_panel = ConsolePanel(self)
            if self.dwarf_args.script and len(
                    self.dwarf_args.script) > 0 and os.path.exists(
                        self.dwarf_args.script):
                with open(self.dwarf_args.script, 'r') as f:
                    self.console_panel.get_js_console(
                    ).function_content = f.read()
            self.dwarf.onLogToConsole.connect(self._log_js_output)
            self.dwarf.onLogEvent.connect(self._log_event)
            self.console_dock.setWidget(self.console_panel)
            self.console_dock.setObjectName('ConsolePanel')
            self.addDockWidget(Qt.BottomDockWidgetArea, self.console_dock)
            self.view_menu.addAction(self.console_dock.toggleViewAction())
        elif elem == 'backtrace':
            from ui.panel_backtrace import BacktracePanel
            self.backtrace_dock = QDockWidget('Backtrace', self)
            self.backtrace_panel = BacktracePanel(self)
            self.backtrace_dock.setWidget(self.backtrace_panel)
            self.backtrace_dock.setObjectName('BacktracePanel')
            self.backtrace_panel.onShowMemoryRequest.connect(
                self._on_watcher_clicked)
            self.addDockWidget(Qt.RightDockWidgetArea, self.backtrace_dock)
            self.view_menu.addAction(self.backtrace_dock.toggleViewAction())
        elif elem == 'threads':
            from ui.panel_contexts_list import ContextsListPanel
            self.threads_dock = QDockWidget('Threads', self)
            self.contexts_list_panel = ContextsListPanel(self)
            self.dwarf.onThreadResumed.connect(
                self.contexts_list_panel.resume_tid)
            self.contexts_list_panel.onItemDoubleClicked.connect(
                self._manually_apply_context)
            self.threads_dock.setWidget(self.contexts_list_panel)
            self.threads_dock.setObjectName('ThreadPanel')
            self.addDockWidget(Qt.RightDockWidgetArea, self.threads_dock)
            self.view_menu.addAction(self.threads_dock.toggleViewAction())
        elif elem == 'modules':
            from ui.panel_modules import ModulesPanel
            self.modules_panel = ModulesPanel(self)
            self.modules_panel.onModuleSelected.connect(
                self._on_module_dblclicked)
            self.modules_panel.onModuleFuncSelected.connect(
                self._on_modulefunc_dblclicked)
            self.modules_panel.onAddHook.connect(self._on_addmodule_hook)
            self.modules_panel.onDumpBinary.connect(self._on_dumpmodule)
            self.main_tabs.addTab(self.modules_panel, 'Modules')
        elif elem == 'ranges':
            from ui.panel_ranges import RangesPanel
            self.ranges_panel = RangesPanel(self)
            self.ranges_panel.onItemDoubleClicked.connect(
                self._range_dblclicked)
            self.ranges_panel.onDumpBinary.connect(self._on_dumpmodule)
            # connect to watcherpanel func
            self.ranges_panel.onAddWatcher.connect(
                self.watchers_panel.do_addwatcher_dlg)
            self.main_tabs.addTab(self.ranges_panel, 'Ranges')
        elif elem == 'search':
            from ui.panel_search import SearchPanel
            self.search_panel = SearchPanel(self)
            self.search_panel.onShowMemoryRequest.connect(
                self._on_watcher_clicked)
            self.main_tabs.addTab(self.search_panel, 'Search')
        elif elem == 'data':
            from ui.panel_data import DataPanel
            self.data_panel = DataPanel(self)
            self.main_tabs.addTab(self.data_panel, 'Data')
        elif elem == 'disassembly':
            from ui.widgets.disasm_view import DisassemblyView
            self.asm_panel = DisassemblyView(self)
            self.asm_panel.onShowMemoryRequest.connect(self._on_disasm_showmem)
            self.main_tabs.addTab(self.asm_panel, 'Disassembly')
        elif elem == 'emulator':
            from ui.panel_emulator import EmulatorPanel
            self.emulator_panel = EmulatorPanel(self)
            self.main_tabs.addTab(self.emulator_panel, 'Emulator')
        elif elem == 'java-trace':
            from ui.panel_java_trace import JavaTracePanel
            self.java_trace_panel = JavaTracePanel(self)
            self.main_tabs.addTab(self.java_trace_panel, 'JVM tracer')
        elif elem == 'smali':
            from ui.panel_smali import SmaliPanel
            self.smali_panel = SmaliPanel()
            self.main_tabs.addTab(self.smali_panel, 'Smali')
        else:
            print('no handler for elem: ' + elem)

        # make tabs unclosable and sort
        self._handle_tab_change()

        # TODO: remove add @2x
        for item in self.findChildren(QDockWidget):
            if item:
                if 'darwin' in sys.platform:
                    item.setStyleSheet(
                        'QDockWidget::title { padding-left:-30px; }')

    def set_theme(self, theme):
        if theme:
            theme = theme.replace(os.pardir, '').replace('.', '')
            theme = theme.join(theme.split()).lower()
            theme_style = 'assets/' + theme + '_style.qss'
            if not os.path.exists(utils.resource_path(theme_style)):
                return

            self.prefs.put('dwarf_ui_theme', theme)

            try:
                _app = QApplication.instance()
                with open(theme_style) as stylesheet:
                    _app.setStyleSheet(_app.styleSheet() + '\n' +
                                       stylesheet.read())
            except Exception as e:
                pass
                # err = self.dwarf.spawn(dwarf_args.package, dwarf_args.script)

    def set_status_text(self, txt):
        self.statusbar.showMessage(txt)

    # ************************************************************************
    # **************************** Properties ********************************
    # ************************************************************************
    @property
    def disassembly(self):
        return self.asm_panel

    @property
    def backtrace(self):
        return self.backtrace_panel

    @property
    def console(self):
        return self.console_panel

    @property
    def context(self):
        return self.context_panel

    @property
    def threads(self):
        return self.contexts_list_panel

    @property
    def emulator(self):
        return self.emulator_panel

    @property
    def ftrace(self):
        return self.ftrace_panel

    @property
    def hooks(self):
        return self.hooks_panel

    @property
    def java_inspector(self):
        return self.java_inspector_panel

    @property
    def java_explorer(self):
        return self.java_explorer_panel

    @property
    def memory(self):
        return self.memory_panel

    @property
    def modules(self):
        return self.memory_panel

    @property
    def ranges(self):
        return self.ranges_panel

    @property
    def watchers(self):
        return self.watchers_panel

    @property
    def dwarf(self):
        if self.session_manager.session is not None:
            return self.session_manager.session.dwarf
        else:
            return None

    # ************************************************************************
    # **************************** Handlers **********************************
    # ************************************************************************
    # session handlers
    def _start_session(self, session_type, session_data=None):
        if self.welcome_window is not None:
            self.welcome_window.close()
        self.session_manager.create_session(session_type,
                                            session_data=session_data)

    def _restore_session(self, session_data):
        if 'session' in session_data:
            session_type = session_data['session']
            self._start_session(session_type, session_data=session_data)

    def session_created(self):
        # session init done create ui for it
        session = self.session_manager.session
        self._setup_main_menu()
        for ui_elem in session.session_ui_sections:
            ui_elem = ui_elem.join(ui_elem.split()).lower()
            self._create_ui_elem(ui_elem)

        self.dwarf.onProcessAttached.connect(self._on_attached)
        self.dwarf.onProcessDetached.connect(self._on_detached)
        self.dwarf.onScriptLoaded.connect(self._on_script_loaded)

        # hookup
        self.dwarf.onSetRanges.connect(self._on_setranges)
        self.dwarf.onSetModules.connect(self._on_setmodules)

        self.dwarf.onAddNativeHook.connect(self._on_add_hook)
        self.dwarf.onApplyContext.connect(self._apply_context)
        self.dwarf.onThreadResumed.connect(self.on_tid_resumed)

        self.dwarf.onSetData.connect(self._on_set_data)

        self.session_manager.start_session(self.dwarf_args)
        q_settings = QSettings("dwarf_window_pos.ini", QSettings.IniFormat)
        ui_state = q_settings.value('dwarf_ui_state')
        if ui_state:
            self.restoreGeometry(ui_state)
        window_state = q_settings.value('dwarf_ui_window', self.saveState())
        if window_state:
            self.restoreState(window_state)

        self.showMaximized()

    def session_stopped(self):
        self.remove_tmp_dir()
        self.menu.clear()

        self.main_tabs.clear()

        # actually we need to kill this. needs a refactor
        if self.java_trace_panel is not None:
            self.java_trace_panel = None

        for elem in self._ui_elems:
            if elem == 'watchers':
                self.watchers_panel.clear_list()
                self.watchers_panel.close()
                self.watchers_panel = None
                self.removeDockWidget(self.watchers_dwidget)
                self.watchers_dwidget = None
            elif elem == 'hooks':
                self.hooks_panel.close()
                self.hooks_panel = None
                self.removeDockWidget(self.hooks_dwiget)
                self.hooks_dwiget = None
            elif elem == 'registers':
                self.context_panel.close()
                self.context_panel = None
                self.removeDockWidget(self.registers_dock)
                self.registers_dock = None
            elif elem == 'memory':
                self.memory_panel.close()
                self.memory_panel = None
                self.main_tabs.removeTab(0)
                # self.main_tabs
            elif elem == 'jvm-debugger':
                self.java_explorer_panel.close()
                self.java_explorer_panel = None
                self.removeDockWidget(self.watchers_dwidget)
            elif elem == 'console':
                self.console_panel.close()
                self.console_panel = None
                self.removeDockWidget(self.console_dock)
                self.console_dock = None
            elif elem == 'backtrace':
                self.backtrace_panel.close()
                self.backtrace_panel = None
                self.removeDockWidget(self.backtrace_dock)
            elif elem == 'threads':
                self.contexts_list_panel.close()
                self.contexts_list_panel = None
                self.removeDockWidget(self.threads_dock)
                self.threads_dock = None
            elif elem == 'bookmarks':
                self.bookmarks_panel.close()
                self.bookmarks_panel = None
                self.removeDockWidget(self.bookmarks_dwiget)
                self.bookmarks_dwiget = None

    def session_closed(self):
        self._ui_elems = []
        self.hide()
        if self.welcome_window is not None:
            self.welcome_window.exec()

        # close if it was a commandline session
        if self.welcome_window is None:
            if self.dwarf_args.package:
                self.close()

    # ui handler
    def closeEvent(self, event):
        """ Window closed
            save stuff or whatever at exit

            detaches dwarf
        """
        # save windowstuff
        q_settings = QSettings("dwarf_window_pos.ini", QSettings.IniFormat)
        q_settings.setValue('dwarf_ui_state', self.saveGeometry())
        q_settings.setValue('dwarf_ui_window', self.saveState())

        if self.dwarf:
            self.dwarf.detach()
        super().closeEvent(event)

    def _on_watcher_clicked(self, ptr):
        """ Address in Watcher/Hookpanel was clicked
            show Memory
        """
        if '.' in ptr:  # java_hook
            file_path = ptr.replace('.', os.path.sep)
            if os.path.exists('.tmp/smali/' + file_path + '.smali'):
                if self.smali_panel is None:
                    self._create_ui_elem('smali')
                self.smali_panel.set_file('.tmp/smali/' + file_path + '.smali')
                self.show_main_tab('smali')
        else:
            self.memory_panel.read_memory(ptr=ptr)
            self.show_main_tab('memory')

    def _on_disasm_showmem(self, ptr, length):
        """ Address in Disasm was clicked
            adds temphighlight for bytes from current instruction
        """
        self.memory_panel.read_memory(ptr)
        self.memory_panel.add_highlight(
            HighLight('attention', utils.parse_ptr(ptr), length))
        self.show_main_tab('memory')

    def _on_watcher_added(self, ptr):
        """ Watcher Entry was added
        """
        try:
            # set highlight
            self.memory_panel.add_highlight(
                HighLight('watcher', ptr, self.dwarf.pointer_size))
        except HighlightExistsError:
            pass

    def _on_watcher_removeditem(self, ptr):
        """ Watcher Entry was removed
            remove highlight too
        """
        self.memory_panel.remove_highlight(ptr)

    def _on_module_dblclicked(self, data):
        """ Module in ModulePanel was doubleclicked
        """
        addr, size = data
        addr = utils.parse_ptr(addr)
        size = int(size, 10)
        self.memory_panel.read_memory(ptr=addr, length=size)
        self.show_main_tab('Memory')

    def _on_modulefunc_dblclicked(self, ptr):
        """ Function in ModulePanel was doubleclicked
        """
        ptr = utils.parse_ptr(ptr)
        self.memory_panel.read_memory(ptr=ptr)
        self.show_main_tab('Memory')

    def _on_dumpmodule(self, data):
        """ DumpBinary MenuItem in ModulePanel was selected
        """
        ptr, size = data
        ptr = utils.parse_ptr(ptr)
        size = int(size, 10)
        self.dwarf.dump_memory(ptr=ptr, length=size)

    def _disassemble_range(self, mem_range):
        """ Disassemble MenuItem in Hexview was selected
        """
        if mem_range:
            if self.asm_panel is None:
                self._create_ui_elem('disassembly')

            if mem_range:
                self.asm_panel.disassemble(mem_range)
                self.show_main_tab('disassembly')

    def _range_dblclicked(self, ptr):
        """ Range in RangesPanel was doubleclicked
        """
        ptr = utils.parse_ptr(ptr)
        self.memory_panel.read_memory(ptr=ptr)
        self.show_main_tab('Memory')

    # dwarf handlers
    def _log_js_output(self, output):
        if self.console_panel is not None:
            self.console_panel.get_js_console().log(output)

    def _log_event(self, output):
        if self.console_panel is not None:
            self.console_panel.get_events_console().log(output)

    def _on_setranges(self, ranges):
        """ Dwarf wants to set Ranges
            only hooked up to switch tab or create ui
            its connected in panel after creation
        """
        if self.ranges_panel is None:
            self.show_main_tab('ranges')
            # forward only now to panel it connects after creation
            self.ranges_panel.set_ranges(ranges)

    def _on_setmodules(self, modules):
        """ Dwarf wants to set Modules
            only hooked up to switch tab or create ui
            its connected in panel after creation
        """
        if self.modules_panel is None:
            self._create_ui_elem('modules')
            self.modules_panel.set_modules(modules)

        if self.modules_panel is not None:
            self.show_main_tab('modules')

    def _manually_apply_context(self, context):
        """
        perform additional operation if the context has been manually applied from the context list
        """
        self._apply_context(context, manual=True)

    def _apply_context(self, context, manual=False):
        # update current context tid
        # this should be on top as any further api from js needs to be executed on that thread
        is_initial_hook = context['reason'] >= 0
        if manual or (self.dwarf.context_tid and not is_initial_hook):
            self.dwarf.context_tid = context['tid']

        if 'context' in context:
            if not manual:
                self.threads.add_context(context)

            is_java = context['is_java']
            if is_java:
                if self.java_explorer_panel is None:
                    self._create_ui_elem('jvm-debugger')
                self.context_panel.set_context(context['ptr'], 1,
                                               context['context'])
                self.java_explorer_panel._set_handle_arg(-1)
                self.show_main_tab('jvm-debugger')
            else:
                self.context_panel.set_context(context['ptr'], 0,
                                               context['context'])

                if 'pc' in context['context']:
                    if not 'disassembly' in self._ui_elems or manual:
                        from lib.range import Range
                        _range = Range(Range.SOURCE_TARGET, self.dwarf)
                        _range.init_with_address(
                            int(context['context']['pc']['value'], 16))

                        self._disassemble_range(_range)

        if 'backtrace' in context:
            self.backtrace_panel.set_backtrace(context['backtrace'])

    def _on_add_hook(self, hook):
        try:
            # set highlight
            ptr = hook.get_ptr()
            ptr = utils.parse_ptr(ptr)
            self.memory_panel.add_highlight(
                HighLight('hook', ptr, self.dwarf.pointer_size))
        except HighlightExistsError:
            pass

    def _on_hook_removed(self, ptr):
        ptr = utils.parse_ptr(ptr)
        self.memory_panel.remove_highlight(ptr)

    def _on_addmodule_hook(self, data):
        ptr, name = data
        self.dwarf.hook_native(ptr, own_input=name)

    def on_tid_resumed(self, tid):
        if self.dwarf:
            if self.dwarf.context_tid == tid:
                # clear backtrace
                if 'backtrace' in self._ui_elems:
                    if self.backtrace_panel is not None:
                        self.backtrace_panel.clear()

                # remove thread
                if 'threads' in self._ui_elems:
                    if self.contexts_list_panel is not None:
                        self.contexts_list_panel.resume_tid(tid)

                # clear registers
                if 'registers' in self._ui_elems:
                    if self.context_panel is not None:
                        self.context_panel.clear()

                # clear jvm explorer
                if 'jvm-debugger' in self._ui_elems:
                    if self.java_explorer_panel is not None:
                        self.java_explorer_panel.clear_panel()

                # invalidate dwarf context tid
                self.dwarf.context_tid = 0

    def _on_set_data(self, data):
        if not isinstance(data, list):
            return

        if self.data_panel is None:
            self._create_ui_elem('data')

        if self.data_panel is not None:
            self.show_main_tab('Data')
            self.data_panel.append_data(data[0], data[1], data[2])

    def show_progress(self, text):
        self.progressbar.setVisible(True)
        self.set_status_text(text)

    def hide_progress(self):
        self.progressbar.setVisible(False)
        self.set_status_text('')

    def _on_attached(self, data):
        self.setWindowTitle('Dwarf - Attached to %s (%s)' % (data[1], data[0]))

    def _on_detached(self, data):
        reason = data[1]

        if reason == 'application-requested':
            self.session_manager.session.stop()
            return 0

        ret = QDialogDetached.show_dialog(self.dwarf, data[0], data[1],
                                          data[2])
        if ret == 0:
            self.dwarf.restart_proc()
        elif ret == 1:
            self.session_manager.session.stop()

        return 0

    def _on_script_loaded(self):
        # restore the loaded session if any
        self.session_manager.restore_session()

    def _on_memory_modified(self, pos, length):
        data_pos = self.memory_panel.base + pos
        data = self.memory_panel.data[pos:pos + length]
        data = [data[0]]  # todo: strange js part

        if self.dwarf.dwarf_api('writeBytes', [data_pos, data]):
            pass
        else:
            utils.show_message_box('Failed to write Memory')

    def on_add_bookmark(self, ptr):
        """
        provide ptr as int
        """
        if self.bookmarks_panel is not None:
            self.bookmarks_panel._create_bookmark(ptr=hex(ptr))
Exemple #45
0
class MyTableWidget(QWidget):
    
    def __init__(self, parent):
        super(QWidget, self).__init__(parent)
        self.layout = QVBoxLayout(self)
        #self.setStyleSheet("background-color:grey")
        self.setAutoFillBackground(True)
        
        # Initialize tab screen
        self.tabs = QTabWidget()
        self.tab1 = QWidget()
        self.tab2 = QWidget()
        self.tabs.resize(300,200)
        
        # Add tabs
        self.tabs.addTab(self.tab1,"Main")
        self.tabs.addTab(self.tab2,"Config")
        
        # Create first tab
        self.tab1.layout = QGridLayout(self)
        
        # Create Load button
        self.loadButton = QPushButton("Load Gcode")
        self.loadButton.clicked.connect(self.loadGcode)
        self.tab1.layout.addWidget(self.loadButton,0,0)
        # Create Gcode File Dir textbox
        self.gcodeDirTextBox = QLabel("Load Gcode file")
        self.gcodeDirTextBox.setAlignment(Qt.Qt.AlignCenter)
        self.tab1.layout.addWidget(self.gcodeDirTextBox,0,1,1,2)
        
        # Create Connect button
        self.connectButton = QPushButton("Connect")
        self.tab1.layout.addWidget(self.connectButton,1,0)
        self.connectButton.clicked.connect(self.connect)
        # Create Print button
        self.Print = QPushButton("Print")
        self.tab1.layout.addWidget(self.Print,1,1)
        self.Print.clicked.connect(self.machinePrint)
        
        #create pause button
        self.pauseButton = QPushButton("Pause")
        self.tab1.layout.addWidget(self.pauseButton,1,2)
        self.pauseButton.clicked.connect(self.pause)
#create machine group box
        hBox = QGridLayout()
        groupBox = QGroupBox()
#create input command for both machine
        #both input group box
        generalInputGroupBox = QGroupBox("Send To Both")
        generalInputGroupBoxLayout = QGridLayout()
        #command input box
        self.generalInputCommandBox = QLineEdit("SEND TO BOTH")
        #Send button
        generalInputSendButton = QPushButton("SEND")
        generalInputSendButton.clicked.connect(self.sendToALL)

        generalInputGroupBoxLayout.addWidget(self.generalInputCommandBox,0,0,1,2)
        generalInputGroupBoxLayout.addWidget(generalInputSendButton,0,2)
        generalInputGroupBox.setLayout(generalInputGroupBoxLayout)

#create machine one group
        groupBox1 = QGroupBox("Machine One")
        hBox1 = QGridLayout()
        #create machine one port8
        self.portOneButton = QLineEdit("COM7")
        self.portOne = "COM7"
        self.portOneButton.textChanged.connect(self.updatePortName)
        #create machine one baudrate
        baudrateOneButton = QLineEdit("115200")
        self.baudrateOne = 115200
        #create machine one send comman box
        self.oneInputCommandBox = QLineEdit("SEND TO ONE")
        oneInputSendButton = QPushButton("SEND")
        oneInputSendButton.clicked.connect(self.sendToOne)

        hBox1.addWidget(self.portOneButton,0,0)
        hBox1.addWidget(baudrateOneButton,0,1)
        hBox1.addWidget(self.oneInputCommandBox,1,0,1,2)
        hBox1.addWidget(oneInputSendButton,1,3)
        groupBox1.setLayout(hBox1)
#create machine two group
        groupBox2 = QGroupBox("Machine Two")
        hBox2 = QGridLayout()
        #create machine two port
        self.portTwoButton = QLineEdit("COM8")
        self.portTwo = "COM8"
        self.portTwoButton.textChanged.connect(self.updatePortName)
        
        #create machine two baudrate
        baudrateTwoButton = QLineEdit("115200")
        self.baudrateTwo = 115200
        #create machine one send comman box
        self.twoInputCommandBox = QLineEdit("SEND TO TWO")
        twoInputSendButton = QPushButton("SEND")
        twoInputSendButton.clicked.connect(self.sendToTwo)


        hBox2.addWidget(self.portTwoButton,0,0)
        hBox2.addWidget(baudrateTwoButton,0,1)
        hBox2.addWidget(self.twoInputCommandBox,1,0,1,2)
        hBox2.addWidget(twoInputSendButton,1,3)
        groupBox2.setLayout(hBox2)


        hBox.addWidget(generalInputGroupBox,0,0,1,2)
        hBox.addWidget(groupBox1,1,0)
        hBox.addWidget(groupBox2,1,1)
        groupBox.setLayout(hBox)
        self.tab1.layout.addWidget(groupBox,2,0,1,3)
        #################
        self.tab1.setLayout(self.tab1.layout)
        
        # Add tabs to widget
        self.layout.addWidget(self.tabs)
        self.setLayout(self.layout)


################################## ALL SLOT HERE ####################################################

    @pyqtSlot()
    def loadGcode(self):
        print("load gcode file")
        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        fileName, _ = QFileDialog.getOpenFileName(self,"QFileDialog.getOpenFileName()", "","All Files (*);;Python Files (*.gcode)", options=options)
        if fileName:
            print(fileName)
            self.gcodeDir = fileName
            self.gcodeDirTextBox.setText(fileName)
        self.splitGcode()
    @pyqtSlot()
    def doConnect(self):
        try:
            print("connect to machine")
            self.onePrinter = virtualPrinter.typeOnePrinter("nameOne","Gcode/one.gcode",self.portOne,self.baudrateOne)
            self.twoPrinter = virtualPrinter.typeTwoPrinter("nameTwo","Gcode/two.gcode",self.portTwo,self.baudrateTwo)

            # get gcode data 
            self.onePrinter.getGcodeData()
            self.twoPrinter.getGcodeData()


            # get friend printer
            self.onePrinter.getFirstFriendPrinter(self.twoPrinter)
            self.twoPrinter.getFirstFriendPrinter(self.onePrinter)

            # Connect One Printer
            self.onePrinter.connectToPrinter()
            #Connect Two Printer
            self.twoPrinter.connectToPrinter()

            print("Connect OK")
           
        except:
            print("can not connect to machine")
            print(Exception)
    def connect(self):
         x = threading.Thread(target = self.doConnect)
         x.daemon = True
         x.start()
    def updatePortName(self):
        self.portOne = str(self.portOneButton.text())
        self.portTwo = str(self.portTwoButton.text())
        print(self.portOne,self.portTwo)

    def doMachineOnePrint(self):
        try:
            print("3D printer print")
            virtualPrinter.runningEvent.set()
            self.onePrinter.start()
            self.onePrinter.join()
        except:
            print("Connect before print")
    def doMachineTwoPrint(self):
        try:
            print("3D printer print")
            self.twoPrinter.start()
            self.twoPrinter.join()
        except:
            print("Connect before print")
    @pyqtSlot()
    def machinePrint(self):
        
        x = threading.Thread(target=self.doMachineOnePrint)
        y = threading.Thread(target=self.doMachineTwoPrint)
        x.daemon = True
        y.daemon = True
        y.start()
        x.start()

    def splitGcode(self):
        try:
            gcodesplit.split(self.gcodeDir)
            print("Split OK")
        except:
            print("can not split gcode")
    @pyqtSlot()
    def pause(self):
        virtualPrinter.runningEvent.clear()
        print("pause")

    def doSendToAll(self):
        try:
            self.twoPrinter.sendGcode(str(self.generalInputCommandBox.text()))
            self.onePrinter.sendGcode(str(self.generalInputCommandBox.text()))
        except:
            print("Can not send to all")
    
    def sendToALL(self):
        x = threading.Thread(target=self.doSendToAll)
        x.start()
    def doSendToOne(self):
        try:
            self.onePrinter.sendGcode(str(self.oneInputCommandBox.text()))
        except:
            print("Can not send to one")
    def sendToOne(self):
        x = threading.Thread(target=self.doSendToOne)
        x.daemon = True
        x.start()
    def doSendToTwo(self):
        try:
            self.twoPrinter.sendGcode(str(self.twoInputCommandBox.text()))
        except:
            print("Can not send to two")
    def sendToTwo(self):
        x = threading.Thread(target=self.doSendToTwo)
        x.daemon = True
        x.start()
Exemple #46
0
class ModeBResultsWidget(QWidget):
    def __init__(self, models, phaseNames, phaseValues, results, parent=None):
        super().__init__()
        self.models = models
        self.phaseNames = phaseNames
        self.phaseValues = phaseValues
        self.results = results
        self.tabWidget = QTabWidget()

        self.tabWidget.addTab(self.modeBResultPlot(), "Mode 2 Results")
        self.tabWidget.addTab(self.mode3ResultPlot(), "Mode 3 Results")

        layout = QVBoxLayout(self)
        layout.addWidget(self.tabWidget)
        #self.setLayout(self.resultPlot())
        self.show()

    def modeBResultPlot(self):
        widget = QWidget()
        fig = plt.figure()
        canvas = FigureCanvas(fig)
        toolbar = NavigationToolbar(canvas, self)
        ax = fig.add_subplot(111)
        ax.set_xticklabels([""] + self.phaseNames)  #Shifting names
        a = self.models[-1].a_est
        b = self.models[-1].b_est
        c = self.models[-1].c_est
        self.estTotalErrors = self.models[-1].a_est
        self.selPeakLocation = self.models[-1].get_peak_loc()
        self.numLatentErrors = self.models[-1].fi_t(a, b, c, len(self.models))
        self.eff = (1 - self.numLatentErrors / a) * 100
        #ax.bar([i+1-0.1 for i in range(len(self.models))], [m.kVec_cumu_sum[-1] for m in self.models], width=0.2, color='b', label="Actual")
        #ax.bar([i+1+0.1 for i in range(len(self.models))], [m.MVF(m.tVec[-1], a, b, c) for i, m in enumerate(self.models)], width=0.2, color='r', label="Estimated")
        ax.bar([i + 1 - 0.1 for i in range(len(self.phaseNames))],
               np.cumsum(self.phaseValues),
               width=0.2,
               color='b',
               label="Actual")
        ax.bar([i + 1 + 0.1 for i in range(len(self.phaseNames))], [
            self.models[-1].MVF(t + 1, a, b, c)
            for t in range(len(self.phaseNames))
        ],
               width=0.2,
               color='r',
               label="Estimated")

        ax.set_xlabel("Phases")
        ax.set_ylabel("Cumulative Defects")
        ax.set_title("Defect Discovery Data and Fitted Histograms")
        ax.legend()
        canvas.draw()
        plt.grid(True)

        self.setWindowTitle('SwEET - Mode B Results')
        layoutfig = QVBoxLayout()
        layoutfig.addWidget(toolbar)
        layoutfig.addWidget(canvas, 1)
        widget.setLayout(layoutfig)
        plt.tight_layout()
        return widget

    def mode3ResultPlot(self):
        widget = QWidget()
        fig = plt.figure()
        #plt.tight_layout()
        plt.grid(True)
        canvas = FigureCanvas(fig)
        toolbar = NavigationToolbar(canvas, self)
        ax = fig.add_subplot(111)
        ax.set_xticklabels([""] + self.phaseNames)
        ax.plot(self.results['lower'], color='g', label='Lower')
        #ax.bar([i+1-0.2 for i in range(len(self.phaseNames))], self.results['lower'], width=0.2, color='g', label="Lower")
        ax.plot(self.results['nominal'], color='b', label='Nominal')
        #ax.bar([i+1 for i in range(len(self.phaseNames))], self.results['nominal'], width=0.2, color='b', label="Nominal")
        ax.plot(self.results['upper'], color='r', label='Upper')
        #ax.bar([i+1+0.2 for i in range(len(self.phaseNames))], self.results['upper'], width=0.2, color='r', label="Upper")

        ax.set_xlabel("Phases")
        ax.set_ylabel("Defects")
        ax.set_title("Defect Discovery Data and Fitted Histograms")
        ax.legend()
        canvas.draw()
        layoutfig = QVBoxLayout()
        layoutfig.addWidget(toolbar)
        layoutfig.addWidget(canvas, 1)
        widget.setLayout(layoutfig)
        plt.tight_layout()
        return widget
Exemple #47
0
    def __init__(self, persepolis_setting):
        super().__init__()

        self.persepolis_setting = persepolis_setting
        icons = ':/' + \
            str(self.persepolis_setting.value('settings/icons')) + '/'

        # add support for other languages
        locale = str(self.persepolis_setting.value('settings/locale'))
        QLocale.setDefault(QLocale(locale))
        self.translator = QTranslator()
        if self.translator.load(':/translations/locales/ui_' + locale, 'ts'):
            QCoreApplication.installTranslator(self.translator)

        # set ui direction
        ui_direction = self.persepolis_setting.value('ui_direction')

        if ui_direction == 'rtl':
            self.setLayoutDirection(Qt.RightToLeft)

        elif ui_direction in 'ltr':
            self.setLayoutDirection(Qt.LeftToRight)

        self.setWindowIcon(
            QIcon.fromTheme('persepolis', QIcon(':/persepolis.svg')))
        window_verticalLayout = QVBoxLayout()
        self.setLayout(window_verticalLayout)

        # queue_tabWidget
        self.queue_tabWidget = QTabWidget(self)
        window_verticalLayout.addWidget(self.queue_tabWidget)

        # links_tab
        self.links_tab = QWidget()
        links_tab_verticalLayout = QVBoxLayout(self.links_tab)

        # link table
        self.links_table = QTableWidget(self.links_tab)
        links_tab_verticalLayout.addWidget(self.links_table)

        self.links_table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.links_table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.links_table.verticalHeader().hide()

        self.links_table.setColumnCount(3)
        links_table_header_labels = [
            'File Name', 'Download Link', 'dictionary'
        ]
        self.links_table.setHorizontalHeaderLabels(links_table_header_labels)
        self.links_table.setColumnHidden(2, True)

        self.links_table.horizontalHeader().setSectionResizeMode(0)
        self.links_table.horizontalHeader().setStretchLastSection(True)

        # add_queue
        add_queue_horizontalLayout = QHBoxLayout()

        self.select_all_pushButton = QPushButton(self.links_tab)
        add_queue_horizontalLayout.addWidget(self.select_all_pushButton)

        self.deselect_all_pushButton = QPushButton(self.links_tab)
        add_queue_horizontalLayout.addWidget(self.deselect_all_pushButton)

        add_queue_horizontalLayout.addStretch(1)

        self.add_queue_label = QLabel(self.links_tab)
        add_queue_horizontalLayout.addWidget(self.add_queue_label)

        self.add_queue_comboBox = QComboBox(self.links_tab)
        add_queue_horizontalLayout.addWidget(self.add_queue_comboBox)

        links_tab_verticalLayout.addLayout(add_queue_horizontalLayout)

        links_tab_verticalLayout.addStretch(1)
        self.queue_tabWidget.addTab(self.links_tab, "")

        # options_tab
        self.options_tab = QWidget()
        options_tab_verticalLayout = QVBoxLayout(self.options_tab)

        # proxy
        proxy_verticalLayout = QVBoxLayout()

        self.proxy_checkBox = QCheckBox(self.options_tab)
        proxy_verticalLayout.addWidget(self.proxy_checkBox)

        self.proxy_frame = QFrame(self.options_tab)
        self.proxy_frame.setFrameShape(QFrame.StyledPanel)
        self.proxy_frame.setFrameShadow(QFrame.Raised)

        proxy_gridLayout = QGridLayout(self.proxy_frame)

        self.ip_lineEdit = QLineEdit(self.proxy_frame)
        self.ip_lineEdit.setInputMethodHints(Qt.ImhNone)
        proxy_gridLayout.addWidget(self.ip_lineEdit, 0, 1, 1, 1)

        self.proxy_pass_label = QLabel(self.proxy_frame)
        proxy_gridLayout.addWidget(self.proxy_pass_label, 2, 2, 1, 1)

        self.proxy_pass_lineEdit = QLineEdit(self.proxy_frame)
        self.proxy_pass_lineEdit.setEchoMode(QLineEdit.Password)
        proxy_gridLayout.addWidget(self.proxy_pass_lineEdit, 2, 3, 1, 1)

        self.ip_label = QLabel(self.proxy_frame)
        proxy_gridLayout.addWidget(self.ip_label, 0, 0, 1, 1)

        self.proxy_user_lineEdit = QLineEdit(self.proxy_frame)
        proxy_gridLayout.addWidget(self.proxy_user_lineEdit, 0, 3, 1, 1)

        self.proxy_user_label = QLabel(self.proxy_frame)
        proxy_gridLayout.addWidget(self.proxy_user_label, 0, 2, 1, 1)

        self.port_label = QLabel(self.proxy_frame)
        proxy_gridLayout.addWidget(self.port_label, 2, 0, 1, 1)

        self.port_spinBox = QSpinBox(self.proxy_frame)
        self.port_spinBox.setMaximum(9999)
        self.port_spinBox.setSingleStep(1)
        proxy_gridLayout.addWidget(self.port_spinBox, 2, 1, 1, 1)
        proxy_verticalLayout.addWidget(self.proxy_frame)
        options_tab_verticalLayout.addLayout(proxy_verticalLayout)

        # download UserName & Password
        download_horizontalLayout = QHBoxLayout()
        download_horizontalLayout.setContentsMargins(-1, 10, -1, -1)

        download_verticalLayout = QVBoxLayout()
        self.download_checkBox = QCheckBox(self.options_tab)
        download_verticalLayout.addWidget(self.download_checkBox)

        self.download_frame = QFrame(self.options_tab)
        self.download_frame.setFrameShape(QFrame.StyledPanel)
        self.download_frame.setFrameShadow(QFrame.Raised)

        download_gridLayout = QGridLayout(self.download_frame)

        self.download_user_lineEdit = QLineEdit(self.download_frame)
        download_gridLayout.addWidget(self.download_user_lineEdit, 0, 1, 1, 1)

        self.download_user_label = QLabel(self.download_frame)
        download_gridLayout.addWidget(self.download_user_label, 0, 0, 1, 1)

        self.download_pass_label = QLabel(self.download_frame)
        download_gridLayout.addWidget(self.download_pass_label, 1, 0, 1, 1)

        self.download_pass_lineEdit = QLineEdit(self.download_frame)
        self.download_pass_lineEdit.setEchoMode(QLineEdit.Password)
        download_gridLayout.addWidget(self.download_pass_lineEdit, 1, 1, 1, 1)
        download_verticalLayout.addWidget(self.download_frame)
        download_horizontalLayout.addLayout(download_verticalLayout)

        # select folder
        self.folder_frame = QFrame(self.options_tab)
        self.folder_frame.setFrameShape(QFrame.StyledPanel)
        self.folder_frame.setFrameShadow(QFrame.Raised)

        folder_gridLayout = QGridLayout(self.folder_frame)

        self.download_folder_lineEdit = QLineEdit(self.folder_frame)
        folder_gridLayout.addWidget(self.download_folder_lineEdit, 2, 0, 1, 1)

        self.folder_pushButton = QPushButton(self.folder_frame)
        folder_gridLayout.addWidget(self.folder_pushButton, 3, 0, 1, 1)
        self.folder_pushButton.setIcon(QIcon(icons + 'folder'))

        self.folder_label = QLabel(self.folder_frame)
        self.folder_label.setAlignment(Qt.AlignCenter)
        folder_gridLayout.addWidget(self.folder_label, 1, 0, 1, 1)
        download_horizontalLayout.addWidget(self.folder_frame)
        options_tab_verticalLayout.addLayout(download_horizontalLayout)

        self.queue_tabWidget.addTab(self.options_tab, '')

        # limit Speed
        limit_verticalLayout = QVBoxLayout()

        self.limit_checkBox = QCheckBox(self.options_tab)
        limit_verticalLayout.addWidget(self.limit_checkBox)

        self.limit_frame = QFrame(self.options_tab)
        self.limit_frame.setFrameShape(QFrame.StyledPanel)
        self.limit_frame.setFrameShadow(QFrame.Raised)

        limit_horizontalLayout = QHBoxLayout(self.limit_frame)

        self.limit_spinBox = QSpinBox(self.limit_frame)
        self.limit_spinBox.setMinimum(1)
        self.limit_spinBox.setMaximum(1023)
        limit_horizontalLayout.addWidget(self.limit_spinBox)

        self.limit_comboBox = QComboBox(self.limit_frame)
        self.limit_comboBox.addItem("KiB/S")
        self.limit_comboBox.addItem("MiB/S")
        limit_horizontalLayout.addWidget(self.limit_comboBox)

        limit_verticalLayout.addWidget(self.limit_frame)

        limit_connections_horizontalLayout = QHBoxLayout()
        limit_connections_horizontalLayout.addLayout(limit_verticalLayout)

        # number of connections
        connections_horizontalLayout = QHBoxLayout()
        connections_horizontalLayout.setContentsMargins(-1, 10, -1, -1)

        self.connections_frame = QFrame(self.options_tab)
        self.connections_frame.setFrameShape(QFrame.StyledPanel)
        self.connections_frame.setFrameShadow(QFrame.Raised)

        horizontalLayout_3 = QHBoxLayout(self.connections_frame)
        self.connections_label = QLabel(self.connections_frame)
        horizontalLayout_3.addWidget(self.connections_label)

        self.connections_spinBox = QSpinBox(self.connections_frame)
        self.connections_spinBox.setMinimum(1)
        #nomaxx# self.connections_spinBox.setMaximum(16)
        self.connections_spinBox.setProperty("value", 16)

        horizontalLayout_3.addWidget(self.connections_spinBox)
        connections_horizontalLayout.addWidget(self.connections_frame)

        limit_connections_horizontalLayout.addLayout(
            connections_horizontalLayout)

        options_tab_verticalLayout.addLayout(
            limit_connections_horizontalLayout)

        options_tab_verticalLayout.addStretch(1)

        # buttons
        buttons_horizontalLayout = QHBoxLayout()
        buttons_horizontalLayout.addStretch(1)
        # ok_pushButton
        self.ok_pushButton = QPushButton(self)
        self.ok_pushButton.setIcon(QIcon(icons + 'ok'))
        buttons_horizontalLayout.addWidget(self.ok_pushButton)
        # cancel_pushButton
        self.cancel_pushButton = QPushButton(self)
        self.cancel_pushButton.setIcon(QIcon(icons + 'remove'))
        buttons_horizontalLayout.addWidget(self.cancel_pushButton)

        window_verticalLayout.addLayout(buttons_horizontalLayout)

        # labels
        self.setWindowTitle(
            QCoreApplication.translate("text_ui_tr",
                                       "Persepolis Download Manager"))

        self.queue_tabWidget.setTabText(
            self.queue_tabWidget.indexOf(self.links_tab),
            QCoreApplication.translate("text_ui_tr", 'Links'))
        self.queue_tabWidget.setTabText(
            self.queue_tabWidget.indexOf(self.options_tab),
            QCoreApplication.translate("text_ui_tr", 'Download options'))

        self.select_all_pushButton.setText(
            QCoreApplication.translate("text_ui_tr", 'Select All'))
        self.deselect_all_pushButton.setText(
            QCoreApplication.translate("text_ui_tr", 'Deselect All'))

        self.add_queue_label.setText(
            QCoreApplication.translate("text_ui_tr", 'Add to queue: '))

        self.proxy_checkBox.setText(
            QCoreApplication.translate("text_ui_tr", 'Proxy'))
        self.proxy_pass_label.setText(
            QCoreApplication.translate("text_ui_tr", "Proxy PassWord: "******"text_ui_tr", "IP:"))
        self.proxy_user_label.setText(
            QCoreApplication.translate("text_ui_tr", "Proxy UserName: "******"text_ui_tr", "Port:"))

        self.download_checkBox.setText(
            QCoreApplication.translate("text_ui_tr",
                                       "Download UserName and PassWord"))
        self.download_user_label.setText(
            QCoreApplication.translate("text_ui_tr", "Download UserName: "******"text_ui_tr", "Download PassWord: "******"text_ui_tr", "Change Download Folder"))
        self.folder_label.setText(
            QCoreApplication.translate("text_ui_tr", "Download Folder: "))

        self.limit_checkBox.setText(
            QCoreApplication.translate("text_ui_tr", "Limit Speed"))

        self.connections_label.setText(
            QCoreApplication.translate("text_ui_tr", "Number Of Connections:"))

        self.ok_pushButton.setText(
            QCoreApplication.translate("text_ui_tr", 'OK'))
        self.cancel_pushButton.setText(
            QCoreApplication.translate("text_ui_tr", 'Cancel'))
Exemple #48
0
    def __init__(self, dwarf_args, flags=None):
        super(AppWindow, self).__init__(flags)

        self.dwarf_args = dwarf_args

        self.session_manager = SessionManager(self)
        self.session_manager.sessionCreated.connect(self.session_created)
        self.session_manager.sessionStopped.connect(self.session_stopped)
        self.session_manager.sessionClosed.connect(self.session_closed)

        self._tab_order = [
            'memory', 'modules', 'ranges', 'jvm-inspector', 'jvm-debugger'
        ]

        self.menu = self.menuBar()
        self._is_newer_dwarf = False
        self.view_menu = None

        #dockwidgets
        self.watchers_dwidget = None
        self.hooks_dwiget = None
        self.bookmarks_dwiget = None
        self.registers_dock = None
        self.console_dock = None
        self.backtrace_dock = None
        self.threads_dock = None
        #panels
        self.asm_panel = None
        self.console_panel = None
        self.context_panel = None
        self.backtrace_panel = None
        self.contexts_list_panel = None
        self.data_panel = None
        self.emulator_panel = None
        self.ftrace_panel = None
        self.hooks_panel = None
        self.bookmarks_panel = None
        self.smali_panel = None
        self.java_inspector_panel = None
        self.java_explorer_panel = None
        self.java_trace_panel = None
        self.memory_panel = None
        self.modules_panel = None
        self.ranges_panel = None
        self.search_panel = None
        self.watchers_panel = None
        self.welcome_window = None

        self._ui_elems = []

        self.setWindowTitle(
            'Dwarf - A debugger for reverse engineers, crackers and security analyst'
        )

        # load external assets
        _app = QApplication.instance()

        self.remove_tmp_dir()

        # themes
        self.prefs = Prefs()
        self.set_theme(self.prefs.get('dwarf_ui_theme', 'black'))

        # load font
        if os.path.exists(utils.resource_path('assets/Anton.ttf')):
            QFontDatabase.addApplicationFont(
                utils.resource_path('assets/Anton.ttf'))
        if os.path.exists(utils.resource_path('assets/OpenSans-Regular.ttf')):
            QFontDatabase.addApplicationFont(
                utils.resource_path('assets/OpenSans-Regular.ttf'))
            font = QFont("OpenSans", 9, QFont.Normal)
            # TODO: add settingsdlg
            font_size = self.prefs.get('dwarf_ui_font_size', 12)
            font.setPixelSize(font_size)
            _app.setFont(font)
            if os.path.exists(utils.resource_path('assets/OpenSans-Bold.ttf')):
                QFontDatabase.addApplicationFont(
                    utils.resource_path('assets/OpenSans-Bold.ttf'))

        # mainwindow statusbar
        self.progressbar = QProgressBar()
        self.progressbar.setRange(0, 0)
        self.progressbar.setVisible(False)
        self.progressbar.setFixedHeight(15)
        self.progressbar.setFixedWidth(100)
        self.progressbar.setTextVisible(False)
        self.progressbar.setValue(30)
        self.statusbar = QStatusBar(self)
        self.statusbar.setAutoFillBackground(False)
        self.statusbar.addPermanentWidget(self.progressbar)
        self.statusbar.setObjectName("statusbar")
        self.setStatusBar(self.statusbar)

        self.main_tabs = QTabWidget(self)
        self.main_tabs.setMovable(False)
        self.main_tabs.setTabsClosable(True)
        self.main_tabs.setAutoFillBackground(True)
        self.main_tabs.tabCloseRequested.connect(self._on_close_tab)
        self.setCentralWidget(self.main_tabs)

        if self.dwarf_args.package is None:
            self.welcome_window = WelcomeDialog(self)
            self.welcome_window.setModal(True)
            self.welcome_window.onIsNewerVersion.connect(
                self._enable_update_menu)
            self.welcome_window.onUpdateComplete.connect(
                self._on_dwarf_updated)
            self.welcome_window.setWindowTitle(
                'Welcome to Dwarf - A debugger for reverse engineers, crackers and security analyst'
            )
            self.welcome_window.onSessionSelected.connect(self._start_session)
            # wait for welcome screen
            self.hide()
            self.welcome_window.show()
        else:
            if dwarf_args.package is not None:
                if dwarf_args.type is None:
                    # no device given check if package is local path
                    if os.path.exists(dwarf_args.package):
                        print('* Starting new LocalSession')
                        self._start_session('local')
                    else:
                        print('use -t to set sessiontype')
                        exit(0)
                else:
                    print('* Starting new Session')
                    self._start_session(dwarf_args.type)
Exemple #49
0
class MainWinBase(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi()

    def setupUi(self):
        self.resize(1200, 600)
        self.menubar = self.menuBar()
        self.statusbar = self.statusBar()
        self.mainWidget = QTabWidget()
        self.editor = Editor()

        self.actions = {}
        self.menus = {}
        self.submenus = {}
        self.contexMenus = {}
        self.toolbars = {}
        self.status = {}
        self.docks = {}
        self.documents = {}

        self.createActions()
        self.themeCombo = QComboBox()
        self.createMenubar()
        self.createContexMenus()
        self.createToolbars()
        self.createStatusBar()
        self.colorPanelLayout = QFlowLayout()
        self.createDocks()
        self.createMainWidget()

    def createActions(self):
        def createAct(text, tip=None, shortcut=None, iconimg=None, checkable=False, slot=None):
            action = QAction(self.tr(text), self)
            if iconimg is not None:
                action.setIcon(QIcon(iconimg))
            if shortcut is not None:
                action.setShortcut(shortcut)
            if tip is not None:
                tip = self.tr(tip)
                action.setToolTip(tip)
                action.setStatusTip(tip)
            if checkable:
                action.setCheckable(True)
            if slot is not None:
                action.triggered.connect(slot)
            return action

        def keys2str(standardkey):
            return "".join(("(", QKeySequence(standardkey).toString(), ")"))

        self.actions["new"] = createAct(self.tr("&New", "&New"),
                                        self.tr("new") + keys2str(QKeySequence.New), QKeySequence.New,
                                        ':appres.img/NewDocument.png')
        self.actions["open"] = createAct(self.tr("&Open"),
                                         self.tr("Open") + keys2str(QKeySequence.Open), QKeySequence.Open,
                                         ':appres.img/openHS.png')
        self.actions["save"] = createAct(self.tr("&Save"),
                                         self.tr("Save") + keys2str(QKeySequence.Save), QKeySequence.Save,
                                         ':appres.img/save.png')
        self.actions["saveas"] = createAct(self.tr("&Save as..."), self.tr("Save as..."), None,
                                           ':appres.img/SaveAs.png')
        self.actions["export"] = createAct(self.tr("&ExportQss"), self.tr("ExportQss"), "Ctrl+Alt+E",
                                           ':appres.img/export5.png')
        self.actions["exit"] = createAct(self.tr("&Exit"), self.tr("Exit"), "Ctrl+Q", ':appres.img/close.png')
        self.actions["undo"] = createAct(self.tr("&Undo"),
                                         self.tr("Undo") + keys2str(QKeySequence.Undo), QKeySequence.Undo,
                                         ':appres.img/undo.png')
        self.actions["redo"] = createAct(self.tr("&Redo"),
                                         self.tr("Redo") + keys2str(QKeySequence.Redo), QKeySequence.Redo,
                                         ':appres.img/redo.png')
        self.actions["cut"] = createAct(self.tr("&Cut"),
                                        self.tr("Cut") + keys2str(QKeySequence.Cut), QKeySequence.Cut,
                                        ':appres.img/cut.png')
        self.actions["copy"] = createAct(self.tr("&Copy"),
                                         self.tr("Copy") + keys2str(QKeySequence.Copy), QKeySequence.Copy,
                                         ':appres.img/copy.png')
        self.actions["paste"] = createAct(self.tr("&Paste"),
                                          self.tr("Paste") + keys2str(QKeySequence.Paste), QKeySequence.Paste,
                                          ':appres.img/paste.png')
        self.actions["find"] = createAct(self.tr("&Find"),
                                         self.tr("Find") + keys2str(QKeySequence.Find), QKeySequence.Find,
                                         ':appres.img/find.png')
        self.actions["replace"] = createAct(self.tr("&Replace"),
                                            self.tr("Replace") + keys2str(QKeySequence.Replace), QKeySequence.Replace,
                                            ':appres.img/replace.png')
        self.actions["fontup"] = createAct(self.tr("&BiggerFont"), self.tr("Bigger Font"), None,
                                           ':appres.img/fontup.png')
        self.actions["fontdown"] = createAct(self.tr("&SmallerFont"), self.tr("Smaller Font"), None,
                                             ':appres.img/fontdown.png')
        self.actions["echospace"] = createAct(self.tr("&Space"), self.tr("Show Spaces"), None, ':appres.img/space.png')
        self.actions["echoeol"] = createAct(self.tr("&Eol"), self.tr("Show Eol"), None, ':appres.img/eol.png')
        self.actions["autowrap"] = createAct(self.tr("&AutoWrap"), self.tr("Auto wrap text"), None,
                                             ":appres.img/autowrap.png")

        # self.fontcolorAct=QAction(QIcon(":appres.img/broadcast_send_fontcolor_normal.bmp"),"&FontColor",self)
        # self.fontcolorAct.setShortcut("Ctr+Shit+C")
        # self.fontcolorAct.setStatusTip("FontColor")
        self.actions["DisableQss"] = createAct(self.tr("&DisableQss"), self.tr("DisableQss"), checkable=True)
        self.actions["DisableQss"].setChecked(False)
        self.actions["ShowColor"] = createAct(self.tr("&ColorPanel"),
                                              self.tr("ShowColorPanel"),
                                              None,
                                              ":appres.img/color.png",
                                              checkable=True)
        self.actions["ShowColor"].setChecked(True)
        self.actions["ShowPreview"] = createAct(self.tr("&PreviewPanel"),
                                                self.tr("ShowPreviewPanel"),
                                                None,
                                                ":appres.img/view.png",
                                                checkable=True)
        self.actions["Palette"] = createAct(self.tr("&Palette"), self.tr("ShowPaletteSettingDialog"), None,
                                            ":appres.img/texture.png")
        self.actions["ShowPreview"].setChecked(True)

        self.actions["config"] = createAct(self.tr("&Config"), self.tr("settings."), None, ":appres.img/config.png")

        self.actions["checkupdate"] = createAct(self.tr("&Check for Updates..."),
                                                self.tr("Check is there new version released for update."))
        self.actions["about"] = createAct(self.tr("&About"), self.tr("About"))

        # self.exitAct.triggered.connect(qApp.exit)#等价于qApp.quit
        self.actions["exit"].triggered.connect(self.close)

    def createMenubar(self):
        self.menus["File"] = QMenu(self.tr("&File"))
        self.menus["Edit"] = QMenu(self.tr("&Edit"))
        self.menus["View"] = QMenu(self.tr("&View"))
        self.menus["Tool"] = QMenu(self.tr("&Tool"))
        self.menus["Help"] = QMenu(self.tr("&Help"))

        recentMenu = QMenu(self.tr("Recent"), self.menus["File"])
        recentMenu.setIcon(QIcon(":appres.img/none.png"))

        editMenu = QMenu(self.tr("Text"), self.menus["Edit"])
        editMenu.setIcon(QIcon(":appres.img/edit_whitepage.png"))
        editMenu.addAction(self.actions["undo"])
        editMenu.addAction(self.actions["redo"])
        editMenu.addSeparator()
        editMenu.addAction(self.actions["cut"])
        editMenu.addAction(self.actions["copy"])
        editMenu.addAction(self.actions["paste"])

        searchMenu = QMenu(self.tr("Search"), self.menus["Edit"])
        searchMenu.setIcon(QIcon(":appres.img/findnext.png"))
        searchMenu.addAction(self.actions["find"])
        searchMenu.addAction(self.actions["replace"])

        self.submenus["recent"] = recentMenu
        self.submenus["text"] = editMenu
        self.submenus["search"] = searchMenu

        self.menus["File"].addAction(self.actions["new"])
        self.menus["File"].addAction(self.actions["open"])
        self.menus["File"].addAction(self.actions["save"])
        self.menus["File"].addAction(self.actions["saveas"])
        self.menus["File"].addAction(self.actions["export"])
        self.menus["File"].addMenu(self.submenus["recent"])
        self.menus["File"].addSeparator()
        self.menus["File"].addAction(self.actions["exit"])

        self.menus["Edit"].addMenu(editMenu)
        self.menus["Edit"].addMenu(searchMenu)

        self.menus["View"].addAction(self.actions["ShowColor"])
        self.menus["View"].addAction(self.actions["ShowPreview"])
        self.menus["View"].addAction(self.actions["Palette"])

        self.menus["Tool"].addAction(self.actions["config"])

        self.menus["Help"].addAction(self.actions["about"])
        self.menus["Help"].addAction(self.actions["checkupdate"])

        for m in self.menus.values():
            self.menubar.addMenu(m)

    def createContexMenus(self):
        self.contexMenus["Edit"] = QMenu(self.tr("Edit"))
        self.contexMenus["Edit"].addAction(self.actions["cut"])
        self.contexMenus["Edit"].addAction(self.actions["copy"])
        self.contexMenus["Edit"].addAction(self.actions["paste"])

    def createToolbars(self):
        checkbox = QCheckBox(self.tr("DisableQSS"))
        # self.themeCombo = QComboBox()
        checkbox.setToolTip(self.tr("Using system style, disable qss."))
        self.themeCombo.setToolTip(self.tr("Select system style."))
        self.themeCombo.addItems(QStyleFactory.keys())
        self.themeCombo.setMinimumWidth(105)
        theme = QApplication.style().objectName()
        self.themeCombo.setCurrentIndex(self.themeCombo.findText(theme, Qt.MatchFixedString))
        # self.themeCombo.setEnabled(False)
        # themeCombo.activated[str].connect(qApp.setStyle)
        # themeCombo.currentTextChanged.connect(qApp.setStyle)
        # checkbox.stateChanged.connect(self.themeCombo.setEnabled)
        checkbox.stateChanged.connect(self.actions["DisableQss"].setChecked)
        # checkbox.stateChanged.connect(lambda x:self.actions["DisableQss"].setChecked(checkbox.isChecked()))

        self.toolbars["Main"] = QToolBar(self.tr("Main", "toolbar"))
        self.toolbars["Main"].addWidget(checkbox)
        self.toolbars["Main"].addWidget(self.themeCombo)

        self.toolbars["File"] = QToolBar(self.tr("File"))
        self.toolbars["File"].addAction(self.actions["new"])
        self.toolbars["File"].addAction(self.actions["open"])
        self.toolbars["File"].addAction(self.actions["save"])
        # self.toolbars["File"].addAction(self.actions["saveas"])
        self.toolbars["File"].addAction(self.actions["export"])

        self.toolbars["Edit"] = QToolBar(self.tr("Edit"))
        self.toolbars["Edit"].addAction(self.actions["undo"])
        self.toolbars["Edit"].addAction(self.actions["redo"])
        self.toolbars["Edit"].addSeparator()
        self.toolbars["Edit"].addAction(self.actions["cut"])
        self.toolbars["Edit"].addAction(self.actions["copy"])
        self.toolbars["Edit"].addAction(self.actions["paste"])
        self.toolbars["Search"] = QToolBar(self.tr("Search"))
        self.toolbars["Search"].addAction(self.actions["find"])
        self.toolbars["Search"].addAction(self.actions["replace"])

        self.toolbars["View"] = QToolBar(self.tr("View"))
        self.toolbars["View"].addAction(self.actions["ShowColor"])
        self.toolbars["View"].addAction(self.actions["ShowPreview"])
        self.toolbars["View"].addAction(self.actions["Palette"])

        self.toolbars["Echo"] = QToolBar(self.tr("Echo"))
        self.toolbars["Echo"].addAction(self.actions["fontup"])
        self.toolbars["Echo"].addAction(self.actions["fontdown"])
        self.toolbars["Echo"].addAction(self.actions["echospace"])
        self.toolbars["Echo"].addAction(self.actions["echoeol"])
        self.toolbars["Echo"].addAction(self.actions["autowrap"])

        for t in self.toolbars.values():
            self.addToolBar(t)

    def createStatusBar(self):
        self.statusbar.showMessage(self.tr("Ready"))
        # self.statusbar.addWidget(QWidget(),1)
        # self.status["date"] = QLabel()
        # self.statusbar.addPermanentWidget(self.status["date"])
        # self.status["date"].setText(QDate.currentDate().toString())
        # self.status["date"].setVisible(False)

        self.status["line"] = QLabel(self.tr("line:0 pos:0"))
        self.status["select"] = QLabel(self.tr("select: none"))
        self.status["coding"] = QLabel(self.tr("coding"))
        self.status["lines"] = QLabel(self.tr("lines:0"))
        self.status["line"].setMinimumWidth(120)
        self.status["select"].setMinimumWidth(150)
        self.status["coding"].setMinimumWidth(80)
        self.status["coding"].setAlignment(Qt.AlignCenter)
        self.status["lines"].setMinimumWidth(60)
        self.status["lines"].setAlignment(Qt.AlignRight)
        self.statusbar.addPermanentWidget(self.status["line"])
        self.statusbar.addPermanentWidget(self.status["select"])
        self.statusbar.addPermanentWidget(self.status["coding"])
        self.statusbar.addPermanentWidget(self.status["lines"])

    def createDocks(self):
        self.docks["color"] = QDockWidget(self.tr("Color Variables"))
        self.docks["preview"] = QDockWidget(self.tr("Preview"))

        self.docks["color"].setMinimumSize(QSize(80, 20))
        self.docks["color"].setFeatures(QDockWidget.AllDockWidgetFeatures)
        self.docks["preview"].setMinimumSize(QSize(200, 200))
        self.docks["preview"].setFeatures(QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetFloatable)

        self.addDockWidget(Qt.LeftDockWidgetArea, self.docks["color"])
        self.addDockWidget(Qt.RightDockWidgetArea, self.docks["preview"])

        class ColorPanelWidget(QWidget):
            def sizeHint(self):
                return self.layout().sizeHint()

        colorPanelWidget = ColorPanelWidget()
        # self.colorPanelLayout = QFlowLayout()
        colorPanelWidget.setLayout(self.colorPanelLayout)
        self.docks["color"].setWidget(colorPanelWidget)
        self.docks["preview"].setWidget(PreviewWidget())

        self.docks["color"].visibilityChanged.connect(self.actions["ShowColor"].setChecked)

    def createMainWidget(self):
        self.setCentralWidget(self.mainWidget)
        self.mainWidget.setTabBarAutoHide(True)
        self.mainWidget.addTab(self.editor, self.tr("main", "CodeEditor tab in tabwidget of mainwidget"))
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.imageLabel = QLabel(self.tab1)
        self.imageLabel.setGeometry(80, 50, 510, 310)
        self.imageLabel.setPixmap(
            QtGui.QPixmap(os.getcwd() + "/" + 'image.jpg'))

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

        self.tabs.addTab(self.tab1, "Facial Authentication")

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

    def recognizeFace(self):
        global imageName, username
        while not os.path.exists(os.getcwd() + "/" + 'image.jpg'):
            a = 5
        if os.path.isfile('image.jpg'):
            copyfile('image.jpg', imageName)
        username = faceRecognition(self)
        #This is used to handle the case if the image size too small error is returned
        if username == 'error':
            _translate = QtCore.QCoreApplication.translate
            self.tab1.label.setText(
                _translate(
                    "Form",
                    "*Picture is not upto the required quality. It could be due to poor ambient light "
                ))
            self.tab1.label.setStyleSheet('color: red')
            return 1
        #This is used to handle the case if there is no face in the picture frame
        elif username == 'No Face':
            _translate = QtCore.QCoreApplication.translate
            self.tab1.label.setText(
                _translate(
                    "Form",
                    "*No face detected. Please position the camera pointing towards your face"
                ))
            self.tab1.label.setStyleSheet('color: red')
            return 1
        elif username == 'Fail':
            _translate = QtCore.QCoreApplication.translate
            self.tab1.label.setText(
                _translate(
                    "Form",
                    "*Authentication Failed. You have been denied access"))
            self.tab1.label.setStyleSheet('color: red')
            return 1
        length = len(username)
        print('Before Independence')
        self.tab2 = Dash(self)
        print('After Independence')
        if length > 0:
            _translate = QtCore.QCoreApplication.translate
            p = 'Hello %s' % (username)
            print('India')
            self.tab2.label.setText(_translate("Dash", p))
            self.tab2.label_2.setText(
                _translate(
                    "Dash", "You have been granted access to Book My Show, \n"
                    "a Secure Voice Assisted movie show booking website"))
            self.tab2.label_3.setText(
                _translate("Dash", "Do you want to add a new user?"))
            #This function is used to send a message(websockets) containing the username to the control pi
            msg_type = 'login'
            send_message(username, msg_type)
            print(username)

        dashboardIndex = self.tabs.addTab(self.tab2, "Dashboard")
        self.tabs.setCurrentIndex(dashboardIndex)
        faceIdentifyIndex = self.tabs.indexOf(self.tab1)
        self.tabs.removeTab(faceIdentifyIndex)

    def registerUser(self):
        print('Registering User')
        self.tab3 = AddUser(self)
        addUserIndex = self.tabs.addTab(self.tab3, "Add User")
        self.tabs.setCurrentIndex(addUserIndex)
        dashboardIndex = self.tabs.indexOf(self.tab2)
        self.tabs.removeTab(dashboardIndex)

    def logout(self):
        msg_type = 'logout'
        send_message(username, msg_type)
        faceIdentifyIndex = self.tabs.addTab(self.tab1,
                                             "Facial Authentication")
        self.tabs.setCurrentIndex(faceIdentifyIndex)
        dashboardIndex = self.tabs.indexOf(self.tab2)
        self.tabs.removeTab(dashboardIndex)

    def addUser(self):
        print('Printing Entered text')
        global new_user_username, new_user_emailid, new_user_password
        new_user_username = self.tab3.usernameLineEdit.text()
        new_user_emailid = self.tab3.emailIdLineEdit.text()
        new_user_password = self.tab3.passwordLineEdit.text()
        register_url_base = 'http://ec2-184-72-98-174.compute-1.amazonaws.com/'
        register = {
            'postUser': new_user_username,
            'postEmail': new_user_emailid,
            'postPass': new_user_password
        }
        request_parameters = {'s': '3', 'insert': '1'}
        session = requests.session()
        r = session.request('POST',
                            register_url_base + 'index.php',
                            json=None,
                            data=register,
                            headers=None,
                            params=request_parameters)
        print(new_user_username)
        print(new_user_emailid)
        print(new_user_password)
        self.tab4 = AddPhoto(self)
        self.imageLabel = QLabel(self.tab4)
        self.imageLabel.setGeometry(50, 50, 510, 310)
        self.imageLabel.setPixmap(
            QtGui.QPixmap(os.getcwd() + "/" + 'image.jpg'))
        self.tabs.addTab(self.tab4, "Adding Photo to a person")
        addUserIndex = self.tabs.indexOf(self.tab3)
        self.tabs.removeTab(addUserIndex)

    def addPhoto(self):
        global imageName, new_user_username, username
        copyfile('image.jpg', imageName)

        print('Photo has been added')
        personId = createPerson(new_user_username)
        if personId:
            returnString = addPersonFace(personId)
            _translate = QtCore.QCoreApplication.translate
            if returnString:
                if returnString == 'Bad Detect Request':
                    self.tab4.label.setText(
                        _translate(
                            "AddPhoto",
                            "*Picture is not upto the required quality. It could be due to poor ambient light "
                        ))
                    self.tab4.label.setStyleSheet('color: red')

                elif returnString == 'No Face Detected':
                    self.tab4.label.setText(
                        _translate(
                            "AddPhoto",
                            "*No face detected. Please position the camera pointing towards your face"
                        ))
                    self.tab4.label.setStyleSheet('color: red')

            else:
                print('Training')
                trainSuperProjectGroup()
                dashboardIndex = self.tabs.addTab(self.tab2, "Dashboard")
                helloString = 'Hello %s' % (username)
                self.tab2.label.setText(_translate("Dash", helloString))
                self.tab2.label_2.setText(
                    _translate(
                        "Dash",
                        "You have been granted access to Book My Show, \n"
                        "a Secure Voice Assisted movie show booking website"))
                self.tab2.label_3.setText(
                    _translate("Dash", "Do you want to add a new user?"))
                stringVar = 'You have successfully added %s as a user' % (
                    new_user_username)
                self.tab2.label_4.setText(_translate("Dash", stringVar))
                self.tab2.label_4.setStyleSheet('color: blue')
                self.tabs.setCurrentIndex(dashboardIndex)
                addPhotoIndex = self.tabs.indexOf(self.tab4)
                self.tabs.removeTab(addPhotoIndex)
class Example(QWidget):
    def __init__(self):
        super().__init__()

        self.initUI()

    def connect(self):
        if self.IPbox.text() == "":
            text, ok = QInputDialog.getText(self, 'Input Dialog', '输入IP:')
            if ok:
                self.IPbox.setText(str(text))


#        if self.usernamebox.text() == "":
#            text, ok = QInputDialog.getText(self, 'Input Dialog', '输入用户名:')
#            if ok:
#                self.usernamebox.setText(str(text))
#        if self.passwordbox.text() == "":
#            text, ok = QInputDialog.getText(self, 'Input Dialog', '输入密码:')
#            if ok:
#                self.passwordbox.setText(str(text))
#        if self.ethbox.text() == "":
#            text, ok = QInputDialog.getText(self, 'Input Dialog', '输入网口号:(eg:eth1)')
#            if ok:
#                self.ethbox.setText(str(text))
        self.IP = self.IPbox.text()
        self.username = self.usernamebox.text()
        self.password = self.passwordbox.text()
        self.eth = self.ethbox.text()
        QMessageBox.information(self, "", "需要一段时间,请等待")
        #a, b = subprocess.getstatusoutput('ping ' + self.IP)  # a是退出状态 b是输出的结果
        self.thread_connect = MyThread(re='ping  -t 100 -c 2 ' +
                                       self.IP)  # 创建一个线程 发送cmd
        self.thread_connect.sec_changed_signal.connect(
            self.update_state_connect)  # cmd线程发过来的信号挂接到槽:update_state
        #self.thread2.sec_changed_signal.connect(self.update_time)  # 计时线程发过来的信号挂接到槽:update_time
        self.thread_connect.start()

    def update_state_connect(self, b):
        self.resultbox.setText(b)
        if "ms" in b and "100% packet loss" not in b:
            QMessageBox.information(
                self,  # 使用infomation信息框
                "注意",
                "连接成功")
        else:
            QMessageBox.information(self, "注意", "连接失败 请检查IP设置")
        self.thread_connect.terminate()

    def update(self):
        QApplication.processEvents()

    def read_json(self):
        global config_dic
        global res_cmd
        global send_list
        global tab_name
        global pcap_path
        global twolineflag

        try:
            fname = QFileDialog.getOpenFileName(
                self,
                "选取文件",
                "./",  # 起始路径
                "配置文件 (*.json)")  # 设置文件扩展名过滤,用双分号间隔

            with open(fname[0], 'r') as load_f:
                config_dic = json.load(load_f)
                send_list = {}
                res_cmd = ""
                tab_name = []
                pcap_path = ""
                res_cmd = fname[0]
                self.tab.clear()
                for test_type in config_dic.keys():
                    send_list[test_type] = []
                    tab_name.append(test_type)
                    self.tab.test_type = Checkboxlist(test_type)
                    l = int(len(test_type) / 2)
                    s = test_type[0:l] + '\n' * twolineflag + test_type[l:]
                    self.tab.addTab(self.tab.test_type, s)
                self.update()
        except:
            return 1

    def initUI(self):
        # 读取配置文件
        global config_dic
        global twolineflag
        try:
            with open('config.json', 'r') as load_f:
                config_dic = json.load(load_f)
        except:
            config_dic = config_dic
            QMessageBox.information(
                self,  # 使用infomation信息框
                "注意",
                "未找到配置文件 请手动选择")
            self.read_json()
            # 初始化连接
        self.IPbox = QLineEdit()
        #self.IPbox.setText("192.168.201.129")
        self.re_num = 1
        self.usernamebox = QLineEdit()
        self.ethbox = QLineEdit()
        self.passwordbox = QLineEdit()
        self.connect_button = QPushButton("测试连接")
        self.update_button = QPushButton("更新配置")
        hbox1 = QHBoxLayout()
        hbox1.addWidget(QLabel("被测试IP:"))
        hbox1.addWidget(self.IPbox)
        hbox1.addWidget(self.connect_button)
        hbox1.addWidget(QLabel("      "))
        hbox1.addWidget(QLabel("本机用户名:"))
        hbox1.addWidget(self.usernamebox)
        hbox1.addWidget(QLabel("本机密码:"))
        hbox1.addWidget(self.passwordbox)
        hbox1.addWidget(QLabel("网口号:"))
        hbox1.addWidget(self.ethbox)

        hbox1.addWidget(self.update_button)

        self.connect_button.clicked.connect(self.connect)
        self.update_button.clicked.connect(self.read_json)

        # 中间

        self.topFiller = QWidget()
        self.topFiller.setMinimumSize(2500, 2000)  #######设置滚动条的尺寸
        self.tab = QTabWidget()
        for test_type in config_dic.keys():
            send_list[test_type] = []
            tab_name.append(test_type)

            self.tab.test_type = Checkboxlist(test_type)
            l = int(len(test_type) / 2)
            s = test_type[0:l] + '\n' * twolineflag + test_type[l:]
            self.tab.addTab(self.tab.test_type, s)
        # tab.tabBar().setFixedHeight(48)
        hbox2 = QHBoxLayout(self.topFiller)
        hbox2.addWidget(self.tab)
        #hbox2.addWidget(self.scroll)
        self.scroll = QScrollArea()
        self.scroll.setWidget(self.topFiller)

        # 辅助功能
        hbox3 = QHBoxLayout()
        hbox4 = QHBoxLayout()
        self.re_timebox = QSlider(Qt.Horizontal, self)
        self.re_timebox.setMinimum(1)
        self.re_timebox.setMaximum(1000)
        self.re_timebox.valueChanged[int].connect(self.changeValue)
        self.num = QLabel("1")
        self.fullspeed = QCheckBox("全速发送")
        hbox3.addWidget(self.fullspeed)  # -R

        hbox4.addWidget(QLabel("  重复次数:"))
        hbox4.addWidget(self.num)
        hbox4.addWidget(self.re_timebox)

        hbox3.addWidget(QLabel("  最大发包数量:"))
        self.maxpacknumbox = QLineEdit()  # -L
        hbox3.addWidget(self.maxpacknumbox)
        hbox3.addWidget(QLabel("  每秒发送报文数:"))
        self.packpsbox = QLineEdit()  # -p
        hbox3.addWidget(self.packpsbox)
        '''hbox3.addWidget(QLabel("  指定MTU:"))
        self.MTUbox = QLineEdit()  # -t
        hbox3.addWidget(self.MTUbox)'''

        hbox3.addWidget(QLabel("发包速度/Mbps:"))
        self.Mbpsbox = QLineEdit()
        hbox3.addWidget(self.Mbpsbox)

        # 开始测试
        self.start_button = QPushButton("开始发送数据包")
        self.start_button.clicked.connect(self.start_test)
        self.stop_button = QPushButton("停止发送数据包")
        self.stop_button.clicked.connect(self.stop_test)
        hbox5 = QHBoxLayout()
        hbox5.addWidget(self.start_button)
        hbox5.addWidget(self.stop_button)
        #        hbox5.addWidget(QLabel("                            time:"))
        #        self.timebox = QLineEdit()
        #        hbox5.addWidget(self.timebox)
        # 显示输出结果
        self.resultbox = QTextBrowser()

        vbox = QVBoxLayout()
        vbox.addLayout(hbox1)
        vbox.addWidget(QLabel("选择测试模式:"))

        #vbox.addLayout(hbox2)
        vbox.addWidget(self.scroll)
        vbox.addWidget(QLabel("可选项:"))
        vbox.addLayout(hbox3)
        vbox.addLayout(hbox4)

        vbox.addLayout(hbox5)
        vbox.addWidget(QLabel("状态提示信息:"))
        vbox.addWidget(self.resultbox)
        self.setLayout(vbox)
        # self.setGeometry(300, 300, 290, 150)
        self.setWindowTitle('tcpreplay_gui')
        self.show()

    def changeValue(self, value):
        self.num.setText(str(value))
        self.re_num = value

    def stop_test(self):
        if "数据包发送成功" not in self.resultbox.toPlainText(
        ) and " 默认发包速度下" in self.resultbox.toPlainText():
            try:
                self.thread.terminate()
                self.thread2.terminate()
                self.resultbox.setText("")
            except:
                self.resultbox.setText("")
        else:
            self.resultbox.setText("")

    def start_test(self):
        self.resultbox.setText("")

        # tcprewrite是否需要
        self.resultbox.setText("")
        # -i 设置eth端口
        if self.ethbox.text() == "":
            text, ok = QInputDialog.getText(self, 'Input Dialog',
                                            '输入网口号:(eg:eth1)')
            if ok:
                self.ethbox.setText(str(text))
        if self.passwordbox.text() == "":
            text, ok = QInputDialog.getText(self, 'Input Dialog', '输入密码')
            if ok:
                self.passwordbox.setText(str(text))
        re = "echo " + self.passwordbox.text(
        ) + "|sudo -S " + "tcpreplay -i " + self.ethbox.text() + " "
        # 最大速率发送 -t
        if self.fullspeed.isChecked():
            re += " -t "
        else:
            re = re
        # 重复次数
        if self.re_num > 1:
            re = re + "-l " + str(self.re_num) + " "
        ''''#制定MTU
        if not self.MTUbox.text()=="":
            re+=" - "+ self.MTUbox.text()+' ''' ''

        # 每秒发包数量
        if not self.packpsbox.text() == "":
            re += ' -p ' + self.packpsbox.text() + ' '
        # 发送速度MB/s
        if not self.Mbpsbox.text() == "":
            re += ' -M ' + self.Mbpsbox.text() + ' '
        # 最大发包数量
        if not self.maxpacknumbox.text() == "":
            re += ' -L ' + self.maxpacknumbox.text() + ' '
        # 数据包名称 路径应和json文件位置相同
        tabindex = self.tab.currentIndex()
        tn = (tab_name[tabindex])
        pcaplist = send_list[tn]
        if len(pcaplist) == 0:
            QMessageBox.information(
                self,  # 使用infomation信息框
                "注意",
                "请选择至少一个包")
            return
        if len(pcaplist) == 1:
            re += pcap_path + pcaplist[0]
        else:
            temp = re
            re = ""
            for i in pcaplist:
                re += temp + pcap_path + i + " &&"
            re = re[0:-2]

    # self.resultbox.setText(self.resultbox.toPlainText() + '\r\n' + re)
        self.starttime = time.time()
        self.resultbox.setText(self.resultbox.toPlainText() + '\r\n' +
                               "正在发送数据包 默认发包速度下可能需要较长时间 请耐心等待。。。")
        self.thread = MyThread(re=re)  # 创建一个线程 发送cmd
        self.thread2 = MyThread2(self.starttime)  # 创建一个线程 计时

        self.thread.sec_changed_signal.connect(
            self.update_state)  # cmd线程发过来的信号挂接到槽:update_state
        self.thread2.sec_changed_signal.connect(
            self.update_time)  # 计时线程发过来的信号挂接到槽:update_time
        self.thread.start()
        self.thread2.start()

    def update_state(self, b):
        if "Actual" in b:
            self.resultbox.setText("数据包发送成功!" + '\r\n结果统计信息:\r\n' +
                                   b[b.index("Actual"):])
        else:
            QMessageBox.information(
                self,  # 使用infomation信息框
                "注意",
                "未能成功发送 请检查网口设置与软件是否正确安装")

        # self.resultbox.setText(self.resultbox.toPlainText() + '\r\n' + b)
        self.thread.terminate()
        self.thread2.terminate()

    def update_time(self, a):
        self.resultbox.setText(self.resultbox.toPlainText() + '\r\n' +
                               "已用时间:" +
                               str(round(time.time() - self.starttime)) + "s")
Exemple #52
0
class MainForm(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(MainForm, self).__init__()
        self.setupUi(self)

        self.db_name = None
        self.db_connection = None
        self.tables_tab_widget = None
        self.modified_data_in_tables = {}
        self.connect_toolbar_with_functions()

    def connect_toolbar_with_functions(self):
        self.open_db_action.triggered.connect(self.open_db)
        self.delete_selected_elements_action.triggered.connect(self.delete_elem)
        self.save_current_table_action.triggered.connect(self.save_current_table_changes)
        self.save_all_tables_action.triggered.connect(self.save_all_tables_changes)
        self.save_db_as_action.triggered.connect(self.save_db_as)

    def open_db(self):
        try:
            name = QFileDialog.getOpenFileName(self, "Выберите базу данных sqlite", '', "*.sqlite")[0]
            if name:
                self.db_name = name
                if self.db_connection:
                    self.db_connection.close()
                self.db_connection = sqlite3.connect(self.db_name)

                cur = self.db_connection.cursor()
                cur.execute("SELECT name FROM sqlite_master WHERE type='table';")
                tables_names = [el[0] for el in cur.fetchall()]
                if not tables_names:
                    raise Exception("Нет таблиц в базе данных")

                if self.notLoadDbLabel:
                    self.notLoadDbLabel.deleteLater()
                    self.notLoadDbLabel = None

                if not self.tables_tab_widget:
                    self.tables_tab_widget = QTabWidget(self)
                    self.gridLayout.addWidget(self.tables_tab_widget)
                else:
                    self.tables_tab_widget.clear()

                for name in tables_names:
                    self.modified_data_in_tables[name] = {}
                    table_widget = QTableWidget()
                    self.tables_tab_widget.addTab(table_widget, name)
                    self.init_table_widget_for_db_table(table_widget, name)

        except sqlite3.Error as e:
            self.statusBar().showMessage(f'Ошибка с бд: {e.args[0]}')
        except Exception as e:
            self.statusBar().showMessage(f'Ошибка: {e.args[0]}')

    def save_db_as(self):
        try:
            db_name = QFileDialog.getSaveFileName(self, "Сохранить базу данных sqlite как", '', "*.sqlite")[0]
            with open(self.db_name, mode='rb') as db_cur:
                with open(db_name, mode='wb') as out_file:
                    out_file.write(db_cur.read())
        except Exception as e:
            self.statusBar().showMessage(f'Ошибка: {e.args[0]}')

    def init_table_widget_for_db_table(self, table_widget, name):
        try:
            # Получим результат запроса
            cursor = self.db_connection.cursor()
            res = cursor.execute(f"SELECT * FROM {name}").fetchall()

            # Если запись не нашлась, то не будем ничего делать
            if not res:
                self.statusBar().showMessage('Ничего не нашлось')
                return
            table_widget.clear()
            # Заполнили размеры таблицы
            table_widget.setRowCount(len(res))
            table_widget.setColumnCount(len(res[0]))
            # Устанавливаем заголовки таблицы
            titles = [description[0] for description in cursor.description]
            table_widget.setHorizontalHeaderLabels(titles)
            # Заполнили таблицу полученными элементами
            for i, elem in enumerate(res):
                for j, val in enumerate(elem):
                    str_val = str(val)
                    if str_val.startswith("b'") and type(val) is bytes:
                        button = QPushButton('Открыть файл')
                        file_type = magic.from_buffer(val).split()[0].lower()
                        image_file_types = ['jpeg', 'jpg']
                        if file_type in image_file_types:
                            button.imageBytes = val
                            id_el = self.get_id_of_element_at_row_and_column(i, j)
                            prop = titles[j]

                            button.clicked.connect(self.open_image_edit_form(id_el, prop,
                                                                             button.imageBytes, button))
                            table_widget.setCellWidget(i, j, button)
                    else:
                        table_widget.setItem(i, j, QTableWidgetItem(str_val))

            table_widget.resizeColumnsToContents()

            table_widget.itemChanged.connect(self.item_changed)

        except sqlite3.Error as e:
            self.statusBar().showMessage(f'Ошибка с бд: {e.args[0]}')
        except Exception as e:
            self.statusBar().showMessage(f'Ошибка: {e.args[0]}')

    def open_image_edit_form(self, id_el, prop, image_data, button):
        def callback():
            try:
                self.imageEditForm = ImageReplaceForm(id_el, prop, image_data)
                self.imageEditForm.show()
                self.imageEditForm.replaceImageButton.clicked.connect(lambda: self.save_image(button))
            except Exception as e:
                self.statusBar().showMessage(f'Ошибка: {e.args[0]}')

        return callback

    def save_image(self, button):
        try:
            if not self.imageEditForm.new_image_name:
                raise Exception("Не отключена кнопка сохранения картинки")
            with open(self.imageEditForm.new_image_name, mode='rb') as new_image:
                blob_data = new_image.read()
                element_id = self.imageEditForm.element_id
                element_property = self.imageEditForm.element_property
                self.imageEditForm.close()

                current_table_name = self.get_current_table_name()
                cur = self.db_connection.cursor()
                cur.execute(f"""UPDATE {current_table_name} 
                        SET '{element_property}'= ? WHERE id = {element_id}""", (blob_data,)).fetchone()

                self.db_connection.commit()
                button.imageBytes = blob_data
                button.clicked.connect(self.open_image_edit_form(element_id, element_property,
                                                                 button.imageBytes, button))

        except Exception as e:
            self.statusBar().showMessage(f'Ошибка: {e.args[0]}')

    def get_current_table_name(self):
        try:
            current_table_name = self.tables_tab_widget \
                .tabText(self.tables_tab_widget.currentIndex())

            # clear table name of modified state
            if current_table_name[-1] == "*":
                current_table_name = current_table_name[:-1]

            return current_table_name
        except Exception as e:
            self.statusBar().showMessage(f'Ошибка: {e.args[0]}')

    def get_id_of_element_at_row_and_column(self, item_row, item_column):
        try:
            table_widget = self.tables_tab_widget.currentWidget()
            column_id = -1
            for column_i in range(table_widget.columnCount()):
                column_text = table_widget.horizontalHeaderItem(column_i).text()
                if column_text == "id":
                    column_id = column_i
                    break
            if column_id == -1:
                raise Exception("Поля id не существует в таблице")

            return int(table_widget.item(item_row, column_id).text())
        except Exception as e:
            self.statusBar().showMessage(f'Ошибка: {e.args[0]}')

    def item_changed(self, item):
        try:
            current_table_name = self.get_current_table_name()
            # Если значение в ячейке было изменено,
            # то в словарь записывается пара: название поля, новое значение
            table_widget = self.tables_tab_widget.currentWidget()
            prop = table_widget.horizontalHeaderItem(item.column()).text()

            id = self.get_id_of_element_at_row_and_column(item.row(), item.column())

            modified_data = {"property": prop, "text": item.text()}
            current_modif_table = self.modified_data_in_tables.get(current_table_name)
            if not current_modif_table.get(id, False):
                current_modif_table[id] = [modified_data]
            else:
                current_modif_table[id].append(modified_data)

            self.tables_tab_widget.setTabText(
                self.tables_tab_widget.currentIndex(), f"{current_table_name}*")
        except Exception as e:
            self.statusBar().showMessage(f'Ошибка: {e.args[0]}')

    def save_all_tables_changes(self):
        try:
            if self.modified_data_in_tables and self.tables_tab_widget:
                indx_of_table = 0
                for table_name, value in self.modified_data_in_tables.items():
                    if value:
                        cur = self.db_connection.cursor()
                        for id, changed_props in self.modified_data_in_tables[table_name].items():
                            que = f"UPDATE {table_name} SET\n"
                            que += ", ".join([f"{props['property']}='{props['text']}'" for props in changed_props])
                            que += f" WHERE id = {id}"
                            cur.execute(que)

                        self.db_connection.commit()
                        self.modified_data_in_tables[table_name].clear()
                    self.tables_tab_widget.setTabText(
                        indx_of_table, table_name)
                    indx_of_table += 1
            else:
                raise Exception('Нет таблицы')
        except Exception as e:
            self.statusBar().showMessage(f'Ошибка: {e.args[0]}')

    def save_current_table_changes(self):
        try:
            if self.modified_data_in_tables and self.tables_tab_widget:
                current_table_name = self.get_current_table_name()
                if current_table_name and self.modified_data_in_tables[current_table_name]:
                    cur = self.db_connection.cursor()
                    for id, changed_props in self.modified_data_in_tables[current_table_name].items():
                        que = f"UPDATE {current_table_name} SET\n"
                        que += ", ".join([f"'{props['property']}'='{props['text']}'" for props in changed_props])
                        que += f" WHERE id = '{id}'"
                        cur.execute(que)

                    self.db_connection.commit()
                    self.modified_data_in_tables[current_table_name].clear()
                    self.tables_tab_widget.setTabText(
                        self.tables_tab_widget.currentIndex(), current_table_name)
            else:
                raise Exception('Нет таблицы')
        except Exception as e:
            self.statusBar().showMessage(f'Ошибка: {e.args[0]}')

    def delete_elem(self):
        try:
            if self.tables_tab_widget:
                table_widget = self.tables_tab_widget.currentWidget()
                rows = list(set([i.row() for i in table_widget.selectedItems()]))
                if not rows:
                    raise Exception('Не выделены никакие строки')
                ids = [table_widget.item(i, 0).text() for i in rows]

                valid = QMessageBox.question(
                    self, '', "Действительно удалить элементы с id " + ",".join(ids),
                    QMessageBox.Yes, QMessageBox.No)

                if valid == QMessageBox.Yes:
                    cur = self.db_connection.cursor()
                    current_table_name = self.get_current_table_name()

                    cur.execute(f"DELETE FROM {current_table_name} WHERE id IN (" + ", ".join(
                        '?' * len(ids)) + ")", ids)
                    self.db_connection.commit()

                    self.init_table_widget_for_db_table(table_widget, current_table_name)

                    self.modified_data_in_tables[current_table_name].clear()
                    self.tables_tab_widget.setTabText(
                        self.tables_tab_widget.currentIndex(), current_table_name)
            else:
                raise Exception('Нет таблицы')
        except sqlite3.Error as e:
            self.statusBar().showMessage(f'Ошибка с бд: {e.args[0]}')
        except Exception as e:
            self.statusBar().showMessage(f'Ошибка: {e.args[0]}')

    def closeEvent(self, event):
        reply = QMessageBox.question(self, 'Закрытие окна', 'Вы уверены, что хотите закрыть приложение?',
                                     QMessageBox.Yes | QMessageBox.No, QMessageBox.No)

        if reply == QMessageBox.Yes:
            if self.db_connection:
                self.db_connection.close()
            event.accept()
        else:
            event.ignore()
Exemple #53
0
class MainWindow(QMainWindow):
    """
	the main render proccess of the browser including all updating methods and the webview
	"""
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
        self.url = {}
        self.setWindowTitle("Bird-Browser")
        self.wordlist = [
            "dev://", "bookmark://", "bookmarks://", "search://", "http://",
            "https://", "pwd://"
        ]
        self.tabs = QTabWidget()
        self.tabcreate = QPushButton("+")
        self.shortcreatetab = QShortcut(self)
        self.shortcreatetab.setKey("Ctrl+T")
        self.pwdman = pwdmanager.PwdManager(
            config["key"], f"{Path.home()}/.config/bird/database.db")

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

        self.tabs.setTabsClosable(True)

        self.createtab()

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

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

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

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

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

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

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

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

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

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

    def renderDevToolsView(self, webview):
        return self.tabs.setCurrentWidget(
            devtools.DevToolWidget(webview.page().url().toString()))
Exemple #54
0
    def __init__(self, manager, parent=None):
        QTabWidget.__init__(self, parent)
        self.manager = manager
        self.area = None
        self.reference = None
        self.index = 0
        self.dragCanStart = False
        self.tabDragCanStart = False
        self.areaDragCanStart = False
        self.setTabBar(QToolWindowTabBar(self))
        self.setMovable(True)
        self.setTabShape(QTabWidget.Rounded)
        self.setDocumentMode(
            self.manager.config.setdefault(QTWM_AREA_DOCUMENT_MODE, True))
        self.useCustomTabCloseButton = self.manager.config.setdefault(
            QTWM_AREA_TABS_CLOSABLE, False)
        self.useTableFrame = self.manager.config.setdefault(
            QTWM_AREA_USE_TAB_FRAME, False)
        self.setTabsClosable(
            self.manager.config.setdefault(QTWM_AREA_TABS_CLOSABLE, False)
            and not self.useCustomTabCloseButton)
        self.setTabPosition(
            self.manager.config.setdefault(QTWM_AREA_TAB_POSITION,
                                           QTabWidget.North))
        # self.setLayoutDirection ( QtCore.Qt.LeftToRight )

        self.tabBar().setSizePolicy(QSizePolicy.Expanding,
                                    QSizePolicy.Preferred)
        self.setFocusPolicy(QtCore.Qt.StrongFocus)

        areaUseImageHandle = self.manager.config.setdefault(
            QTWM_AREA_IMAGE_HANDLE, False)
        if self.useTableFrame:
            self.tabFrame = QToolWindowSingleTabAreaFrame(manager, self)
            self.tabFrame.hide()
            self.tabFrame.installEventFilter(self)
            self.tabFrame.caption.installEventFilter(self)

        if self.manager.config.setdefault(QTWM_AREA_SHOW_DRAG_HANDLE, False):
            corner = QLabel(self)
            corner.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding)
            corner.setAttribute(QtCore.Qt.WA_TranslucentBackground)
            self.setCornerWidget(corner)
            if areaUseImageHandle:
                corner_img = QPixmap()
                corner_img.load(
                    self.manager.config.setdefault(
                        QTWM_DROPTARGET_COMBINE,
                        "./resources/drag_handle.png"))
                corner.setPixmap(corner_img)
            else:
                corner.setFixedHeight(8)
                corner_img = QPixmap(corner.size())
                corner_img.fill(QtCore.Qt.transparent)

                option = QStyleOptionToolBar()
                option.initFrom(self.tabBar())
                option.state |= Qt.QStyle.State_Horizontal
                option.lineWidth = self.tabBar().style().pixelMetric(
                    Qt.QStyle.PM_ToolBarFrameWidth, None, self.tabBar())
                option.features = QStyleOptionToolBar.Movable
                option.toolBarArea = QtCore.Qt.NoToolBarArea
                option.direction = QtCore.Qt.RightToLeft
                option.rect = corner_img.rect()
                option.rect.moveTo(0, 0)

                painter = QPainter(corner_img)
                self.tabBar().style().drawPrimitive(
                    Qt.QStyle.PE_IndicatorToolBarHandle, option, painter,
                    corner)
                painter.end()
                corner.setPixmap(corner_img)
            corner.setCursor(QtCore.Qt.OpenHandCursor)
            corner.installEventFilter(self)

        self.tabBar().installEventFilter(self)
        self.tabBar().setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.showContextMenu)
        self.tabBar().customContextMenuRequested.connect(self.showContextMenu)
        self.tabBar().tabCloseRequested.connect(self.closeTab)
Exemple #55
0
    def eventFilter(self, o, e):
        if o == self.tabBar() or o == self.cornerWidget(
        ) or o == self.tabFrame or o == self.tabFrame.caption:

            # debug msg
            # if e.type () == Qt.QEvent.MouseButtonPress or e.type () == Qt.QEvent.MouseMove:
            # 	if o == self.tabBar ():
            # 		qWarning ( "eventFilter o == self.tabBar ()" )
            # 	elif o == self.cornerWidget ():
            # 		qWarning ( "eventFilter o == self.cornerWidget ()" )
            # 	elif o == self.tabFrame:
            # 		qWarning ( "eventFilter o == self.tabFrame" )
            # 	elif o == self.tabFrame.caption:
            # 		qWarning ( "eventFilter o == self.tabFrame.caption" )

            if e.type() == QEvent.MouseButtonPress and e.buttons(
            ) == QtCore.Qt.LeftButton:

                self.areaDragCanStart = False
                self.tabDragCanStart = False
                # if ((pObject == m_pTabFrame & & m_pTabFrame->m_pCaption->rect().contains ( me->pos())) | | pObject == m_pTabFrame->m_pCaption | | (pObject == tabBar() & & tabBar()->tabAt(static_cast < QMouseEvent * > (pEvent)->pos()) >= 0))

                if ( self.useTableFrame and o == self.tabFrame and self.tabFrame.caption.rect ().contains ( e.pos () ) )\
                  or ( self.useTableFrame and o == self.tabFrame.caption ) \
                  or ( o == self.tabBar () and self.tabBar ().tabAt ( e.pos () ) >= 0 ):
                    self.tabDragCanStart = True
                    # qWarning ( "[QToolWindowArea] eventFilter: tabDragCanStart = true" )
                elif self.manager.config.setdefault(
                        QTWM_AREA_SHOW_DRAG_HANDLE,
                        False) and (o == self.cornerWidget() or
                                    (o == self.tabBar()
                                     and self.cornerWidget().isVisible()
                                     and self.manager.config.setdefault(
                                         QTWM_AREA_EMPTY_SPACE_DRAG, False))):
                    self.areaDragCanStart = True
                    # qWarning ( "[QToolWindowArea] eventFilter: areaDragCanStart = true" )
                # MyCode
                else:
                    self.dragCanStart = True
                    # qWarning ( "[QToolWindowArea] eventFilter: dragCanStart = true" )

                if self.manager.isMainWrapper(self.parentWidget()):
                    self.areaDragCanStart = False
                    if self.count() == 1:
                        self.tabDragCanStart = False

            elif e.type() == QEvent.MouseButtonRelease:
                self.tabDragCanStart = False
                self.dragCanStart = False
                self.areaDragCanStart = False
                self.manager.updateDragPosition()
                # qWarning ( "[QToolWindowArea] eventFilter: MouseButtonRelease" )

            elif e.type() == QEvent.MouseMove:
                self.manager.updateDragPosition()

                if self.tabDragCanStart:
                    if self.tabBar ().rect ().contains ( e.pos () ) \
                      or ( self.manager.config.setdefault ( QTWM_AREA_SHOW_DRAG_HANDLE, False ) and self.cornerWidget ().rect ().contains ( e.pos () ) ):
                        return False

                    if e.buttons() != QtCore.Qt.LeftButton:
                        return False

                    # qWarning ( "[QToolWindowArea] eventFilter: tabDragCanStart." )

                    toolWindow = self.currentWidget()
                    if self.useTableFrame and cast(
                            toolWindow,
                            QToolWindowSingleTabAreaFrame) == self.tabFrame:
                        toolWindow = self.tabFrame.contents

                    if not (toolWindow
                            and self.manager.ownsToolWindow(toolWindow)):
                        return False

                    self.tabDragCanStart = False
                    # qWarning ( "[QToolWindowArea] eventFilter: tabDragCanStart = false" )

                    # stop internal tab drag in QTabBar
                    releaseEvent = QMouseEvent(QEvent.MouseButtonRelease,
                                               e.pos(), QtCore.Qt.LeftButton,
                                               QtCore.Qt.LeftButton,
                                               QtCore.Qt.NoModifier)
                    qApp.sendEvent(self.tabBar(), releaseEvent)

                    self.manager.startDrag([toolWindow], self)

                elif self.areaDragCanStart:
                    if qApp.mouseButtons () == QtCore.Qt.LeftButton \
                      and not ( self.manager.config.setdefault ( QTWM_AREA_SHOW_DRAG_HANDLE, False ) and self.cornerWidget ().rect ().contains (
                     self.mapFromGlobal ( QCursor.pos () ) ) ):

                        # qWarning ( "[QToolWindowArea] eventFilter: areaDragCanStart." )

                        toolWindows = []
                        for i in range(0, self.count()):
                            toolWindow = self.widget(i)
                            if self.useTableFrame and cast(
                                    toolWindow, QToolWindowSingleTabAreaFrame
                            ) == self.tabFrame:
                                toolWindow = self.tabFrame.contents
                            toolWindows.append(toolWindow)

                        self.areaDragCanStart = False
                        # qWarning ( "[QToolWindowArea] eventFilter: areaDragCanStart = false" )

                        if self.cornerWidget() != None:
                            releaseEvent = QMouseEvent(
                                Qt.QEvent.MouseButtonRelease, e.pos(),
                                QtCore.Qt.LeftButton, QtCore.Qt.LeftButton,
                                QtCore.Qt.NoModifier)
                            qApp.sendEvent(self.cornerWidget(), releaseEvent)
                        self.manager.startDrag(toolWindows, self)
                        self.releaseMouse()

                elif self.dragCanStart:
                    self.check_mouse_move(e)

        return QTabWidget.eventFilter(self, o, e)
Exemple #56
0
 def setCurrentWidget(self, w):
     if self.useTableFrame and w == self.tabFrame.contents:
         QTabWidget.setCurrentWidget(self, self.tabFrame)
     else:
         QTabWidget.setCurrentWidget(self, w)
class MainWinBase(QMainWindow):
    def __init__(self):
        super().__init__()
        self.resize(1024, 720)
        self.menubar = self.menuBar()
        self.statusbar = self.statusBar()
        self.mainTabWidget = QTabWidget()

        self.actions = {}
        self.menus = {}
        self.submenus = {}
        self.contexMenus = {}
        self.toolbars = {}
        self.status = {}
        self.docks = {}
        self.documents = {}

        self.createActions()
        self.themeCombo = QComboBox()
        self.createMenubar()
        self.createContexMenus()
        self.createToolbars()
        self.createStatusBar()
        self.createDocks()
        self.createMainWidget()

        self.setupUiActions()

    def createActions(self):
        def createAct(text,
                      tip=None,
                      shortcut=None,
                      iconimg=None,
                      checkable=False,
                      slot=None):
            action = QAction(self.tr(text), self)
            if iconimg is not None:
                action.setIcon(QIcon(iconimg))
            if shortcut is not None:
                action.setShortcut(shortcut)
            if tip is not None:
                tip = self.tr(tip)
                action.setToolTip(tip)
                action.setStatusTip(tip)
            if checkable:
                action.setCheckable(True)
            if slot is not None:
                action.triggered.connect(slot)
            return action

        def keys2str(standardkey):
            return "".join(("(", QKeySequence(standardkey).toString(), ")"))

        # self.actions["new"] = createAct(self.tr("&New", "&New"),
        #                                 self.tr("new") + keys2str(QKeySequence.New), QKeySequence.New,
        #                                 ':appres.img/NewDocument.png')
        self.actions["import"] = createAct(self.tr("&Import Image"),
                                           self.tr("Import Image"), None,
                                           ':appres.img/importimage.png')
        self.actions["replaceimage"] = createAct(
            self.tr("&Replace Image"), self.tr("Replace Image"), None,
            ':appres.img/replaceimage.png')
        self.actions["open"] = createAct(
            self.tr("&Open Project"),
            self.tr("Open") + keys2str(QKeySequence.Open), QKeySequence.Open,
            ':appres.img/open.png')
        self.actions["save"] = createAct(
            self.tr("&Save"),
            self.tr("Save") + keys2str(QKeySequence.Save), QKeySequence.Save,
            ':appres.img/save.png')
        self.actions["saveas"] = createAct(self.tr("&Save as..."),
                                           self.tr("Save as..."), None,
                                           ':appres.img/SaveAs.png')
        self.actions["export"] = createAct(
            self.tr("&ExportCurves"), self.tr("Export digitized curves data"),
            "Ctrl+Alt+E", ':appres.img/export.png')
        self.actions["close"] = createAct(self.tr("&Close"), self.tr("Close"))
        self.actions["exit"] = createAct(self.tr("&Exit"), self.tr("Exit"),
                                         "Ctrl+Q")
        self.actions["undo"] = createAct(
            self.tr("&Undo"),
            self.tr("Undo") + keys2str(QKeySequence.Undo), QKeySequence.Undo,
            ':appres.img/undo.png')
        self.actions["redo"] = createAct(
            self.tr("&Redo"),
            self.tr("Redo") + keys2str(QKeySequence.Redo), QKeySequence.Redo,
            ':appres.img/redo.png')
        self.actions["cut"] = createAct(
            self.tr("&Cut"),
            self.tr("Cut") + keys2str(QKeySequence.Cut), QKeySequence.Cut,
            ':appres.img/cut.png')
        self.actions["copy"] = createAct(
            self.tr("&Copy"),
            self.tr("Copy") + keys2str(QKeySequence.Copy), QKeySequence.Copy,
            ':appres.img/copy.png')
        self.actions["paste"] = createAct(
            self.tr("&Paste"),
            self.tr("Paste") + keys2str(QKeySequence.Paste),
            QKeySequence.Paste, ':appres.img/paste.png')
        self.actions["zoomin"] = createAct(self.tr("&ZoomIn"),
                                           self.tr("Zoom In"), "Ctrl++",
                                           ':appres.img/zoomin.png')
        self.actions["zoomout"] = createAct(self.tr("&ZoomOut"),
                                            self.tr("Zoom Out"), "Ctrl+-",
                                            ':appres.img/zoomout.png')
        self.actions["showgrid"] = createAct(self.tr("Show Axes &Grid"),
                                             self.tr("Show AxesGrid"),
                                             None,
                                             ':appres.img/grid.png',
                                             checkable=True)
        self.actions["showgrid"].setChecked(True)
        self.actions["select"] = createAct(self.tr("Select Mode"),
                                           self.tr("Select Mode"),
                                           None,
                                           ':appres.img/select.png',
                                           checkable=True)
        self.actions["axesx"] = createAct(self.tr("Set x axis postions"),
                                          self.tr("Set x axis position"),
                                          None,
                                          ':appres.img/axesx.png',
                                          checkable=True)
        self.actions["axesy"] = createAct(self.tr("Set y axis postions"),
                                          self.tr("Set y axis position"),
                                          None,
                                          ':appres.img/axesy.png',
                                          checkable=True)
        self.actions["curve"] = createAct(self.tr("&AddCurve"),
                                          self.tr("Add Curve"),
                                          None,
                                          ':appres.img/curve.png',
                                          checkable=True)
        self.actions["del"] = createAct(self.tr("&del point or axis"),
                                        self.tr("delete"), QKeySequence.Delete,
                                        ':appres.img/delete.png')
        self.actions["addcurve"] = createAct(self.tr("add a new curve"),
                                             self.tr("add a new curve"), None,
                                             ':appres.img/new.png')
        self.actions["renamecurve"] = createAct(
            self.tr("change curve name"), self.tr("change current curve name"),
            None, ':appres.img/edit.png')
        self.actions["delcurve"] = createAct(self.tr("&del curve"),
                                             self.tr("delete selected curve"),
                                             QKeySequence.Delete,
                                             ':appres.img/delete.png')

        self.actions["scalegraph"] = createAct(
            self.tr("set graph image scale"),
            self.tr("scale the graph image(background)"), None,
            ":appres.img/resizeimage.png")
        self.actions["gridsetting"] = createAct(
            self.tr("grid settings"), self.tr("set grid range and step"), None,
            ":appres.img/gridsetting.png")

        # self.actions["DisableQss"] = createAct(self.tr("&DisableQss"), self.tr("DisableQss"), checkable=True)
        # self.actions["DisableQss"].setChecked(False)
        # self.actions["ShowColor"] = createAct(self.tr("&ColorPanel"),
        #                                       self.tr("ShowColorPanel"),
        #                                       None,
        #                                       ":appres.img/color.png",
        #                                       checkable=True)
        # self.actions["ShowColor"].setChecked(True)
        self.actions["showcurves"] = createAct(
            self.tr("&CurvePanel"),
            self.tr("ShowCurvesPanel"),
            None,
            ":appres.img/view2col2right.png",
            checkable=True)
        self.actions["showfit"] = createAct(
            self.tr("Show Fit&&Interpolation Panel"),
            self.tr("ShowCurve Fit&Interpolation Panel"),
            None,
            None,
            checkable=True)
        self.actions["showcurves"].setChecked(True)

        self.actions["hidegraph"] = createAct(
            self.tr("Hide Graph"),
            self.tr("Hide the graph(background image)"),
            None,
            None,
            checkable=True)
        self.actions["showoriginalgraph"] = createAct(
            self.tr("Original Graph"),
            self.tr("Show the original graph(background image)"),
            None,
            None,
            checkable=True)

        self.actions["config"] = createAct(self.tr("&Config"),
                                           self.tr("settings"), None,
                                           ":appres.img/config.png")

        self.actions["about"] = createAct(self.tr("&About"), self.tr("About"))
        self.actions["help"] = createAct(self.tr("&Help"), self.tr("Help"))

        # self.exitAct.triggered.connect(qApp.exit)#等价于qApp.quit
        self.actions["exit"].triggered.connect(self.close)

    def createMenubar(self):
        self.menus["File"] = QMenu(self.tr("&File"))
        self.menus["Edit"] = QMenu(self.tr("&Edit"))
        self.menus["Digit"] = QMenu(self.tr("&Digit"))
        self.menus["View"] = QMenu(self.tr("&View"))
        self.menus["Config"] = QMenu(self.tr("&Config"))
        self.menus["Help"] = QMenu(self.tr("&Help"))

        editMenu = QMenu(self.tr("Text"), self.menus["Edit"])
        editMenu.setIcon(QIcon(":appres.img/edit_whitepage.png"))
        editMenu.addAction(self.actions["undo"])
        editMenu.addAction(self.actions["redo"])
        # editMenu.addSeparator()
        # editMenu.addAction(self.actions["cut"])
        # editMenu.addAction(self.actions["copy"])
        # editMenu.addAction(self.actions["paste"])

        self.menus["File"].addAction(self.actions["import"])
        self.menus["File"].addAction(self.actions["replaceimage"])
        self.menus["File"].addAction(self.actions["open"])
        self.menus["File"].addAction(self.actions["save"])
        self.menus["File"].addAction(self.actions["saveas"])
        self.menus["File"].addAction(self.actions["export"])
        self.menus["File"].addAction(self.actions["close"])
        self.menus["File"].addSeparator()
        self.menus["File"].addAction(self.actions["exit"])

        self.menus["Edit"].addAction(self.actions["undo"])
        self.menus["Edit"].addAction(self.actions["redo"])

        self.menus["Digit"].addAction(self.actions["select"])
        self.menus["Digit"].addAction(self.actions["axesx"])
        self.menus["Digit"].addAction(self.actions["axesy"])
        self.menus["Digit"].addAction(self.actions["curve"])
        self.menus["Digit"].addSeparator()
        self.menus["Digit"].addAction(self.actions["addcurve"])
        self.menus["Digit"].addAction(self.actions["renamecurve"])
        self.menus["Digit"].addAction(self.actions["del"])

        self.menus["View"].addAction(self.actions["zoomin"])
        self.menus["View"].addAction(self.actions["zoomout"])
        self.menus["View"].addSeparator()
        background = QMenu(self.tr("Graph Background"), self.menus["View"])
        background.addAction(self.actions["hidegraph"])
        background.addAction(self.actions["showoriginalgraph"])
        self.menus["View"].addMenu(background)
        self.menus["View"].addAction(self.actions["showgrid"])
        self.menus["View"].addSeparator()
        self.menus["View"].addAction(self.actions["showcurves"])
        self.menus["View"].addAction(self.actions["showfit"])
        self.menus["View"].addSeparator()

        self.menus["Config"].addAction(self.actions["config"])

        self.menus["Help"].addAction(self.actions["help"])
        self.menus["Help"].addSeparator()
        self.menus["Help"].addAction(self.actions["about"])

        for m in self.menus.values():
            self.menubar.addMenu(m)

    def createContexMenus(self):
        self.contexMenus["Edit"] = QMenu(self.tr("Edit"))
        self.contexMenus["Edit"].addAction(self.actions["cut"])
        self.contexMenus["Edit"].addAction(self.actions["copy"])
        self.contexMenus["Edit"].addAction(self.actions["paste"])

    def createToolbars(self):
        themeLabel = QLabel(self.tr("Theme "))
        # self.themeCombo = QComboBox()
        themeLabel.setToolTip(self.tr("Using system style."))
        self.themeCombo.setToolTip(self.tr("Select system style."))
        self.themeCombo.addItems(QStyleFactory.keys())
        self.themeCombo.setMinimumWidth(105)
        theme = QApplication.style().objectName()
        self.themeCombo.setCurrentIndex(
            self.themeCombo.findText(theme, Qt.MatchFixedString))
        # self.themeCombo.setEnabled(False)
        # themeCombo.activated[str].connect(qApp.setStyle)
        # themeCombo.currentTextChanged.connect(qApp.setStyle)
        # checkbox.stateChanged.connect(self.themeCombo.setEnabled)
        # checkbox.stateChanged.connect(lambda x:self.actions["DisableQss"].setChecked(checkbox.isChecked()))

        self.toolbars["Main"] = QToolBar(self.tr("Main", "toolbar"))
        self.toolbars["Main"].addWidget(themeLabel)
        self.toolbars["Main"].addWidget(self.themeCombo)

        self.toolbars["File"] = QToolBar(self.tr("File"))
        self.toolbars["File"].addAction(self.actions["import"])
        self.toolbars["File"].addAction(self.actions["open"])
        self.toolbars["File"].addAction(self.actions["save"])
        # self.toolbars["File"].addAction(self.actions["saveas"])
        self.toolbars["File"].addAction(self.actions["export"])

        self.toolbars["Edit"] = QToolBar(self.tr("Edit"))
        self.toolbars["Edit"].addAction(self.actions["undo"])
        self.toolbars["Edit"].addAction(self.actions["redo"])
        self.toolbars["Edit"].addAction(self.actions["del"])

        self.toolbars["Digitize"] = QToolBar(self.tr("Digitize"))
        self.toolbars["Digitize"].addAction(self.actions["select"])
        self.toolbars["Digitize"].addAction(self.actions["axesx"])
        self.toolbars["Digitize"].addAction(self.actions["axesy"])
        self.toolbars["Digitize"].addAction(self.actions["curve"])

        self.toolbars["Display"] = QToolBar(self.tr("Display"))
        self.toolbars["Display"].addAction(self.actions["zoomin"])
        self.toolbars["Display"].addAction(self.actions["zoomout"])
        self.toolbars["Display"].addAction(self.actions["showgrid"])

        self.toolbars["Setting"] = QToolBar(self.tr("Setting"))
        self.toolbars["Setting"].addAction(self.actions["scalegraph"])
        self.toolbars["Setting"].addAction(self.actions["gridsetting"])
        self.toolbars["Setting"].addAction(self.actions["config"])

        self.toolbars["View"] = QToolBar(self.tr("View"))
        self.toolbars["View"].addAction(self.actions["showcurves"])

        for t in self.toolbars.values():
            self.addToolBar(t)

    def createStatusBar(self):
        self.statusbar.showMessage(self.tr("Ready"))
        # self.statusbar.addWidget(QWidget(),1)
        # self.status["date"] = QLabel()
        # self.statusbar.addPermanentWidget(self.status["date"])
        # self.status["date"].setText(QDate.currentDate().toString())
        # self.status["date"].setVisible(False)

        self.status["point"] = QLabel(self.tr("Point Coordinate: 0,0"))
        self.status["pixel"] = QLabel(self.tr("Pixel Location: 0,0"))
        self.status["point"].setMinimumWidth(200)
        self.status["pixel"].setMinimumWidth(200)
        # self.status["coding"].setAlignment(Qt.AlignCenter)
        self.statusbar.addPermanentWidget(self.status["point"])
        self.statusbar.addPermanentWidget(self.status["pixel"])

    def createDocks(self):
        self.docks["curves"] = QDockWidget(self.tr("Axes and Curves"))
        self.docks["curves"].setMinimumSize(QSize(200, 200))
        self.docks["curves"].setFeatures(QDockWidget.DockWidgetMovable
                                         | QDockWidget.DockWidgetFloatable)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.docks["curves"])

        self.docks["fit"] = FitDockWidget(self.tr("Poly Fit"))
        self.docks["fit"].setMinimumSize(QSize(200, 200))
        self.docks["fit"].setFeatures(QDockWidget.DockWidgetMovable
                                      | QDockWidget.DockWidgetFloatable)
        self.addDockWidget(Qt.RightDockWidgetArea, self.docks["fit"])
        #self.tabifyDockWidget(self.docks["curves"], self.docks["fit"])
        #self.docks["curves"].raise_()
        self.docks["fit"].setVisible(False)

        self.docks["curves"].visibilityChanged.connect(
            self.actions["showcurves"].setChecked)
        self.docks["fit"].visibilityChanged.connect(
            self.actions["showfit"].setChecked)

        self.docktabwidget = QTabWidget(self.docks["curves"])
        self.docks["curves"].setWidget(self.docktabwidget)
        self.docktabwidget.setTabPosition(QTabWidget.South)
        self.axesTab = QSplitter(Qt.Vertical)  # QScrollArea()
        self.curveTab = QSplitter(Qt.Vertical)
        self.docktabwidget.addTab(self.axesTab, "axes")
        self.docktabwidget.addTab(self.curveTab, "curve")
        self.docktabwidget.setCurrentIndex(1)

        self.axesxTable = QTableView()
        self.axesyTable = QTableView()
        self.axesTab.addWidget(self.axesxTable)
        self.axesTab.addWidget(self.axesyTable)

        self.curveTable = QTableView()
        self.pointsTable = QTableView()
        # self.axesTab.setWidgetResizable(True)
        w = QWidget()
        lay = QVBoxLayout()
        lay.setContentsMargins(0, 0, 0, 0)
        self.curvePanelToolbar = QToolBar(self.curveTab)
        lay.addWidget(self.curvePanelToolbar)
        lay.addWidget(self.curveTable)
        w.setLayout(lay)
        self.curveTab.addWidget(w)
        self.curveTab.addWidget(self.pointsTable)
        self.curvePanelToolbar.addAction(self.actions["addcurve"])
        self.curvePanelToolbar.addAction(self.actions["renamecurve"])
        self.curvePanelToolbar.addAction(self.actions["delcurve"])

    def createMainWidget(self):
        self.setCentralWidget(self.mainTabWidget)
        self.mainTabWidget.setTabBarAutoHide(True)

    def setupUiActions(self):
        self.actions["showcurves"].triggered.connect(
            self.docks["curves"].setVisible)
        self.actions["showfit"].triggered.connect(self.docks["fit"].setVisible)
        self.themeCombo.currentTextChanged.connect(qApp.setStyle)

    # misc func
    def updatePixelCoordStatus(self, ptorx, y=None):
        if isinstance(ptorx, QPoint) or isinstance(ptorx, QPointF):
            self.status["pixel"].setText("Pixel Coordinate: {},{}".format(
                ptorx.x(), ptorx.y()))
        else:
            self.status["pixel"].setText("Pixel Coordinate: {},{}".format(
                ptorx, y))

    def updatePointCoordStatus(self, ptorx, y=None):
        if isinstance(ptorx, QPoint) or isinstance(ptorx, QPointF):
            self.status["point"].setText(
                "Point Coordinate: {:.0f},{:.0f}".format(ptorx.x(), ptorx.y()))
        else:
            self.status["point"].setText(
                "Point Coordinate: {:.0f},{:.0f}".format(ptorx, y))
Exemple #58
0
 def indexOf(self, w):
     if self.useTableFrame and w == self.tabFrame.contents:
         w = self.tabFrame
     return QTabWidget.indexOf(self, w)
Exemple #59
0
    def setupUi(self, MainWindow):
        resolution = QDesktopWidget().screenGeometry(self)
        # MainWindow.setGeometry(QRect(0,0,0,0))
        MainWindow.setFixedSize(resolution.size().width() * 0.99,
                                resolution.size().height() * 0.90)  #1200 800
        # self.setWindowState(Qt.WindowMaximized)
        print("resol : ", MainWindow.size())

        #메인 화면 색상py
        self.setStyleSheet("color: black;" "background-color: white;")

        font = QFont()
        font.setFamily("NanumGothic")
        MainWindow.setFont(font)
        self.centralwidget = QWidget(MainWindow)
        self.label = QLabel(self.centralwidget)
        self.label.setGeometry(QRect(20, 20, 130, 35))
        font = QFont()
        font.setFamily("NanumGothic")
        font.setPointSize(18)
        font.setBold(True)
        font.setWeight(75)
        self.label.setFont(font)
        self.button_add = QPushButton(self.centralwidget)
        self.button_add.setGeometry(
            QRect(MainWindow.size().width() * 0.05,
                  MainWindow.size().height() - 80, 131, 34))
        #버튼 스타일 변경
        self.button_add.setStyleSheet(staticValues.blueButtonStyleSheet)
        self.button_add.setFont(staticValues.buttonFont)

        self.button_modi = QPushButton(self.centralwidget)
        self.button_modi.setGeometry(
            QRect(MainWindow.size().width() * 0.20,
                  MainWindow.size().height() - 80, 131, 34))
        self.button_modi.setStyleSheet(staticValues.blueButtonStyleSheet)
        self.button_modi.setFont(staticValues.buttonFont)

        self.button_del = QPushButton(self.centralwidget)
        self.button_del.setGeometry(
            QRect(MainWindow.size().width() * 0.35,
                  MainWindow.size().height() - 80, 131, 34))
        self.button_del.setStyleSheet(staticValues.redButtonStyleSheet)
        self.button_del.setFont(staticValues.buttonFont)

        self.button_upload = QPushButton(self.centralwidget)
        self.button_upload.setGeometry(
            QRect(MainWindow.size().width() * 0.7,
                  MainWindow.size().height() - 80, 131, 34))
        self.button_upload.setStyleSheet(staticValues.grayButtonStyleSheet)
        self.button_upload.setFont(staticValues.buttonFont)

        self.tabWidget = QTabWidget(self.centralwidget)
        self.tabWidget.setGeometry(
            QRect(10, 70,
                  MainWindow.size().width() - 15,
                  MainWindow.size().height() - 180))
        self.tab = QWidget()
        self.tab.layout = QVBoxLayout()
        self.tab2 = QWidget()
        self.tab2.layout = QVBoxLayout()
        self.tabWidget.addTab(self.tab, "회원 목록")
        self.tableWidget = QTableWidget(self.tab)
        self.tableWidget.setGeometry(
            QRect(0, 0,
                  self.tabWidget.size().width() - 5,
                  self.tabWidget.size().height() - 25))
        self.tableWidget.setColumnCount(13)
        self.tableWidget.setRowCount(0)
        self.tableWidget.setSelectionBehavior(QAbstractItemView.SelectRows)

        self.tableWidget = QTableWidget(self.tab)
        self.tableWidget.setGeometry(
            QRect(0, 0,
                  self.tabWidget.size().width() - 5,
                  self.tabWidget.size().height() - 25))
        self.tableWidget.setObjectName("회원 목록")
        self.tableWidget.setColumnCount(13)
        self.tableWidget.setRowCount(0)
        self.tableWidget.setSelectionBehavior(QAbstractItemView.SelectRows)

        self.tableWidget.setHorizontalHeaderLabels([
            "회원 ID", "단톡방", "코인명", "구매", "입금", "판매", "출근", "보유잔량", "총구매금액",
            "총판매금액", "수익", "평단가", "지갑주소"
        ])

        self.edit_search = QLineEdit(self.centralwidget)
        self.edit_search.setGeometry(
            QRect(MainWindow.size().width() - 280, 35, 200, 30))
        self.edit_search.setStyleSheet(staticValues.solidStyleSheet)

        self.button_search = QPushButton(self.centralwidget)
        self.button_search.setGeometry(
            QRect(MainWindow.size().width() - 80, 35, 70, 30))
        self.button_search.setStyleSheet(staticValues.grayButtonStyleSheet)
        self.button_search.setFont(staticValues.buttonFont)

        MainWindow.setCentralWidget(self.centralwidget)

        self.retranslateUi(MainWindow)
        self.tabWidget.setCurrentIndex(0)
        QMetaObject.connectSlotsByName(MainWindow)
Exemple #60
0
class Window(QWidget):
    COLUMNS_DICT = {
        # "Column label": {'index': column_ID, 'width': column_width}
        "ID": {
            "index": 0,
            "width": 25
        },
        "File name": {
            "index": 1,
            "width": 165
        },
        "Format": {
            "index": 2,
            "width": 50
        },
        "Dup": {
            "index": 3,
            "width": 5
        },
    }

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

        # store active image ID
        self.active_image_id = str()

        # Saves multiple duplicate windows references:
        self.duplicateRefs = {}

        # Gets status bar from QMainWindow:
        self.statusBar = statusBar

        # Initializes all window elements:
        self.folderField = QLineEdit()
        self.folderButton = QPushButton()
        self.folderTreeCheckbox = QCheckBox("Include sub-folders")
        self.processButton = QPushButton("Process media files")
        self.duplicateButton = QPushButton("Find duplicates")
        self.reindexButton = QPushButton("Reindex database files")
        self.tableTabs = QTabWidget()
        # init main images list table
        self.imageListTable = QTableWidget()
        # set main images list table fields unchanged
        self.imageListTable.setEditTriggers(QTableWidget.NoEditTriggers)
        # init main videos list table
        self.videoListTable = QTableWidget()
        # set main videos list table fields unchanged
        self.videoListTable.setEditTriggers(QTableWidget.NoEditTriggers)

        # set up image fields and elements
        self.imageField = QLabel()
        self.imageNameField = QLabel()
        self.imageParamsField = QLabel()

        self.imageCopyButton = QPushButton("Copy image")
        self.imageCopyButton.setIcon(QIcon("gui/static/icon_copy.png"))
        self.imageCopyButton.clicked.connect(self.copy_image_path)
        self.imageViewButton = QPushButton("View image")
        self.imageViewButton.setIcon(QIcon("gui/static/icon_open_image.svg"))
        self.imageViewButton.clicked.connect(self.open_image_file)
        self.imageOpenDirButton = QPushButton("Open dir")
        self.imageOpenDirButton.setIcon(
            QIcon("gui/static/icon_open_folder.svg"))
        self.imageOpenDirButton.clicked.connect(self.open_image_path)
        self.imageDeleteButton = QPushButton("Delete")
        self.imageDeleteButton.setIcon(
            QIcon("gui/static/icon_delete_file.png"))
        self.imageDeleteButton.clicked.connect(self.delete_image)

        self.videoField = QVideoWidget()
        self.videoPlayer = QMediaPlayer()

        # Adjusts settings for the window elements:
        self.folderField.setDisabled(True)

        self.folderButton.setIcon(QIcon("gui/static/icon_process_folder.png"))
        self.folderButton.clicked.connect(self.set_folder)

        self.processButton.clicked.connect(self.process_files)
        self.processButton.setFixedWidth(160)
        self.processButton.setDisabled(True)

        self.duplicateButton.clicked.connect(self.find_duplicates)
        self.duplicateButton.setFixedWidth(160)

        self.reindexButton.clicked.connect(self.reindex_db_data)
        self.reindexButton.setFixedWidth(160)

        # prepare tables for images and videos
        self.imagesTab = self.tableTabs.insertTab(0, self.imageListTable,
                                                  "Images")
        self.videosTab = self.tableTabs.insertTab(1, self.videoListTable,
                                                  "Videos")

        # images list table setup
        self.imageListTable.setColumnCount(len(self.COLUMNS_DICT.keys()))
        self.imageListTable.setHorizontalHeaderLabels(self.COLUMNS_DICT.keys())
        self.imageListTable.verticalHeader().setVisible(False)
        self.imageListTable.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.imageListTable.setSortingEnabled(True)
        self.imageListTable.cellClicked.connect(self.show_image)

        # videos list table setup
        self.videoListTable.setColumnCount(len(self.COLUMNS_DICT.keys()))
        self.videoListTable.setHorizontalHeaderLabels(self.COLUMNS_DICT.keys())
        self.videoListTable.verticalHeader().setVisible(False)
        self.videoListTable.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.videoListTable.setSortingEnabled(True)
        self.videoListTable.cellClicked.connect(self.show_video)

        # set images and videos duplicates columns width
        self.set_columns_width()

        # Places the window elements on the window:
        # Top-left cell of main grid box:
        subGridBox = QWidget()
        subGrid = QGridLayout()
        subGrid.addWidget(self.folderField, 0, 0)
        subGrid.addWidget(self.folderButton, 0, 1)
        subGrid.addWidget(self.folderTreeCheckbox, 1, 0)
        subGrid.addWidget(self.processButton, 2, 0, 1, 2, Qt.AlignCenter)
        subGrid.addWidget(self.duplicateButton, 3, 0, 1, 2, Qt.AlignCenter)
        subGrid.addWidget(self.reindexButton, 4, 0, 1, 2, Qt.AlignCenter)
        subGridBox.setLayout(subGrid)

        # image data grid box
        imageGridBox = QWidget()
        imageGrid = QGridLayout()
        imageGrid.addWidget(self.imageField, 0, 0, 1, 4, Qt.AlignCenter)
        # add image buttons
        imageGrid.addWidget(self.imageCopyButton, 1, 0, 1, 1)
        imageGrid.addWidget(self.imageViewButton, 1, 1, 1, 1)
        imageGrid.addWidget(self.imageOpenDirButton, 1, 2, 1, 1)
        imageGrid.addWidget(self.imageDeleteButton, 1, 3, 1, 1)

        imageGrid.addWidget(self.imageNameField, 2, 0, 1, 1)
        imageGrid.addWidget(self.imageParamsField, 2, 3, 1, 1)
        imageGridBox.setLayout(imageGrid)

        # Main grid box:
        self.mainGrid = QGridLayout()
        self.mainGrid.addWidget(subGridBox, 0, 0)
        self.mainGrid.addWidget(self.tableTabs, 1, 0)
        self.mainGrid.addWidget(imageGridBox, 1, 1)
        self.mainGrid.addWidget(self.videoField, 0, 1, 2, 1)
        self.mainGrid.setColumnMinimumWidth(0, 400)
        self.mainGrid.setRowMinimumHeight(1, 600)
        self.mainGrid.setColumnStretch(1, 1)

        self.setLayout(self.mainGrid)

        # Creates a QThread instance:
        self.thread = ProcessingThread(self.folderField, self.imageListTable,
                                       self.videoListTable,
                                       self.folderTreeCheckbox)

        self.thread.finishedTrigger.connect(self.finish_thread)

        # filling table while first run
        self.reindex_db_data()
        # hide image interface
        self.hide_active_image()

    def set_columns_width(self):
        # looping all columns and set with
        for value in self.COLUMNS_DICT.values():
            self.imageListTable.setColumnWidth(value["index"], value["width"])
            self.videoListTable.setColumnWidth(value["index"], value["width"])

    def reindex_db_data(self):
        self.duplicateButton.setDisabled(True)
        self.processButton.setDisabled(True)
        self.reindexButton.setDisabled(True)
        # Reindex already exist folders and files; Image and Video files
        reindex_image_files()
        reindex_video_files()
        # run table filling after reindexing
        self.table_data_init()
        self.duplicateButton.setEnabled(True)
        self.processButton.setEnabled(True)
        self.reindexButton.setEnabled(True)

    def center_widget_item(self, text: str) -> QTableWidgetItem:
        # create the item
        center_align_item = QTableWidgetItem(text)
        # change the alignment
        center_align_item.setTextAlignment(Qt.AlignCenter)
        return center_align_item

    def table_data_init(self):
        # get available images from DB
        with db_session():
            images = Image.all()

        for idx, image in enumerate(images):
            numRows = self.imageListTable.rowCount()
            self.imageListTable.insertRow(numRows)

            str_image_idx = str(idx)

            IMAGE_PATH_DICT[str_image_idx] = {
                "id": image.id,
                "name": image.image_name,
                "additional_attrs": {
                    "height": image.image_height,
                    "width": image.image_width
                },
                "folder": image.image_path,
                "type": (image.image_name.split(".")[-1]).lower(),
                "full_path": image.full_path(),
            }

            self.imageListTable.setItem(idx, self.COLUMNS_DICT["ID"]["index"],
                                        self.center_widget_item(str_image_idx))
            self.imageListTable.setItem(
                idx,
                self.COLUMNS_DICT["File name"]["index"],
                self.center_widget_item(image.image_name),
            )
            self.imageListTable.setItem(
                idx,
                self.COLUMNS_DICT["Format"]["index"],
                self.center_widget_item(
                    IMAGE_PATH_DICT[str_image_idx]["type"]),
            )

            duplicateIcon = QTableWidgetItem()
            duplicateIcon.setIcon(QIcon("gui/static/icon_view_duplicates.png"))
            self.imageListTable.setItem(idx, self.COLUMNS_DICT["Dup"]["index"],
                                        duplicateIcon)

    def hide_active_image(self):
        self.imageField.hide()
        self.imageCopyButton.hide()
        self.imageViewButton.hide()
        self.imageOpenDirButton.hide()
        self.imageDeleteButton.hide()
        self.imageNameField.hide()
        self.imageParamsField.hide()

    def show_active_image(self):
        self.imageField.show()
        self.imageCopyButton.show()
        self.imageViewButton.show()
        self.imageOpenDirButton.show()
        self.imageDeleteButton.show()
        self.imageNameField.show()
        self.imageParamsField.show()

    def open_image_file(self):
        open_path(path=IMAGE_PATH_DICT[self.active_image_id]["full_path"])

    def open_image_path(self):
        open_path(path=IMAGE_PATH_DICT[self.active_image_id]["folder"])

    def delete_image(self):
        # count image table position
        image_table_position = list(IMAGE_PATH_DICT.keys()).index(
            self.active_image_id)

        message = QMessageBox().question(
            self,
            "Confirm deletion",
            "Delete duplicate media file?",
            QMessageBox.Yes | QMessageBox.No,
        )
        if message == QMessageBox.Yes:
            self.imageListTable.removeRow(image_table_position)
            image_id = IMAGE_PATH_DICT[self.active_image_id]["id"]
            # run custom delete
            with db_session():
                Image[image_id].custom_delete()

            # delete image key from dict
            del IMAGE_PATH_DICT[self.active_image_id]

            self.hide_active_image()
            QMessageBox().information(self, "File deletion",
                                      "File success deleted", QMessageBox.Ok,
                                      QMessageBox.Ok)
        elif message == QMessageBox.No:
            pass

    def copy_image_path(self):
        try:
            result = copy_image(
                IMAGE_PATH_DICT[self.active_image_id]["full_path"])
            if result:
                QMessageBox.information(
                    self,
                    "Copy path",
                    "Success!\nFile copied to clipboard!",
                    QMessageBox.Ok,
                    QMessageBox.Ok,
                )
            else:
                QMessageBox.warning(
                    self,
                    "Copy path",
                    "Error!\nSorry, i can`t copy image to clipboard.",
                    QMessageBox.Ok,
                    QMessageBox.Ok,
                )

        except Exception:
            print(traceback.format_exc())
            QMessageBox.warning(
                self,
                "Copy path",
                f"Error!\n{traceback.format_exc()}",
                QMessageBox.Ok,
                QMessageBox.Ok,
            )

    # Get a folder full of multimedia files to work with
    def set_folder(self):
        self.folderPath = QFileDialog.getExistingDirectory(self)
        if self.folderPath == "":
            self.folderPath = self.folderField.text()
        self.folderField.setText(self.folderPath)
        self.processButton.setEnabled(True)
        self.statusBar.clearMessage()

    # Start the thread and fill the table with those files
    def process_files(self):
        # set other buttons disabled
        self.duplicateButton.setDisabled(True)
        self.reindexButton.setDisabled(True)

        # Clears both tables upon restarting function:
        self.imageListTable.clearContents()
        self.imageListTable.setRowCount(0)
        self.videoListTable.clearContents()
        self.videoListTable.setRowCount(0)

        self.statusBar.setStyleSheet("color: black")
        self.statusBar.showMessage("Processing...")

        if self.folderField.text() == "":
            self.statusBar.setStyleSheet("color: red")
            self.statusBar.showMessage("Please choose a directory")
            self.duplicateButton.setEnabled(True)
            self.reindexButton.setEnabled(True)
            return None

        if not self.thread.isRunning():
            self.duplicateRefs.clear()
            self.thread.start()
            self.processButton.setText("Stop")

        elif self.thread.isRunning():
            self.thread.terminate()
            self.processButton.setText("Process media files")
            self.duplicateButton.setEnabled(True)
            self.reindexButton.setEnabled(True)

    # Thread done and ded
    def finish_thread(self):
        self.statusBar.setStyleSheet("color: black")
        self.statusBar.showMessage("Finished!")
        self.processButton.setText("Process media files")
        # set all buttons able
        self.duplicateButton.setEnabled(True)
        self.reindexButton.setEnabled(True)

    # Start the second thread and remove all unique files from the table
    def find_duplicates(self):
        if IMAGE_PATH_DICT == {}:
            self.statusBar.setStyleSheet("color: red")
            self.statusBar.showMessage("Please process your media files first")
            return None

        self.duplicateButton.setDisabled(True)
        self.processButton.setDisabled(True)
        self.reindexButton.setDisabled(True)
        self.statusBar.setStyleSheet("color: black")
        self.statusBar.showMessage("Finding duplicates...")

        with db_session():
            # get all images descriptors
            image_files_query = Image.get_descriptors()

        pairs_amount = int(
            len(image_files_query) * (len(image_files_query) - 1) / 2)

        QMessageBox.information(
            self,
            "Find duplicates",
            f"""
            Similar images search start. Please wait!\n
            You have ~{pairs_amount} images pairs;
            Work will get ~{round(pairs_amount*0.00006, 2)} sec.
            """,
            QMessageBox.Ok,
            QMessageBox.Ok,
        )

        # run function to find duplicates
        result = feature_description(images_list=image_files_query)
        with db_session():
            # save duplicates to DB
            save_images_duplicates(result)

        QMessageBox.information(self, "Find duplicates", "Success!",
                                QMessageBox.Ok, QMessageBox.Ok)
        # set all buttons able
        self.duplicateButton.setEnabled(True)
        self.reindexButton.setEnabled(True)
        self.processButton.setEnabled(True)

        # TODO: new thread removing all unique media. Only duplicates remain

    # Show an image upon clicking its name in the table
    def show_image(self, row, column):
        imageId = self.imageListTable.item(row, 0).text()

        # set new active image id
        self.active_image_id = imageId

        # Removes a video from screen if shown:
        self.videoPlayer.stop()
        self.videoField.hide()
        # show active image
        self.show_active_image()

        # show image and additional data
        self.imageNameField.setText(f"{IMAGE_PATH_DICT[imageId]['name']}")
        self.imageParamsField.setText(
            f"HxW: {IMAGE_PATH_DICT[imageId]['additional_attrs']['height']}px"
            + f" x {IMAGE_PATH_DICT[imageId]['additional_attrs']['width']}px")

        # Shows animated images
        if IMAGE_PATH_DICT[imageId]["name"].lower().endswith("gif"):
            gif = QMovie(IMAGE_PATH_DICT[imageId]["full_path"])
            gifSize = QSize(*self.smooth_gif_resize(
                IMAGE_PATH_DICT[imageId]["full_path"], 600, 600))
            gif.setScaledSize(gifSize)
            self.imageField.setMovie(gif)
            gif.start()

        # Shows static images
        else:
            self.imageField.setPixmap(
                QPixmap(IMAGE_PATH_DICT[imageId]["full_path"]).scaled(
                    600, 600, Qt.KeepAspectRatio, Qt.SmoothTransformation))

        if column == self.COLUMNS_DICT["Dup"]["index"]:
            self.duplicateWindow = DuplicateWindow(
                image_data=IMAGE_PATH_DICT[imageId], raw_id=imageId)
            if imageId not in self.duplicateRefs.keys():
                self.duplicateRefs[imageId] = self.duplicateWindow
                self.duplicateWindow.show()
            self.duplicateWindow.closeTrigger.connect(self.delete_reference)

    # Show a video upon clicking its name in the table
    def show_video(self, row, column):
        videoItem = self.videoListTable.item(row, column)
        videoId = self.videoListTable.item(row, 0).text()
        self.mainGrid.setColumnMinimumWidth(1, 800)

        # Prevents from KeyError when clicking the second column:
        if videoItem.text() == VIDEO_PATH_DICT[videoId][0]:
            videoItemPath = VIDEO_PATH_DICT[videoId][2]
            videoContent = QMediaContent(QUrl.fromLocalFile(videoItemPath))
            self.videoPlayer.setMedia(videoContent)
            self.videoPlayer.setVideoOutput(self.videoField)

            # Removes an image from screen if shown and starts video:
            self.imageField.clear()
            self.imageField.hide()
            self.videoField.show()
            self.videoPlayer.play()

    # Remove a previously added reference from a dict if a DuplicateWindow was closed
    # so it can be opened again
    def delete_reference(self, itemId):
        self.duplicateRefs.pop(itemId)

    # An amazing workaround for gif resizing procedure
    # because PyQt's native one doesn't work for some reason:
    def smooth_gif_resize(self, gif, frameWidth, frameHeight):
        gif = Pil_Image.open(gif)
        gifWidth0, gifHeight0 = gif.size

        widthRatio = frameWidth / gifWidth0
        heightRatio = frameHeight / gifHeight0

        if widthRatio >= heightRatio:
            gifWidth1 = gifWidth0 * heightRatio
            gifHeight1 = frameHeight
            return gifWidth1, gifHeight1

        gifWidth1 = frameWidth
        gifHeight1 = gifHeight0 * widthRatio
        return gifWidth1, gifHeight1