Esempio n. 1
0
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Assignment")
        self.scene = QGraphicsScene()
        self.button = QPushButton("Draw Text Boxes")
        #        self.image = QImage(self.size(), QImage.Format_RGB32)
        #        self.image.fill(Qt.black)
        self.scene.addWidget(self.button)

        self.view = QGraphicsView(self.scene)
        #        self.view.resize(800, 600)
        self.setCentralWidget(self.view)

        self.button.clicked.connect(self.buttonClicked)
        self.view.viewport().installEventFilter(self)

        self.drawing = False
        self.brushSize = 2
        self.brushColor = Qt.black
        self.lastPoint = QPoint()

    def mousePressEvent(self, event):
        #        super(MainWindow, self).mousePressEvent(event)
        if event.button() == Qt.LeftButton:
            self.drawing = True
            self.startPoint = event.pos()
            print(self.drawing)

    def mouseReleaseEvent(self, event):
        if (Qt.LeftButton & self.drawing):
            self.lastPoint = event.pos()
            print(self.startPoint)
            painter = QPainter()
            painter.setPen(
                QPen(self.brushColor, self.brushSize, Qt.SolidLine,
                     Qt.RoundCap, Qt.RoundJoin))
            painter.drawRect(QtCore.QRect(self.startPoint, self.lastPoint))
            self.update()


#    def paintEvent(self, event):
#        canvasPainter = QPainter(self)
#        canvasPainter.drawImage(self.rect())

    def buttonClicked(self):
        self.button.hide()

    def eventFilter(self, obj, event):
        if obj is self.view.viewport():
            if event.type() == QEvent.MouseButtonPress:
                print('mouse press event = ', event.pos())
            elif event.type() == QEvent.MouseButtonRelease:
                self.mouseReleaseEvent(event)
                print('mouse release event = ', event.pos())

        return QWidget.eventFilter(self, obj, event)
Esempio n. 2
0
 def createEditor(self, parent, option, index):
     if index.column() == 0:
         pushButton = QPushButton(parent)
         pushButton.hide()
         #pushButton.setIcon(QtGui.QPixmap(":/spotify/resources/icons/play_lgrey.png"), QtGui.QIcon.Normal,
         #  QtGui.QIcon.Off)
         return pushButton
     else:
         return QStyledItemDelegate.createEditor(self, parent, option,
                                                 index)
Esempio n. 3
0
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Assignment")
        self.scene = QGraphicsScene()
        self.resize(800, 600)
        self.button = QPushButton("Draw Text Boxes")

        self.scene.addWidget(self.button)

        self.view = QGraphicsView()
        self.view.setScene(self.scene)
        self.setCentralWidget(self.view)
        self.button.clicked.connect(self.buttonClicked)
        self.view.viewport().installEventFilter(self)

        self.drawing = False
        self.lastPoint = QPoint()
        self.startPoint = QPoint()

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.startPoint = self.view.mapToScene(event.pos())
            self.drawing = True

    def mouseReleaseEvent(self, event):
        if Qt.LeftButton and self.drawing:
            self.lastPoint = self.view.mapToScene(event.pos())
            self.update()

    def paintEvent(self, event):

        if self.drawing :

            self.view.le = QPlainTextEdit()
            width = QtCore.QRectF(self.startPoint, self.lastPoint).size().width()
            height = QtCore.QRectF(self.startPoint, self.lastPoint).size().height()
            x = self.startPoint.x()
            y = self.startPoint.y()
            if width > 1 and height > 1:
                self.view.le.setGeometry(x, y, width, height)
                self.qsizegrip = QSizeGrip(self.view.le)
                self.scene.addWidget(self.view.le)

    def buttonClicked(self):
        self.button.hide()

    def eventFilter(self, obj, event):
        if obj is self.view.viewport():
            if event.type() == QEvent.MouseButtonPress:
                pass
#                self.mousePressEvent(event)
            elif event.type() == QEvent.MouseButtonRelease:
                self.mouseReleaseEvent(event)
        return QWidget.eventFilter(self, obj, event)
Esempio n. 4
0
class QLabelDescription(QWidget):
	click_on=Signal(str)
	def __init__(self,label="",description="",parent=None):
		super (QLabelDescription,self).__init__(parent)
		widget=QWidget()
		HBox=QHBoxLayout()
		self.label=QLabel()
		self.labelText=label
		self.label.setText('<span style="font-size:14pt"><b>{}</b></span>'.format(label))
		self.label.setStyleSheet("border:0px;margin:0px;")
		HBox.addWidget(self.label,1)
		self.btn_edit=QPushButton()
		self.btn_edit.setToolTip(_("Edit {} file".format(label)))
		icn=QtGui.QIcon().fromTheme('document-edit')
		self.btn_edit.setIcon(icn)
		self.btn_edit.clicked.connect(self.editRepo)
		self.btn_edit.hide()
		HBox.addWidget(self.btn_edit)
		widget.setLayout(HBox)
		self.description=QLabel()
		self.description.setStyleSheet("border:3px solid silver;border-top:0px;border-right:0px;border-left:0px;margin-top:0px;")
		self.descriptionText=description
		self.description.setText('<span style="font-size:10pt; color:grey">{}</span>'.format(description))
		QBox=QVBoxLayout()
		QBox.addWidget(widget,1,Qt.AlignBottom)
		QBox.addWidget(self.description,1,Qt.AlignTop)
		self.setLayout(QBox)
		self.show()

	def setText(self,label,description=""):
		self.labelText=label
		self.label.setText('<span style="font-size:14pt"><b>{}</b></span>'.format(label))
		self.descriptionText=description
		self.description.setText('<span style="font-size:10pt; color:grey">{}</span>'.format(description))

	def text(self):
		return([self.labelText,self.descriptionText])

	def showEdit(self):
		self.btn_edit.show()

	def stateEdit(self,state):
		self.btn_edit.setEnabled(state)
		if state:
			self.btn_edit.setToolTip(_("Edit {} file".format(self.labelText)))
		else:
			self.btn_edit.setToolTip(_("Enable {} and apply to edit".format(self.labelText)))

	def editRepo(self):
		self.click_on.emit(self.labelText)
Esempio n. 5
0
class ContractKeiUI(QSplitter):
    """ 合约K线界面 """
    def __init__(self, *args, **kwargs):
        super(ContractKeiUI, self).__init__(*args, **kwargs)
        main_layout = QHBoxLayout()  # 使用主layout,让控件自适应窗口改变大小
        main_layout.setSpacing(0)

        self.variety_tree = VarietyTree(self)
        main_layout.addWidget(self.variety_tree)

        self.right_widget = QWidget(self)
        right_layout = QVBoxLayout()
        right_layout.setContentsMargins(QMargins(1, 1, 1, 1))
        opts_layout = QHBoxLayout()

        opts_layout.addWidget(QLabel("选择合约:", self))
        self.contract_combobox = QComboBox(self)
        opts_layout.addWidget(self.contract_combobox)

        self.confirm_button = QPushButton("确定", self)
        opts_layout.addWidget(self.confirm_button)

        self.tip_button = QPushButton("正在查询数据 ", self)
        self.tip_button.hide()
        opts_layout.addWidget(self.tip_button)

        opts_layout.addStretch()

        right_layout.addLayout(opts_layout)

        self.web_container = QWebEngineView(self)
        right_layout.addWidget(self.web_container)

        self.right_widget.setLayout(right_layout)
        main_layout.addWidget(self.right_widget)

        self.setStretchFactor(1, 2)
        self.setStretchFactor(2, 8)
        self.setHandleWidth(1)
        self.contract_combobox.setMinimumWidth(80)
        self.setLayout(main_layout)
        self.tip_button.setObjectName("tipButton")
        self.setStyleSheet("#tipButton{border:none;color:rgb(230,50,50);font-weight:bold}")
Esempio n. 6
0
    def add_row(self, criterion, deleteable=True):
        # The last row for this criterion
        index = self.rows_for_each_criteria[criterion]

        value_spin_box = QSpinBox()
        value_spin_box.setRange(0, 100)
        self.value_spin_boxes[criterion].append(value_spin_box)

        score_spin_box = QSpinBox()
        score_spin_box.setRange(0, 100)
        self.score_spin_boxes[criterion].append(score_spin_box)

        delete_button = QPushButton('&Delete')
        cb = partial(self.delete, criterion, index)
        delete_button.clicked.connect(cb)
        size_policy = QSizePolicy()
        size_policy.setRetainSizeWhenHidden(True)
        delete_button.setSizePolicy(size_policy)

        cb = partial(self.value_changed, criterion, index)
        value_spin_box.valueChanged.connect(cb)
        cb = partial(self.score_changed, criterion, index)
        score_spin_box.valueChanged.connect(cb)

        inner_grid = QGridLayout()
        inner_grid.addWidget(value_spin_box, index, 0)
        inner_grid.addWidget(QLabel('then score should be '), index, 1)
        inner_grid.addWidget(score_spin_box, index, 2)
        inner_grid.addWidget(delete_button, index, 3)
        if not deleteable:
            delete_button.hide()

        form = QFormLayout()
        form.addRow(QLabel('If ' + str(criterion) + ' is '), inner_grid)

        pos = self.vertical_layouts[criterion].count() - 1
        self.vertical_layouts[criterion].insertLayout(pos, form)

        # Increment the row number
        self.rows_for_each_criteria[criterion] += 1
Esempio n. 7
0
class UserBarUI(QWidget):
    def __init__(self, *args, **kwargs):
        super(UserBarUI, self).__init__(*args, **kwargs)
        layout = QHBoxLayout()
        layout.setContentsMargins(QMargins(0, 0, 5, 0))
        self.login_button = QPushButton("点击登录", self)
        self.login_button.setCursor(Qt.PointingHandCursor)
        self.login_button.setIcon(QIcon("icons/login.png"))
        self.login_button.setFixedWidth(88)
        setattr(self.login_button, "username", "")

        layout.addWidget(self.login_button)
        self.logout_button = QPushButton("退出", self)
        self.logout_button.setCursor(Qt.PointingHandCursor)
        layout.addWidget(self.logout_button)
        self.setLayout(layout)
        self.logout_button.hide()
        self.login_button.setObjectName("loginButton")
        self.logout_button.setObjectName("logoutButton")
        # loginButton::menu-indicator{image:none;}
        self.setStyleSheet(
            "#loginButton,#logoutButton{border:none;height:22px}"
            "#loginButton:hover{color:rgb(100,160,210)}"
        )
Esempio n. 8
0
class shotgun_ui(QWidget):

    e_local_export = Signal()
    e_shotgun_export = Signal(str)
    export_path = None

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setSizePolicy(QSizePolicy.MinimumExpanding,
                           QSizePolicy.MinimumExpanding)

        # Setup UI view
        v_main_box = QVBoxLayout()

        # Setup list for production handoff export option
        self.handoff_type_list = QComboBox()
        self.handoff_type_list.addItems(['Local Export', 'Shotgun Export'])
        self.handoff_type_label = QLabel('Handoff Type')
        self.handoff_type_label.setBuddy(self.handoff_type_list)
        self.handoff_type_list.currentTextChanged.connect(
            self.__on_handoff_type_changed)

        # Setup Local Export option
        self.export_layout = QHBoxLayout()
        self.export_path_button = QPushButton('Browse')
        self.export_path_button.clicked.connect(self.__browse_export_path)

        self.export_path, self.export_path_label = self.__create_line_label(
            '', 'Export Path', 200)
        self.__add_widget_to_layout(self.export_layout, self.export_path,
                                    self.export_path_button)

        # Setup Shotgun export option
        self.sg_hostname, self.sg_hostname_label = self.__create_line_label(
            'https://thomaslacroix.shotgunstudio.com', 'Shotgun URL', 350)
        self.sg_login, self.sg_login_label = self.__create_line_label(
            '*****@*****.**', 'Username', 200)

        pull = QPushButton('Export Latest')
        pull.clicked.connect(self.__pull_latest)

        self.__add_widget_to_layout(v_main_box, self.handoff_type_label,
                                    self.handoff_type_list,
                                    self.export_path_label)
        v_main_box.addLayout(self.export_layout)
        self.__add_widget_to_layout(v_main_box, self.sg_hostname_label,
                                    self.sg_hostname, self.sg_login_label,
                                    self.sg_login, pull)

        self.__update_ui_handoff_type('Local Export')
        self.setLayout(v_main_box)

    def get_shotgun_api(self) -> shotgun_api.shotgun:
        """get_shotgun_api will return the shotgun_api

        Returns:
            shotgun_api.shotgun -- Shotgun api
        """
        return self.shotgun

    def create_folders(self,
                       show_tc: str,
                       seq_tc: str,
                       seq_rev_nbr: int,
                       episode_tc: str = None) -> str:
        """create_folders will create the structure of folders from
        shows to sequence revision

        Arguments:
            show_tc {str} -- Show tracking code

            seq_tc {str} -- Sequence tracking code

            seq_rev_nbr {int} -- Sequence revision number

            episode_tc {str} -- Episode tracking code (default: {None})

        Returns:
            str -- Sequence revision path
        """
        show_path = os.path.join(self.export_path.text(), show_tc)
        self.__create_folder(show_path)
        sequence_path = os.path.join(show_path, seq_tc)
        if episode_tc is not None:
            episode_path = os.path.join(show_path, episode_tc)
            self.__create_folder(episode_path)
            sequence_path = os.path.join(episode_path, seq_tc)
        self.__create_folder(sequence_path)
        sequence_revision_path = os.path.join(sequence_path,
                                              'v{0}'.format(seq_rev_nbr))
        self.__create_folder(sequence_revision_path)
        return sequence_revision_path

    def get_shot_download_paths(self, export_path: str,
                                shot: str) -> Tuple[str, str, str]:
        """get_shot_download_paths will create folders for show, artwork and thumbnails
        and return those paths

        Arguments:
            export_path {str} -- Base export path

            shot {str} -- Shot name

        Returns:
            Tuple[str, str, str] -- show_path, artwork_path, thumb_path
        """
        show_folder_path = os.path.join(export_path, shot)
        self.__create_folder(show_folder_path)
        artwork_folder_path = os.path.join(show_folder_path, 'artwork')
        self.__create_folder(artwork_folder_path)
        thumb_folder_path = os.path.join(show_folder_path, 'thumbnail')
        self.__create_folder(thumb_folder_path)
        return show_folder_path, artwork_folder_path, thumb_folder_path

    def export_to_version(self, shots: List, sg_password: str, show_tc: str,
                          seq_rev_nbr: int, seq_tc: str,
                          fn_progress: Callable[[str], None]) -> Dict:
        """export_to_version will export to shotgun a project, a sequence, a shot and version

        Arguments:
            shots {List} -- List of shots

            sg_password {str} -- Shotgun password

            show_tc {str} -- Show tracking code

            seq_rev_nbr {int} -- Sequence revision number

            seq_tc {str} -- Sequence tracking code

            Callable[[str], None]) -- fn_progress is a progress function

        Returns:
            Dict -- Mapping of shot to quicktime info with his corresponding shotgun version
        """
        fn_progress('get or create shotgun project')
        sg_show = self.shotgun.get_project(show_tc)
        if sg_show is None:
            sg_show = self.shotgun.create_project(show_tc)
        fn_progress('get or create shotgun sequence')
        sg_seq = self.shotgun.get_sequence(sg_show, seq_tc)
        if sg_seq is None:
            sg_seq = self.shotgun.create_seq(sg_show, seq_tc)

        shot_to_file = {}
        for shot_name in shots:
            fn_progress(
                'get or create shotgun shot for shot {0}'.format(shot_name))
            sg_shot = self.shotgun.get_shot(sg_show, sg_seq, shot_name)
            if sg_shot is None:
                sg_shot = self.shotgun.create_shot(sg_show, sg_seq, shot_name)
            fn_progress(
                'get or create shotgun version for shot {0}'.format(shot_name))
            version = self.shotgun.get_version(sg_show, sg_shot)
            if version is None:
                new_version = 1
            else:
                ver = re.search('(.*)v([0-9]+)', version['code'])
                new_version = int(ver.group(2)) + 1
            version = self.shotgun.create_version(sg_show, sg_shot,
                                                  new_version)
            mov_name = '{0}_v{1}_{2}.mov'.format(seq_tc, seq_rev_nbr,
                                                 shot_name)
            shot_to_file[shot_name] = {
                'mov_name': mov_name,
                'version': version
            }
        return shot_to_file

    def init_local_export(self) -> bool:
        """init_local_export will initialise the export

        Returns:
            bool -- If the export path is valid or not
        """
        if len(self.export_path.text()) <= 0:
            self.__info('You need to select an export path')
            return False
        if os.path.exists(self.export_path.text()) is False:
            self.__info('Invalid export path')
            return False
        return True

    def init_shotgun_export(self) -> bool:
        """init_shotgun_export will init the shotgun export

        Returns:
            bool -- Can login to shotgun
        """
        if self.sg_login.text() == '' or self.sg_hostname.text() == '':
            self.__info('You need to enter your shotgun info')
            return '', False
        sg_password, ok = QInputDialog().getText(self, 'Shotgun password',
                                                 'Shotgun password:'******'', False
        self.shotgun = shotgun_api.shotgun(self.sg_hostname.text(),
                                           self.sg_login.text(), sg_password)
        return sg_password, True

    def __pull_latest(self):
        """__pull_latest will export the latest sequence revision
        """
        if self.selected_handoff_type == 'Local Export':
            if self.init_local_export():
                self.e_local_export.emit()
        else:
            sg_password, ok = self.init_shotgun_export()
            if ok:
                self.e_shotgun_export.emit(sg_password)

    def __create_line_label(self,
                            name: str,
                            label: str,
                            min_width: int = 200) -> Tuple[Dict, Dict]:
        """__create_line_label will create a line edit button and his label

        Arguments:
            name {str} -- Default value

            label {str} -- Label name

            min_width {int} -- Minium width (default: {200})

        Returns:
            Tuple[Dict, Dict] -- Line Edit, Label
        """
        line_edit = QLineEdit(name)
        line_edit.setMinimumWidth(min_width)
        label = QLabel(label)
        label.setBuddy(line_edit)
        return line_edit, label

    def __add_widget_to_layout(self, layout: Dict, *widgets: Dict):
        """__add_widget_to_layout will add all the widget to a layout
        __add_widget_to_layout(layout, widget1, widget2, widget3)

        Arguments:
            layout {Dict} -- Layout to add widget to

            widgets {*Dict} -- All the widgets to add
        """

        for w in widgets:
            layout.addWidget(w)

    def __error(self, message: str):
        """__error will show a error message with a given message

        Arguments:
            message {str} -- Message to show
        """
        err = QErrorMessage(self.parent())
        err.setWindowTitle('Flix')
        err.showMessage(message)
        err.exec_()

    def __info(self, message: str):
        """__info will show a message with a given message

        Arguments:
            message {str} -- Message to show
        """
        msgbox = QMessageBox(self.parent())
        msgbox.setWindowTitle('Flix')
        msgbox.setText(message)
        msgbox.exec_()

    def __on_handoff_type_changed(self, handoff_type: str):
        """__on_handoff_type_changed triggered when the handoff type changed

        Arguments:
            handoff_type {str} -- Handoff type from the event
        """
        self.__update_ui_handoff_type(handoff_type)

    def __browse_export_path(self):
        """__browse_export_path will create a dialog window to
        browse and set an export path
        """
        dialog = QFileDialog()
        export_p = None
        if self.export_path.text() is not '':
            if os.path.exists(self.export_path.text()):
                export_p = self.export_path.text()
        export_p = dialog.getExistingDirectory(dir=export_p)
        if len(export_p) < 1:
            return
        self.export_path.setText(export_p)

    def __update_ui_handoff_type(self, handoff_type: str):
        """__update_ui_handoff_type will update the UI depending
        of the handoff type

        Arguments:
            handoff_type {str} -- Handoff type
        """
        if handoff_type == 'Local Export':
            self.sg_hostname.hide()
            self.sg_hostname_label.hide()
            self.sg_login.hide()
            self.sg_login_label.hide()
            self.export_path_label.show()
            self.export_path.show()
            self.export_path_button.show()
        else:
            self.sg_hostname.show()
            self.sg_hostname_label.show()
            self.sg_login.show()
            self.sg_login_label.show()
            self.export_path_label.hide()
            self.export_path.hide()
            self.export_path_button.hide()
        self.selected_handoff_type = handoff_type

    def __create_folder(self, path: str):
        """__create_folder will create a folder if it does not exist

        Arguments:
            path {str} -- Path to create the folder
        """
        if not os.path.exists(path):
            os.makedirs(path)
Esempio n. 9
0
class UserSelect(QWidget):
    def __init__(self, kernel, parent=None):
        super(UserSelect, self).__init__(parent)
        self.kernel = kernel
        self.parent = parent
        self.initUI()

    def initUI(self):
        self.createElements()
        self.createLayout()
        self.createActions()
        self.hideNewUserForm()
        self.hideLoginForm()

    def createElements(self):
        self.userButtons = [
            UserTile(u, self) for u in self.kernel.getAllUsers()
        ]
        for b, u in zip(self.userButtons, self.kernel.getAllUsers()):
            b.setProfilePicture(self.kernel.getUsersDir() + u +
                                '/profile/profile_pic.png')
            b.createLayout()

        self.newUserButton = QPushButton('New User')
        self.nevermindButton = QPushButton("Nevermind")
        self.newUserNameField = QLineEdit("Username")
        self.newUserPasswordField = QLineEdit("Password")
        self.newUserPasswordField.setEchoMode(QLineEdit.Password)
        self.newUserConfirmPasswordField = QLineEdit("Confirm Password")
        self.newUserConfirmPasswordField.setEchoMode(QLineEdit.Password)
        self.submitNewUserButton = QPushButton('submit')
        self.newUserNameErrorLabel = QLabel('')
        self.newPasswordErrorLabel = QLabel('')
        self.existingUserLoginField = QLineEdit('Password')
        self.existingUserLoginField.setEchoMode(QLineEdit.Password)
        self.existingUserLoginButton = QPushButton('Login')
        self.existingUserLoginErrorLabel = QLabel('')
        self.selectedUser = None

    def createLayout(self):
        self.existingUsersLayout = QHBoxLayout()
        self.existingUsersLayout.addStretch()
        for ub in self.userButtons:
            ub.resize(100, 120)
            self.existingUsersLayout.addWidget(ub)
            self.existingUsersLayout.addStretch()

        self.formLayout = QVBoxLayout()
        self.formLayout.addStretch()
        self.formLayout.addWidget(self.newUserButton)
        self.formLayout.addWidget(self.nevermindButton)
        self.formLayout.addWidget(self.newUserNameField)
        self.formLayout.addWidget(self.newUserNameErrorLabel)
        self.formLayout.addWidget(self.newUserPasswordField)
        self.formLayout.addWidget(self.newUserConfirmPasswordField)
        self.formLayout.addWidget(self.newPasswordErrorLabel)
        self.formLayout.addWidget(self.submitNewUserButton)
        self.formLayout.addWidget(self.existingUserLoginField)
        self.formLayout.addWidget(self.existingUserLoginErrorLabel)
        self.formLayout.addWidget(self.existingUserLoginButton)
        self.formLayout.addStretch()

        self.lowLayout = QHBoxLayout()
        self.lowLayout.addStretch()
        self.lowLayout.addLayout(self.formLayout)
        self.lowLayout.addStretch()

        self.layout = QVBoxLayout(self)
        self.layout.addStretch()
        self.layout.addLayout(self.existingUsersLayout)
        self.layout.addLayout(self.lowLayout)
        self.layout.addStretch()

    def createActions(self):
        self.newUserButton.clicked.connect(self.revealNewUserForm)
        self.nevermindButton.clicked.connect(self.hideNewUserForm)
        self.submitNewUserButton.clicked.connect(self.submitNewUserRequest)
        self.existingUserLoginButton.clicked.connect(self.login)
        for btn in self.userButtons:
            btn.nameButton.clicked.connect(
                lambda: self.revealLoginForm(btn.nameButton.text()))

    def revealNewUserForm(self):
        self.hideLoginForm()
        self.newUserButton.hide()
        self.newUserNameField.show()
        self.newUserPasswordField.show()
        self.newUserConfirmPasswordField.show()
        self.submitNewUserButton.show()
        self.nevermindButton.show()

    def hideNewUserForm(self):
        self.newUserButton.show()
        self.newUserNameErrorLabel.hide()
        self.newPasswordErrorLabel.hide()
        self.newUserNameField.hide()
        self.newUserPasswordField.hide()
        self.newUserConfirmPasswordField.hide()
        self.submitNewUserButton.hide()
        self.nevermindButton.hide()

    def revealLoginForm(self, user):
        self.hideNewUserForm()
        self.selectedUser = user
        self.existingUserLoginButton.show()
        self.existingUserLoginErrorLabel.show()
        self.existingUserLoginField.show()

    def hideLoginForm(self):
        self.selectedUser = None
        self.existingUserLoginButton.hide()
        self.existingUserLoginErrorLabel.hide()
        self.existingUserLoginField.hide()

    def submitNewUserRequest(self):
        userName = self.newUserNameField.text()
        pwd = self.newUserPasswordField.text()
        conf_pwd = self.newUserConfirmPasswordField.text()

        err_msg = ''
        if pwd != conf_pwd:
            err_msg = 'Error: passwords do not match'
            self.newPasswordErrorLabel.setText(err_msg)
            self.newPasswordErrorLabel.show()
        else:
            self.newPasswordErrorLabel.hide()

        if self.kernel.userExists(userName):
            err_msg = 'Error: Username is already taken. Choose something else'
            self.newUserNameErrorLabel.setText(err_msg)
            self.newUserNameErrorLabel.show()
        else:
            self.newUserNameErrorLabel.hide()

        if err_msg != '':
            return

        if self.kernel.addUser(userName, pwd):
            self.parent.loadApplication()
        else:
            err = "Error: User Creation failed.\nPlease use your Robinhood Credentials"
            self.newPasswordErrorLabel.setText(err)
            self.newPasswordErrorLabel.show()

    def login(self):
        assert (self.selectedUser != None)
        pwd = self.existingUserLoginField.text()
        if not self.kernel.switchUser(self.selectedUser, pwd):
            self.existingUserLoginErrorLabel.setText(err)
            self.existingUserLoginErrorLabel.show()
        else:
            self.parent.loadApplication()
Esempio n. 10
0
class QDataViewer(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        # Layout Init.
        self.language = 'ud'
        if len(sys.argv)>1:
            self.language = sys.argv[1]
        self.setGeometry(650, 300, 600, 600)
        self.setWindowTitle('Data Viewer')
        self.uploadButton = QPushButton('Load Conll File', self)
        self.sentence_id = 0
        self.column_number = 10
        self.columns = ["ID", "FORM", "LEMMA", "UPOS", "XPOS", "FEATS", "HEAD", "DEPREL", "DEPS", "MISC"]
        self.current_dict = {}
        self.load_finished = True
        self.first_time = True
        self.session_start = True
        self.map_col = {0:"ID", 1:"FORM", 2:"LEMMA", 3:"UPOS", 4:"XPOS", 5:"FEATS", 6:"HEAD", 7:"DEPREL", 8:"DEPS", 9:"MISC", 10:"Abbr", 11:"Animacy", 12:"Aspect", 13:"Case",
                        14:"Clusivity", 15:"Definite", 16:"Degree", 17:"Echo", 18:"Evident", 19:"Foreign", 20:"Gender", 21:"Mood", 22:"NounClass", 23:"Number", 24:"Number[psor]",
                        25:"NumType", 26:"Person", 27:"Person[psor]", 28:"Polarity", 29:"Polite", 30:"Poss", 31:"PronType", 32:"Reflex", 33:"Register", 34:"Tense", 35:"VerbForm",
                        36:"Voice"}

        self.doc = None
        
        self.vBoxLayout = QVBoxLayout()
        self.vBoxLayout.addWidget(self.uploadButton)
        self.setLayout(self.vBoxLayout)
        
        # Signal Init.
        self.connect(self.uploadButton, QtCore.SIGNAL('clicked()'), self.open)

    def open(self):
        filename = QFileDialog.getOpenFileName(self, 'Open File', '.')[0]
        self.notename = "notes-"+filename.split("/")[-1].split(".")[0]+".txt"
        self.uploadButton.hide()
        print(filename)
        self.doc = Doc(filename)

        if not os.path.exists(self.notename):
            open(self.notename, "w").close()

        self.construct()

    def writeNotes(self):
        if self.qTextEdit2.toPlainText() != "Write your note here...":
            if self.qTextEdit2.toPlainText() == "":
                if str(self.sentence_id) in self.noteDictionary:
                    del self.noteDictionary[str(self.sentence_id)]
            else:
                self.noteDictionary[str(self.sentence_id)] = self.qTextEdit2.toPlainText().rstrip().replace("\r\n", " ").replace("\n", " ").replace("\r", " ")
            noteTxt = open(self.notename, "w")
            for noteKey in sorted(self.noteDictionary.keys()):
                noteTxt.write(noteKey+" --- "+self.noteDictionary[noteKey]+"\n")
            noteTxt.close()

    def go_prev(self):
        self.first_time = True
        self.writeNotes()

        if self.sentence_id>0:
            self.sentence_id-=1   
        self.update_table()
        self.session_start = True
        self.update_html()
        self.check_errors()

        self.qTextEdit.setText(str(self.sentence_id))
        self.first_time = False
    
    def go_next(self):
        self.first_time = True
        self.writeNotes()

        if self.sentence_id<len(self.doc.sentences)-1:
            self.sentence_id+=1
        self.update_table()
        self.session_start = True
        self.update_html()
        self.check_errors()

        self.qTextEdit.setText(str(self.sentence_id))
        self.first_time = False
    
    def go(self):
        self.doc.write()
        self.first_time = True
        self.writeNotes()

        try:
            self.sentence_id = int(self.qTextEdit.toPlainText())
            self.update_table()
            self.session_start = True
            self.update_html()
            self.check_errors()
        except Exception as e:
            print(e)
        
        self.qTextEdit.setText(str(self.sentence_id))
        self.first_time = False


    def reset(self):
        if not self.first_time:
            self.first_time = True
            self.sentence = copy.deepcopy(self.sentence_backup)
            self.doc.sentences[self.sentence_id] = copy.deepcopy(self.sentence_backup)
            self.session_start = True
            self.doc.write()
            self.update_table()
            self.update_html()
            self.check_errors()

            self.first_time = False


    def construct(self):
        self.hBoxLayout = QHBoxLayout()
        self.prevButton = QPushButton("Prev", self)
        self.prevButton.setShortcut("Alt+O")

        self.resetButton = QPushButton("Reset", self)
        self.resetButton.setShortcut("Alt+R")

        self.qTextEditAddRow = QTextEdit()
        self.qTextEditAddRow.setFixedHeight(20)
        self.qTextEditAddRow.setFixedWidth(60)

        self.qTextEditDeleteRow = QTextEdit()
        self.qTextEditDeleteRow.setFixedHeight(20)
        self.qTextEditDeleteRow.setFixedWidth(60)

        self.qTextEdit = QTextEdit()
        self.qTextEdit.setFixedHeight(20)
        self.qTextEdit.setFixedWidth(60)

        self.qTextEdit2 = QTextEdit()
        self.qTextEdit2.setFixedHeight(20)
        self.qTextEdit2.setFixedWidth(500)

        self.shortcutText=QShortcut(QtGui.QKeySequence("Alt+M"), self)
        self.shortcutText.activated.connect(self.qTextEdit2.setFocus)

        self.goButton = QPushButton("Go", self)
        self.goButton.setShortcut("Alt+G")
        self.nextButton = QPushButton("Next", self)
        self.nextButton.setShortcut("Alt+P")
        self.addRowButton = QPushButton("Add Row", self)
        self.deleteRowButton = QPushButton("Delete Row", self)
        self.hBoxLayout.addWidget(self.prevButton)
        self.hBoxLayout.addStretch()
        self.hBoxLayout.addWidget(self.resetButton)
        self.hBoxLayout.addStretch()
        self.hBoxLayout.addWidget(self.qTextEditAddRow)
        self.hBoxLayout.addWidget(self.addRowButton)
        self.hBoxLayout.addStretch()
        self.hBoxLayout.addWidget(self.qTextEditDeleteRow)
        self.hBoxLayout.addWidget(self.deleteRowButton)
        self.hBoxLayout.addStretch()
        self.hBoxLayout.addWidget(self.qTextEdit)
        self.hBoxLayout.addWidget(self.goButton)

        self.hBoxLayout.addStretch()
        self.hBoxLayout.addWidget(self.qTextEdit2)

        self.hBoxLayout.addStretch()
        self.hBoxLayout.addWidget(self.nextButton)
        self.vBoxLayout.addLayout(self.hBoxLayout)

        self.chBoxLayout = QHBoxLayout()
        self.chBoxLayout.addStretch()
        cb_ids = ["ID", "FORM", "LEMMA", "UPOS", "XPOS", "FEATS", "HEAD", "DEPREL", "DEPS", "MISC"]
        cb_ids2 = ["Abbr", "Animacy", "Aspect", "Case", "Clusivity", "Definite", "Degree", "Echo", "Evident", "Foreign", "Gender", "Mood", "NounClass", "Number"]
        cb_ids3 = ["Number[psor]", "NumType", "Person", "Person[psor]", "Polarity", "Polite", "Poss", "PronType", "Reflex", "Register", "Tense", "VerbForm", "Voice"]
        for cb_id in cb_ids:
            cb = QCheckBox(cb_id)
            cb.setChecked(True)
            cb.stateChanged.connect(self.cb_change)
            self.chBoxLayout.addWidget(cb)
        
        self.chBoxLayout.addStretch()
        self.vBoxLayout.addLayout(self.chBoxLayout)

        self.chBoxLayout_2 = QHBoxLayout()
        self.chBoxLayout_2.addStretch()
        for cb_id in cb_ids2:
            cb = QCheckBox(cb_id)
            cb.setChecked(False)
            cb.stateChanged.connect(self.cb_change)
            self.chBoxLayout_2.addWidget(cb)

        self.chBoxLayout_2.addStretch()
        self.vBoxLayout.addLayout(self.chBoxLayout_2)

        self.chBoxLayout_3 = QHBoxLayout()
        self.chBoxLayout_3.addStretch()
        for cb_id in cb_ids3:
            cb = QCheckBox(cb_id)
            cb.setChecked(False)
            cb.stateChanged.connect(self.cb_change)
            self.chBoxLayout_3.addWidget(cb)

        self.chBoxLayout_3.addStretch()
        self.vBoxLayout.addLayout(self.chBoxLayout_3)

        self.qTextEdit.setText(str(self.sentence_id))

        self.noteDictionary = {}
        noteFile = open(self.notename, "r")
        for note in noteFile:
            noteSplitted = note.split(" --- ")
            noteID = noteSplitted[0]
            noteContent = noteSplitted[1].rstrip()
            self.noteDictionary[noteID] = noteContent
        noteFile.close()

        self.connect(self.prevButton, QtCore.SIGNAL('clicked()'), self.go_prev)
        self.connect(self.resetButton, QtCore.SIGNAL('clicked()'), self.reset)
        self.connect(self.goButton, QtCore.SIGNAL('clicked()'), self.go)
        self.connect(self.nextButton, QtCore.SIGNAL('clicked()'), self.go_next)
        self.connect(self.addRowButton, QtCore.SIGNAL('clicked()'), self.add_row)
        self.connect(self.deleteRowButton, QtCore.SIGNAL('clicked()'), self.delete_row)

        # create table here
        self.tableWidget = QTableWidget(self)

        self.tableWidget.itemChanged.connect(self.handle_change)

        self.connect(self.tableWidget.verticalHeader(), QtCore.SIGNAL("sectionClicked(int)"), self.agg)

        self.qTextEditError = QTextEdit()
        self.qTextEditError.setReadOnly(True)

        self.splitter = QSplitter(Qt.Vertical)
        self.splitter.addWidget(self.tableWidget)
        self.splitter.addWidget(self.qTextEditError)
        self.vBoxLayout.addWidget(self.splitter)

        self.webView = QWebEngineView()

        self.update_table()
        self.update_html()
        self.check_errors()

        self.splitter2 = QSplitter(Qt.Vertical)
        self.splitter2.addWidget(self.splitter)
        self.splitter2.addWidget(self.webView)
        self.vBoxLayout.addWidget(self.splitter2)

        self.webView.loadFinished.connect(self.finito)

        self.first_time = False
    
    def finito(self):
        self.load_finished = True

    def add_row(self):

        if "-" not in self.qTextEditAddRow.toPlainText():

            word_id = int(self.qTextEditAddRow.toPlainText())
            possible_move = True
            new_sentence_words = []

            for word in self.sentence.words:
                if word.unitword:
                    x1 = int(word.id.split("-")[0])
                    x2 = int(word.id.split("-")[1])
                    if word_id == x1 or word_id == x2:
                        possible_move = False

            if possible_move:
                for word in self.sentence.words:
                    new_word = copy.deepcopy(word)

                    if new_word.head != "_" and int(new_word.head) >= word_id:
                        new_word.head = str(int(new_word.head) + 1)

                    if new_word.unitword:
                        new_word_id = int(new_word.id.split("-")[0])
                    else:
                        new_word_id = int(new_word.id)

                    if new_word_id < word_id:
                        new_sentence_words.append(new_word)
                    elif new_word_id == word_id:
                        if new_word.unitword:
                            x1 = int(new_word.id.split("-")[0])
                            x2 = int(new_word.id.split("-")[1])
                            w = Word("\t".join(
                                [str(x1), new_word.form, "_", "_", "_", "_", new_word.head, "_", "_", "_"]), self.sentence.sent_address)
                            new_word.id = str(x1 + 1) + "-" + str(x2 + 1)
                        else:
                            w = Word("\t".join(
                                [new_word.id, new_word.form, "_", "_", "_", "_", new_word.head, "_", "_", "_"]), self.sentence.sent_address)
                            new_word.id = str(int(new_word.id) + 1)
                        new_sentence_words.append(w)
                        new_sentence_words.append(new_word)
                    elif new_word_id > word_id:
                        if new_word.unitword:
                            x1 = int(new_word.id.split("-")[0])
                            x2 = int(new_word.id.split("-")[1])
                            new_word.id = str(x1 + 1) + "-" + str(x2 + 1)
                        else:
                            new_word.id = str(int(new_word.id) + 1)
                        new_sentence_words.append(new_word)

                self.sentence.words = copy.deepcopy(new_sentence_words)
                self.first_time = True
                self.update_table()
                self.update_html()
                self.first_time = False

    def delete_row(self):

        if "-" not in self.qTextEditDeleteRow.toPlainText():

            word_id = int(self.qTextEditDeleteRow.toPlainText())
            possible_move = True
            new_sentence_words = []

            for word in self.sentence.words:
                if word.unitword:
                    x1 = int(word.id.split("-")[0])
                    x2 = int(word.id.split("-")[1])
                    if word_id == x1 or word_id == x2:
                        possible_move = False
                if not word.head == "_":
                    if int(word.head) == word_id:
                        possible_move = False

            if possible_move:
                for word in self.sentence.words:
                    new_word = copy.deepcopy(word)

                    if new_word.head != "_" and int(new_word.head) >= word_id:
                        new_word.head = str(int(new_word.head) - 1)

                    if new_word.unitword:
                        new_word_id = int(new_word.id.split("-")[0])
                    else:
                        new_word_id = int(new_word.id)

                    if new_word_id < word_id:
                        new_sentence_words.append(new_word)
                    elif new_word_id > word_id:
                        if new_word.unitword:
                            x1 = int(new_word.id.split("-")[0])
                            x2 = int(new_word.id.split("-")[1])
                            new_word.id = str(x1 - 1) + "-" + str(x2 - 1)
                        else:
                            new_word.id = str(int(new_word.id) - 1)
                        new_sentence_words.append(new_word)

                self.sentence.words = copy.deepcopy(new_sentence_words)
                self.first_time = True
                self.update_table()
                self.update_html()
                self.first_time = False

    def agg(self, x):
        
        if self.sentence.words[x].unitword:#remove two-words thing into one
            limit = int(self.sentence.words[x].id.split("-")[0])
            self.sentence.words[x].head = self.sentence.words[x+1].head
            self.sentence.words[x].lemma = self.sentence.words[x+1].lemma
            self.sentence.words[x].upos = self.sentence.words[x+1].upos
            self.sentence.words[x].xpos = self.sentence.words[x+1].xpos
            self.sentence.words[x].feats = self.sentence.words[x+1].feats
            self.sentence.words[x].deprel = self.sentence.words[x+1].deprel
            self.sentence.words[x].deps = self.sentence.words[x+1].deps
            self.sentence.words[x].misc = self.sentence.words[x+1].misc
            self.sentence.words[x].id = str(limit)
            self.sentence.words[x].unitword = False
            del self.sentence.words[x+1]
            del self.sentence.words[x+1]

            for word in self.sentence.words:
                if word.unitword:
                    first_word_id = int(word.id.split("-")[0])
                    if first_word_id>limit:
                        word.id = str(first_word_id-1)+"-"+str(first_word_id)
                else:
                    if int(word.id) > limit:
                        word.id = str(int(word.id)-1)
                
                if word.head != "_" and int(word.head) > limit:
                    word.head = str(int(word.head)-1)
            self.first_time = True
            self.update_table()
            self.update_html()
            self.first_time = False
        
        else:#add two-elements below
            base_word = self.sentence.words[x]
            limit = int(base_word.id)

            for word in self.sentence.words:
                if word.unitword:
                    first_word_id = int(word.id.split("-")[0])
                    if first_word_id>limit:
                        word.id = str(first_word_id+1)+"-"+str(first_word_id+2)
                else:
                    if int(word.id) > limit:
                        word.id = str(int(word.id)+1)
                
                if word.head != "_" and int(word.head) > limit:
                    word.head = str(int(word.head)+1)


            w1 = Word("\t".join([str(limit), base_word.form, base_word.lemma, base_word.upos, base_word.xpos, base_word.feats, base_word.head, base_word.deprel, base_word.deps, "_"]), self.sentence.sent_address)
            w2 = Word("\t".join([str(limit+1), base_word.form, base_word.lemma, base_word.upos, base_word.xpos, base_word.feats, str(limit), base_word.deprel, base_word.deps, "_"]), self.sentence.sent_address)
            self.sentence.words = self.sentence.words[:x+1]+[w1, w2]+self.sentence.words[x+1:]
            base_word.id = str(limit)+"-"+str(limit+1)
            base_word.lemma = "_"
            base_word.upos = "_"
            base_word.xpos = "_"
            base_word.feats = "_"
            base_word.head = "_"
            base_word.deprel = "_"
            base_word.deps = "_"
            base_word.unitword = True
            self.first_time = True
            self.update_table()
            self.update_html()
            self.first_time = False

    
    def update_table(self):
        if str(self.sentence_id) in self.noteDictionary:
            self.qTextEdit2.setText(self.noteDictionary[str(self.sentence_id)])
        else:
            self.qTextEdit2.setText("Write your note here...")

        self.sentence = self.doc.sentences[self.sentence_id]

        self.tableWidget.setRowCount(len(self.sentence.words))
        self.tableWidget.setColumnCount(self.column_number)
        self.tableWidget.setHorizontalHeaderLabels(self.columns)

        for enum, word in enumerate(self.sentence.words):
            if word.unitword:
                self.tableWidget.setVerticalHeaderItem(enum, QTableWidgetItem("-"))
            else:
                self.tableWidget.setVerticalHeaderItem(enum, QTableWidgetItem("+"))

            dict_feat = {}
            uni_feats = re.split('\|', word.feats)
            if uni_feats[0] != "_":
                for uni_feat in uni_feats:
                    uf = re.split('\=', uni_feat)
                    dict_feat[uf[0]]=uf[1]

            for i in range(self.column_number):
                if self.columns[i]=="ID":
                    self.tableWidget.setItem(enum, i, QTableWidgetItem(word.id))
                elif self.columns[i]=="FORM":
                    self.tableWidget.setItem(enum, i, QTableWidgetItem(word.form))
                elif self.columns[i]=="LEMMA":
                    self.tableWidget.setItem(enum, i, QTableWidgetItem(word.lemma))
                elif self.columns[i]=="UPOS":
                    self.tableWidget.setItem(enum, i, QTableWidgetItem(word.upos))
                elif self.columns[i]=="XPOS":
                    self.tableWidget.setItem(enum, i, QTableWidgetItem(word.xpos))
                elif self.columns[i]=="FEATS":
                    self.tableWidget.setItem(enum, i, QTableWidgetItem(word.feats))
                elif self.columns[i]=="HEAD":
                    self.tableWidget.setItem(enum, i, QTableWidgetItem(word.head))
                elif self.columns[i]=="DEPREL":
                    self.tableWidget.setItem(enum, i, QTableWidgetItem(word.deprel))
                elif self.columns[i]=="DEPS":
                    self.tableWidget.setItem(enum, i, QTableWidgetItem(word.deps))
                elif self.columns[i]=="MISC":
                    self.tableWidget.setItem(enum, i, QTableWidgetItem(word.misc))
                else:
                    if self.columns[i] in dict_feat:
                        self.tableWidget.setItem(enum, i, QTableWidgetItem(dict_feat[self.columns[i]]))
                    else:
                        self.tableWidget.setItem(enum, i, QTableWidgetItem("_"))
            
        self.tableWidget.resizeColumnsToContents()

    def check_errors(self):
        index = ""
        for w in self.sentence.words:
            index += w.form + "(" + w.id + ") "
        index += "\n"
        error_list = get_errors(self.sentence.get_raw(), self.sentence.sent_id, self.language)
        if len(error_list)>0:
            error_raw_string = 'ERRORS:\n'
            for error in error_list:
                error_raw_string+=error+'\n'
            self.qTextEditError.setText(index + error_raw_string)
        else:
            self.qTextEditError.setText(index)
    def update_html(self):
        if not self.load_finished: #If the js function not loaded an image onto app it removes browser
            print("Load error!")
            self.splitter2.deleteLater()
            self.webView = QWebEngineView()
            self.splitter2 = QSplitter(Qt.Vertical)
            self.splitter2.addWidget(self.splitter)
            self.splitter2.addWidget(self.webView)
            self.vBoxLayout.addWidget(self.splitter2)
            self.webView.loadFinished.connect(self.finito)

        self.sentence = self.doc.sentences[self.sentence_id]
        if self.session_start:
            self.sentence_backup = copy.deepcopy(self.doc.sentences[self.sentence_id])
            self.session_start = False

        html = process_document(self.sentence)
        self.webView.setHtml(html)
        self.load_finished = False


    def cb_change(self):
        self.column_number = 0
        self.columns = []
        self.map_col = {}
        x = 0
        for i in range(self.chBoxLayout.count()):
            if isinstance(self.chBoxLayout.itemAt(i), QWidgetItem):
                wid = self.chBoxLayout.itemAt(i).widget()
                if wid.isChecked():
                    self.columns.append(wid.text())
                    self.column_number += 1
                    self.map_col[x] = wid.text()
                    x+=1
        for i in range(self.chBoxLayout_2.count()):
            if isinstance(self.chBoxLayout_2.itemAt(i), QWidgetItem):
                wid = self.chBoxLayout_2.itemAt(i).widget()
                if wid.isChecked():
                    self.columns.append(wid.text())
                    self.column_number += 1
                    self.map_col[x] = wid.text()
                    x+=1
        for i in range(self.chBoxLayout_3.count()):
            if isinstance(self.chBoxLayout_3.itemAt(i), QWidgetItem):
                wid = self.chBoxLayout_3.itemAt(i).widget()
                if wid.isChecked():
                    self.columns.append(wid.text())
                    self.column_number += 1
                    self.map_col[x] = wid.text()
                    x+=1
                    
        self.first_time = True
        self.update_table()
        self.first_time = False
                

    def handle_change(self, item):
        col = self.map_col[item.column()]
        text = item.text()
        #print(text)
        isSpace = False
        if text == "":
            if col!="ID" and col!="FORM" and col!="LEMMA" and col!="UPOS" and col!="XPOS" and col!="HEAD" and col!="DEPREL" and col!="DEPS" and col!="MISC":
                isSpace = True
            text = "_"
        row = item.row()
        self.sentence = self.doc.sentences[self.sentence_id]
        
        if col=="ID":
            self.sentence.words[row].id = text
        elif col=="FORM":
            self.sentence.words[row].form = text
        elif col=="LEMMA":
            self.sentence.words[row].lemma = text
        elif col=="UPOS":
            self.sentence.words[row].upos = text.upper()
        elif col=="XPOS":
            self.sentence.words[row].xpos = text
        elif col=="FEATS":
            self.sentence.words[row].feats = text
        elif col=="HEAD":
            self.sentence.words[row].head = text
        elif col=="DEPREL":
            self.sentence.words[row].deprel = text
        elif col=="DEPS":
            self.sentence.words[row].deps = text
        elif col=="MISC":
            self.sentence.words[row].misc = text
        else:
            cur_col = col
            if col=="Number[psor]":
                cur_col = "Number\[psor\]"
            if col=="Person[psor]":
                cur_col = "Person\[psor\]"
            if re.search(cur_col+'=\w*', self.sentence.words[row].feats) is None:
                if text!="_":
                    if self.sentence.words[row].feats=="_":
                        self.sentence.words[row].feats = col+"="+text
                    else:
                        sorted_feats = re.split('\|', self.sentence.words[row].feats)
                        match_col=""
                        match_val=""
                        for sorted_feat in sorted_feats:
                                sf = re.split('\=', sorted_feat)
                                if sf[0].lower()<col.lower():
                                    match_col = sf[0]
                                    match_val = sf[1]
                        if match_col=="":
                            self.sentence.words[row].feats = col+"="+text+"|"+self.sentence.words[row].feats
                        else:
                            cur_match_col=match_col
                            if match_col == "Number[psor]":
                                cur_match_col = "Number\[psor\]"
                            if match_col == "Person[psor]":
                                cur_match_col = "Person\[psor\]"
                            self.sentence.words[row].feats = re.sub(cur_match_col+'='+match_val, match_col+'='+match_val+"|"+col+"="+text, self.sentence.words[row].feats)
            elif isSpace:
                old_feats = re.split('\|', self.sentence.words[row].feats)
                new_feats = []
                for old_feat in old_feats:
                    if old_feat.split("=")[0]!=cur_col:
                        new_feats.append(old_feat)
                self.sentence.words[row].feats =  "|".join(new_feats)
            else:
                self.sentence.words[row].feats = re.sub(cur_col+'=\w*', col+"="+text, self.sentence.words[row].feats)

        if not self.first_time:
            self.doc.write()
            self.first_time = True
            self.writeNotes()

            self.update_table()
            self.update_html()
            self.check_errors()

            self.first_time = False
Esempio n. 11
0
File: Log.py Progetto: zsh2020/Ryven
class Log(QWidget):
    def __init__(self, sender, title=''):
        super(Log, self).__init__()

        self.main_layout = QVBoxLayout()
        self.header_layout = QHBoxLayout()

        title_label = QLabel(title)
        title_label.setFont(QFont('Poppins', 13))
        self.header_layout.addWidget(title_label)

        self.remove_button = QPushButton('x')
        self.remove_button.clicked.connect(self.remove_clicked)
        self.header_layout.addWidget(self.remove_button)
        self.remove_button.hide()

        holder_label = QLabel(shorten(str(sender), 76))
        holder_label.setWordWrap(True)
        self.log_view = QPlainTextEdit()
        self.log_view.setReadOnly(True)

        self.main_layout.addLayout(self.header_layout)
        self.main_layout.addWidget(holder_label)
        self.main_layout.addWidget(self.log_view)

        self.setLayout(self.main_layout)

        self.enabled_style_sheet = '''
            QLabel {
                border: None;
            }
            QWidget {
                color: #e9f4fb;
            }
        '''
        self.disabled_style_sheet = '''
            QLabel {
                border: None;
            }
            QWidget {
                color: #e9f4fb;
            }
            QPlainTextEdit {
                background: black; 
                color: grey;
            }
        '''
        self.setStyleSheet(self.enabled_style_sheet)

    def log(self, *args):
        s = ''
        for arg in args:
            s += ' ' + str(arg)
        self.log_view.appendPlainText('>  ' + s)

    def clear(self):
        self.log_view.clear()

    def disable(self):
        self.remove_button.show()
        self.setStyleSheet(self.disabled_style_sheet)

    def enable(self):
        self.remove_button.hide()
        self.setStyleSheet(self.enabled_style_sheet)
        self.show()

    def remove_clicked(self):
        self.hide()
Esempio n. 12
0
class MainConsole(QWidget):
    """Complete console interpreter.
    One instance will be created at the end of this file, when being imported in Ryven.py."""

    def __init__(
            self,
            context=locals(),       # context for interpreter
            history: int = 100,     # max lines in history buffer
            blockcount: int = 5000  # max lines in output buffer
    ):

        super(MainConsole, self).__init__()

        # CREATE UI

        self.content_layout = QGridLayout(self)
        self.content_layout.setContentsMargins(0, 0, 0, 0)
        self.content_layout.setSpacing(0)

        # reset scope button
        self.reset_scope_button = QPushButton('reset console scope')
        self.reset_scope_button.clicked.connect(self.reset_scope_clicked)
        self.content_layout.addWidget(self.reset_scope_button, 0, 0, 1, 2)
        self.reset_scope_button.hide()

        # display for output
        self.out_display = ConsoleDisplay(blockcount, self)
        self.content_layout.addWidget(self.out_display, 1, 0, 1, 2)

        # colors to differentiate input, output and stderr
        self.inpfmt = self.out_display.currentCharFormat()
        self.inpfmt.setForeground(QBrush(QColor('white')))
        self.outfmt = QTextCharFormat(self.inpfmt)
        self.outfmt.setForeground(QBrush(QColor('#A9D5EF')))
        self.errfmt = QTextCharFormat(self.inpfmt)
        self.errfmt.setForeground(QBrush(QColor('#B55730')))

        # display input prompt left besides input edit
        self.prompt_label = QLabel('> ', self)
        self.prompt_label.setFixedWidth(15)
        self.content_layout.addWidget(self.prompt_label, 2, 0)

        # command line
        self.inpedit = LineEdit(max_history=history)
        self.inpedit.returned.connect(self.push)
        self.content_layout.addWidget(self.inpedit, 2, 1)


        self.interp = None
        self.reset_interpreter()

        self.buffer = []
        self.num_added_object_contexts = 0


    def setprompt(self, text: str):
        self.prompt_label.setText(text)

    def reset_scope_clicked(self):
        self.reset_interpreter()

    def add_obj_context(self, context_obj):
        """adds the new context to the current context by initializing a new interpreter with both"""

        old_context = {} if self.interp is None else self.interp.locals
        name = 'obj' + (str(self.num_added_object_contexts+1) if self.num_added_object_contexts > 0 else '')
        new_context = {name: context_obj}
        context = {**old_context, **new_context}  # merge dicts
        self.interp = code.InteractiveConsole(context)
        print('added as ' + name)

        self.num_added_object_contexts += 1
        self.reset_scope_button.show()

    def reset_interpreter(self):
        """Initializes a new plain interpreter"""

        context = locals()
        self.num_added_object_contexts = 0
        self.reset_scope_button.hide()
        self.interp = code.InteractiveConsole(context)

    def push(self, commands: str) -> None:
        """execute entered command which may span multiple lines when code was pasted"""

        if commands == 'clear':
            self.out_display.clear()
        else:
            lines = commands.split('\n')  # usually just one entry

            # clean and print commands
            for line in lines:

                # remove '> '-and '. ' prefixes which may remain from copy&paste
                if re.match('^[\>\.] ', line):
                    line = line[2:]

                # print input
                self.writeoutput(self.prompt_label.text() + line, self.inpfmt)

                # prepare for multi-line input
                self.setprompt('. ')
                self.buffer.append(line)

            # merge commands
            source = '\n'.join(self.buffer)
            more = self.interp.runsource(source, '<console>')

            if not more:  # no more input required
                self.setprompt('> ')
                self.buffer = []  # reset buffer

    def write(self, line: str) -> None:
        """capture stdout and print to outdisplay"""
        if len(line) != 1 or ord(line[0]) != 10:
            self.writeoutput(line.rstrip(), self.outfmt)

    def errorwrite(self, line: str) -> None:
        """capture stderr and print to outdisplay"""
        self.writeoutput(line, self.errfmt)

    def writeoutput(self, line: str, fmt: QTextCharFormat = None) -> None:
        """prints to outdisplay"""
        if fmt is not None:
            self.out_display.setCurrentCharFormat(fmt)
        self.out_display.appendPlainText(line.rstrip())
Esempio n. 13
0
class Resultat(QDialog):
    """ This class is used to create the window to search new products """
    def __init__(self, mydb, parent=None):
        super(Resultat, self).__init__(parent)

        self.setWindowTitle("Project 5 : Openfoodfacts")
        self.mydb = mydb
        self.text_cat = QtWidgets.QLabel(
            "Select a category below")
        self.mycombo_cat = QtWidgets.QComboBox()
        self.text_prod = QtWidgets.QLabel("Then select a product")
        self.mycombo_prod = QtWidgets.QComboBox()
        self.text_select_subs = QtWidgets.QLabel("Choose one of the \
substitution products")
        self.mytable = QtWidgets.QTableWidget(1, 4)
        self.mytable.setHorizontalHeaderLabels(
            ("Selected product;Nutriscore;Stores;Link to website").split(";"))
        header = self.mytable.horizontalHeader()
        header.setSectionResizeMode(0, QtWidgets.QHeaderView.Stretch)
        header.setSectionResizeMode(1, QtWidgets.QHeaderView.Stretch)
        header.setSectionResizeMode(2, QtWidgets.QHeaderView.Stretch)
        header.setSectionResizeMode(3, QtWidgets.QHeaderView.Stretch)
        self.subs_table = QtWidgets.QTableWidget(1, 4)
        self.subs_table.setHorizontalHeaderLabels(
            ("Substitution product;Nutriscore;\
Stores;Link to website").split(";"))
        header2 = self.mytable.horizontalHeader()
        header2.setSectionResizeMode(0, QtWidgets.QHeaderView.Stretch)
        header2.setSectionResizeMode(1, QtWidgets.QHeaderView.Stretch)
        header2.setSectionResizeMode(2, QtWidgets.QHeaderView.Stretch)
        header2.setSectionResizeMode(3, QtWidgets.QHeaderView.Stretch)
        header2.setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeToContents)
        header2.setSectionResizeMode(1, QtWidgets.QHeaderView.ResizeToContents)
        header2.setSectionResizeMode(2, QtWidgets.QHeaderView.ResizeToContents)
        header2.setSectionResizeMode(3, QtWidgets.QHeaderView.ResizeToContents)
        self.search_button = QPushButton("Search a substitution product")
        self.save_button = QPushButton("Save result")
        self.save_button.hide()

        self.mycursor = self.mydb.cursor()
        # Getting all product categories
        sql_query_cat = "SELECT * FROM Category"
        self.mycursor.execute(sql_query_cat)
        result = self.mycursor.fetchall()
        for category in result:
            category_id = category[0]
            category_name = category[1]
            self.mycombo_cat.addItem("{} - {}".format(category_id,
                                                      (category_name)))
        self.first_cat = result[0][0]
        self.layout = QVBoxLayout()
        self.layout.addWidget(self.text_cat)
        self.layout.addWidget(self.mycombo_cat)
        self.layout.addWidget(self.text_prod)
        self.layout.addWidget(self.mycombo_prod)
        self.update_combo_prod()  # adding products to combo box
        self.update_table()
        self.layout.addWidget(self.mytable)
        self.layout.addWidget(self.search_button)
        self.layout.addWidget(self.text_select_subs)
        self.setLayout(self.layout)
        self.search_button.clicked.connect(self.update_subs_table)
        self.mycombo_cat.currentIndexChanged.connect(self.update_combo_prod)

        self.mycombo_prod.currentIndexChanged.connect(self.update_table)
        self.save_button.clicked.connect(self.save_results)

        self.layout.addWidget(self.subs_table)
        self.subs_table.hide()
        self.layout.addWidget(self.save_button)

    def update_combo_prod(self):
        """
        This function is used to update the list of products for
        the category selected.
        """
        self.mycombo_prod.clear()
        category_selected = (self.mycombo_cat.currentIndex()) + self.first_cat
        sql_query_test = """SELECT product_name FROM Product inner join
                            Product_category
                            WHERE Product.id = Product_category.product_id and
                            Product_category.category_id = %s"""

        self.mycursor.execute(sql_query_test, (category_selected,))
        result = self.mycursor.fetchall()
        for x in result:
            self.mycombo_prod.addItem(x[0])

    def update_table(self):
        """
        This function is used to update product table that the user can select.
        """
        self.mytable.setHorizontalHeaderLabels(("Selected product;\
Nutriscore;Stores;Link to website").split(";"))
        header = self.mytable.horizontalHeader()
        product_selected_name = self.mycombo_prod.currentText()
        sql_query = "SELECT id FROM Product WHERE product_name = %s"
        self.mycursor.execute(sql_query, (product_selected_name,))
        result = self.mycursor.fetchall()
        for product in result:
            self.product_selected_id = product[0]

        sql_query2 = """SELECT product_name, nutriscore, stores,
                        url FROM Product WHERE id = %s"""
        self.mycursor.execute(sql_query2, (self.product_selected_id,))
        result2 = self.mycursor.fetchall()
        for product in result2:
            res_prod_name = product[0]
            self.res_nutri = product[1]
            res_stores = product[2]
            res_url = product[3]
        url = QtWidgets.QTableWidgetItem(res_url)
        product_name = QtWidgets.QTableWidgetItem(res_prod_name)
        nutriscore = QtWidgets.QTableWidgetItem(self.res_nutri)
        stores = QtWidgets.QTableWidgetItem(res_stores)
        self.mytable.setItem(0, 3, url)
        self.mytable.setItem(0, 0, product_name)
        self.mytable.setItem(0, 1, nutriscore)
        self.mytable.setItem(0, 2, stores)
        header.setSectionResizeMode(0, QtWidgets.QHeaderView.Stretch)
        header.setSectionResizeMode(1, QtWidgets.QHeaderView.Stretch)
        header.setSectionResizeMode(2, QtWidgets.QHeaderView.Stretch)
        header.setSectionResizeMode(3, QtWidgets.QHeaderView.Stretch)

        header.setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeToContents)
        header.setSectionResizeMode(1, QtWidgets.QHeaderView.ResizeToContents)
        header.setSectionResizeMode(2, QtWidgets.QHeaderView.ResizeToContents)
        header.setSectionResizeMode(3, QtWidgets.QHeaderView.ResizeToContents)

    def update_subs_table(self):
        """
        This function is used to update the substitution products table
        """
        self.delete_rows_subs_table()
        self.subs_table.setHorizontalHeaderLabels(("Substitution product;\
Nutriscore;Stores;Link to website").split(";"))
        header2 = self.subs_table.horizontalHeader()
        header2.setSectionResizeMode(0, QtWidgets.QHeaderView.Stretch)
        header2.setSectionResizeMode(1, QtWidgets.QHeaderView.Stretch)
        header2.setSectionResizeMode(2, QtWidgets.QHeaderView.Stretch)
        header2.setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeToContents)
        header2.setSectionResizeMode(1, QtWidgets.QHeaderView.ResizeToContents)
        header2.setSectionResizeMode(2, QtWidgets.QHeaderView.ResizeToContents)
        category_selected = (self.mycombo_cat.currentIndex()) + self.first_cat
        sql_query_subs = """SELECT id, product_name, nutriscore,
                            stores, url FROM Product inner join
                            Product_category WHERE Product.id =
                            Product_category.product_id
                            and Product_category.category_id = %s"""
        self.mycursor.execute(sql_query_subs, (category_selected,))
        result = self.mycursor.fetchall()
        row_nbr = 0
        self.possible_substitution = []
        for product in result:
            if product[2] < self.res_nutri:
                self.subs_table.insertRow(row_nbr)
                self.possible_substitution.append(product[0])
                res_prod_name = product[1]
                res_nutri = product[2]
                res_stores = product[3]
                res_url = product[4]
                url = QtWidgets.QTableWidgetItem(res_url)
                product_name = QtWidgets.QTableWidgetItem(res_prod_name)
                nutriscore = QtWidgets.QTableWidgetItem(res_nutri)
                stores = QtWidgets.QTableWidgetItem(res_stores)
                self.subs_table.setItem(row_nbr, 3, url)
                self.subs_table.setItem(row_nbr, 0, product_name)
                self.subs_table.setItem(row_nbr, 1, nutriscore)
                self.subs_table.setItem(row_nbr, 2, stores)
                row_nbr += 1
        if row_nbr == 0:
            message_box = QtWidgets.QMessageBox()
            message_box.setWindowTitle("Project 5 : Openfoodfacts")
            message_box.setText("There is no better product \
than the one selected ! :=)")
            message_box.exec()
        self.subs_table.show()
        self.save_button.show()

    def delete_rows_subs_table(self):
        """
        Clear the substitution products table before a new search.
        """
        self.subs_table.clear()
        self.subs_table.setRowCount(0)

    def save_results(self):
        """
        This function is used to save results by inserting the product selected
        and the substitution product chosen into the table 'Product_saved'
        in our database.
        """
        line_selected = self.subs_table.currentRow()
        substitution_chosen = self.possible_substitution[line_selected]
        sql1 = """INSERT INTO Product_saved (product_selected_id,
                  substitution_product_id) VALUES (%s, %s)"""
        self.mycursor.execute(sql1, (self.product_selected_id,
                                     substitution_chosen))
        self.mydb.commit()
Esempio n. 14
0
class WMatSelectV(QGroupBox):
    """
    Material related widget including a Label, a Combobox to select a material
    and a Button to edit a material libary.
    WMatSelect is instantiated to empty material data, so it has to be referenced
    to actual material data with the update method prior to its first usage.
    """

    # Signal to W_MachineSetup to know that the save popup is needed
    saveNeeded = Signal()

    def __init__(self, parent=None):
        """
        Set a reference to a material libray and material data path,
        updates the Combobox by the material names of the libary
        and set a referenced material by name.

        Parameters
        ----------
        self :
            A WMatSelect object
        parent :
            A reference to the widgets parent

        Returns
        -------

        """

        # Build the interface according to the .ui file
        QGroupBox.__init__(self, parent)

        self.verticalLayout = QVBoxLayout(self)
        self.c_mat_type = QComboBox(self)
        self.c_mat_type.setObjectName(u"c_mat_type")
        self.verticalLayout.addWidget(self.c_mat_type)

        self.b_matlib = QPushButton(self)
        self.b_matlib.setObjectName(u"b_matlib")
        self.b_matlib.setText("Edit Materials")
        self.verticalLayout.addWidget(self.b_matlib)

        # Create the property of the widget
        self.mat_win = None  # DMatLib widget
        self.obj = None  # object that has a material attribute
        self.mat_attr_name = ""  # material attribute name
        self.matlib = list()  # Matlib
        self.matlib_path = ""  # Path to save the matlib
        self.def_mat = "M400-50A"  # Default material
        self.is_hide_button = False  # To hide the "Edit material" button

        # Connect the signals
        self.c_mat_type.currentIndexChanged.connect(self.set_mat_type)
        self.b_matlib.clicked.connect(self.s_open_matlib)

    def update(self, obj, mat_attr_name, matlib, matlib_path=""):
        """
        Set a reference to a material libray and material data path,
        updates the Combobox by the material names of the libary
        and set a referenced material by name.

        Parameters
        ----------
        self :
            A WMatSelect object
        obj :
            A pyleecan object that has a material attribute
        mat_attr_name :
            A string of the material attribute name
        matlib :
            A material libary, i.e. a list of Material objects
        matlib_path :
            A string containing the path of material data

        Returns
        -------

        """
        self.c_mat_type.blockSignals(True)

        # Set material combobox according to matlib names
        self.obj = obj
        self.mat_attr_name = mat_attr_name
        self.matlib = matlib
        self.matlib_path = matlib_path

        if self.is_hide_button:
            self.b_matlib.hide()
        else:
            self.b_matlib.show()

        # Update the list of materials
        self.c_mat_type.clear()
        items_to_add = []
        # Add RefMatLib materials
        items_to_add.extend([mat.name for mat in matlib.dict_mat["RefMatLib"]])
        # Add machine-specific materials
        items_to_add.extend(
            [mat.name for mat in matlib.dict_mat["MachineMatLib"]])
        self.c_mat_type.addItems(items_to_add)

        mat = getattr(self.obj, mat_attr_name, None)
        if mat is None or mat.name is None:
            # Default lamination material: M400-50A
            index = self.c_mat_type.findText(self.def_mat)
            if index != -1:
                # self.mat.__init__(init_dict=self.matlib[index].as_dict())
                setattr(
                    self.obj,
                    self.mat_attr_name,
                    self.matlib.dict_mat["RefMatLib"][index],
                )
        else:
            index = self.c_mat_type.findText(mat.name)
        self.c_mat_type.setCurrentIndex(index)
        self.c_mat_type.blockSignals(False)

    def setText(self, txt):
        """
        Set the Label's text

        Parameters
        ----------
        self :
            A WMatSelect object
        txt :
            A text string

        Returns
        -------

        """
        self.setTitle(txt)

    def set_mat_type(self, index):
        """
        Signal to set the referenced material from the material libary
        by the selected Combobox index

        Parameters
        ----------
        self :
            A WMatSelect object
        index :
            Current index of the combobox

        Returns
        -------

        """
        if index >= len(self.matlib.dict_mat["RefMatLib"]):
            index -= len(self.matlib.dict_mat["RefMatLib"])
            dict_key = "MachineMatLib"
        else:
            dict_key = "RefMatLib"

        setattr(self.obj, self.mat_attr_name,
                self.matlib.dict_mat[dict_key][index])
        # Notify the machine GUI that the machine has changed
        self.saveNeeded.emit()

    def s_open_matlib(self):
        """
        Open the GUI (DMatLib widget) to Edit the Material library

        Parameters
        ----------
        self :
            A WMatSelect object

        Returns
        -------

        """
        if self.c_mat_type.currentIndex() >= len(
                self.matlib.dict_mat["RefMatLib"]):
            index = self.c_mat_type.currentIndex() - len(
                self.matlib.dict_mat["RefMatLib"])
            key = "MachineMatLib"
        else:
            index = self.c_mat_type.currentIndex()
            key = "RefMatLib"
        self.mat_win = DMatLib(self.matlib, key, index)
        self.mat_win.accepted.connect(self.set_matlib)
        self.mat_win.saveNeeded.connect(self.emit_save)
        self.mat_win.show()

    def emit_save(self):
        """
        Emit saveNeeded if a material has been edited
        """
        self.saveNeeded.emit()

    def set_matlib(self):
        """Update the matlib with the new value

        Parameters
        ----------
        self :
            A WMatSelect object

        Returns
        -------

        """
        # Empty and fill the list to keep the same object (to change it everywhere)
        # del self.matlib[:]
        # self.matlib.extend(self.mat_win.matlib)
        # Update the material
        # index = int(self.mat_win.nav_mat.currentItem().text()[:3]) - 1

        # not needed if machine materials are "connected" properly
        # mat_dict = (self.mat_win.matlib[index]).as_dict()
        # self.mat.__init__(init_dict=mat_dict)

        # Do not clear for now to keep editor (DMatLib) open
        # # Clear the window
        # self.mat_win.deleteLater()
        # self.mat_win = None

        # Update the widget
        # Avoid trigger signal currentIndexChanged
        self.c_mat_type.blockSignals(True)

        self.c_mat_type.clear()

        items_to_add = []
        # Add RefMatLib materials
        items_to_add.extend(
            [mat.name for mat in self.matlib.dict_mat["RefMatLib"]])
        # Add machine-specific materials
        items_to_add.extend(
            [mat.name for mat in self.matlib.dict_mat["MachineMatLib"]])
        self.c_mat_type.addItems(items_to_add)

        index = self.c_mat_type.findText(
            getattr(self.obj, self.mat_attr_name).name)
        self.c_mat_type.setCurrentIndex(index)

        self.c_mat_type.blockSignals(False)
Esempio n. 15
0
class appConfigStack(QWidget):
    message = Signal("QObject", "QObject")

    def __init__(self, stack):
        super().__init__()
        self.dbg = True
        self.default_icon = 'shell'
        self.menu_description = (_("Configure stack"))
        self.description = (_("Configure custom stack"))
        self.icon = ('org.kde.plasma.quicklaunch')
        self.tooltip = (_("From here you can configure something"))
        self.index = 1
        self.enabled = True
        self.sw_changes = False
        self.level = 'user'
        self.appConfig = None
        self.config = {}
        self.changes = False
        self.add_events = False
        self.refresh = False
        self.stack = stack
        self.textdomain = ''
        self.btn_ok = QPushButton(_("Apply"))
        self.btn_cancel = QPushButton(_("Undo"))
        self.__init_stack__()
        self.writeConfig = self.writeDecorator(self.writeConfig)

    #def __init__

    def __init_stack__(self):
        raise NotImplementedError()

    #def __init_stack__

    def _debug(self, msg):
        if self.dbg:
            logging.warning("Stack {0}: {1}".format(self.description, msg))

    #def _debug

    def initScreen(self):
        self._debug("No init values")

    def setAppConfig(self, appconfig):
        self.appConfig = appconfig

    #def setAppConfig

    def translate(self, msg=""):
        return (gettext.dgettext(self.textdomain, msg))

    def setTextDomain(self, textDomain):
        #gettext.textdomain(textDomain)
        gettext.textdomain('{}'.format(textDomain))
        _ = gettext.gettext

    #def set_textDomain(self,textDomain):

    def applyParms(self, app):
        self._debug("Set parm %s" % app)
        self.app = app

    #def apply_parms(self,app):

    def getConfig(self, level=None, exclude=[]):
        self._debug("Getting config for level {}".format(level))
        self._debug("Exclude keys: {}".format(exclude))
        cursor = QtGui.QCursor(Qt.WaitCursor)
        self.setCursor(cursor)
        data = {'system': {}, 'user': {}, 'n4d': {}}
        self._debug("Refresh: {}".format(self.refresh))
        self._debug("Changes: {}".format(self.changes))
        if self.refresh or self.changes:
            if level:
                data = self.appConfig.getConfig(level, exclude)
            else:
                data = self.appConfig.getConfig('system', exclude)
                #				self._debug("Data: %s"%data)
                self.level = data['system'].get('config', 'user')
                if self.level != 'system':
                    data = self.appConfig.getConfig(self.level, exclude)
                    level = data[self.level].get('config', 'n4d')
                    if level != self.level:
                        self.level = level
                        data = self.appConfig.getConfig(level, exclude)
                        data[self.level]['config'] = self.level
        else:
            if self.config[self.level]:
                data[self.level] = self.config[self.level].copy()
        self._debug("Read level from config: {}".format(self.level))
        self.refresh = False
        cursor = QtGui.QCursor(Qt.PointingHandCursor)
        self.setCursor(cursor)
        return (data)

    #def get_default_config

    def setConfig(self, config):
        if self.config and self.config == config:
            self.refresh = False
        else:
            if self.config:
                self.refresh = True
            self.config = config.copy()

    #def setConfig

    def setLevel(self, level):
        self.level = level

    #def setLevel

    def _reset_screen(self):
        self.updateScreen()
        self.setChanged(False)

    #def _reset_screen

    def updateScreen(self):
        print("updateScreen method not implemented in this stack")
        raise NotImplementedError()

    #def updateScreen

    def saveChanges(self, key, data, level=None):
        cursor = QtGui.QCursor(Qt.WaitCursor)
        self.setCursor(cursor)
        retval = False
        if not level:
            self.getConfig()
            level = self.level
        self._debug("Saving to level {}".format(level))
        retval = True
        if not self.appConfig.write_config(data, level=level, key=key):
            self.btn_ok.setEnabled(True)
            self.btn_cancel.setEnabled(True)
            self.refresh = False
            self.changes = True
            retval = False
            self.showMsg("Failed to write config")
        cursor = QtGui.QCursor(Qt.PointingHandCursor)
        self.setCursor(cursor)
        return retval

    #def saveChanges

    def writeDecorator(self, func):
        def states():
            cursor = QtGui.QCursor(Qt.WaitCursor)
            self.setCursor(cursor)
            func()
            self.btn_ok.setEnabled(False)
            self.btn_cancel.setEnabled(False)
            self.refresh = True
            self.changes = False
            cursor = QtGui.QCursor(Qt.PointingHandCursor)
            self.setCursor(cursor)

        return states

    #def writeDecorator

    def writeConfig(self):
        print("writeConfig method not implemented in this stack")
        raise NotImplementedError()

    #def writeConfig

    def showEvent(self, event):
        def recursive_add_events(layout):
            def recursive_explore_widgets(widget):
                if widget == None:
                    return
                if isinstance(widget, QCheckBox):
                    widget.stateChanged.connect(self.setChanged)
                if isinstance(widget, QRadioButton):
                    widget.toggled.connect(self.setChanged)
                elif isinstance(widget, QComboBox):
                    widget.currentTextChanged.connect(self.setChanged)
                elif isinstance(widget, QLineEdit):
                    widget.textChanged.connect(self.setChanged)
                elif isinstance(widget, QSlider):
                    widget.valueChanged.connect(self.setChanged)
                elif isinstance(widget, QPushButton):
                    if widget.menu():
                        widget.menu().triggered.connect(self.setChanged)
                    else:
                        widget.clicked.connect(self.setChanged)
                elif 'dropButton' in str(widget):
                    widget.drop.connect(self.setChanged)
                elif isinstance(widget, QTableWidget):
                    for x in range(0, widget.rowCount()):
                        for y in range(0, widget.columnCount()):
                            tableWidget = widget.cellWidget(x, y)
                            recursive_explore_widgets(tableWidget)
                elif widget.layout():
                    recursive_add_events(widget.layout())

            for idx in range(0, layout.count()):
                widget = layout.itemAt(idx).widget()
                if widget:
                    recursive_explore_widgets(widget)

                elif layout.itemAt(idx).layout():
                    recursive_add_events(layout.itemAt(idx).layout())

        if self.add_events == False:
            self.add_events = True
            layout = self.layout()
            if layout:
                recursive_add_events(layout)
                box_btns = QHBoxLayout()
                self.btn_ok.clicked.connect(self.writeConfig)
                self.btn_ok.setFixedWidth(self.btn_ok.sizeHint().width())
                self.btn_cancel.clicked.connect(self._reset_screen)
                self.btn_cancel.setFixedWidth(self.btn_ok.sizeHint().width())
                box_btns.addWidget(self.btn_ok, 1, Qt.AlignRight)
                box_btns.addWidget(self.btn_cancel, Qt.AlignRight)
                try:
                    layout.addLayout(box_btns, Qt.AlignRight)
                except:
                    layout.addLayout(box_btns, layout.rowCount(), 0, 1,
                                     layout.columnCount())
        self.btn_ok.setEnabled(False)
        self.btn_cancel.setEnabled(False)
        try:
            self.updateScreen()
            self.setChanged(False)
        except:
            print("updateScreen method is not implemented in this stack")

    #def showEvent

    def hideControlButtons(self):
        self.btn_ok.hide()
        self.btn_cancel.hide()

    #def hideControlButtons(self):

    def setChanged(self, state=True):
        self._debug("State: {}".format(state))
        if isinstance(state, bool) == False:
            if state:
                state = True
            else:
                state = False

        if self.btn_ok.isHidden() == False:
            self.btn_ok.setEnabled(state)
            self.btn_cancel.setEnabled(state)
        else:
            state = False
        self.changes = state
        self._debug("New State: {}".format(state))

    #def setChanged

    def getChanges(self):
        self._debug("Read state: {}".format(self.changes))
        return self.changes

    #def getChanges

    def setParms(self, parms):
        return

    #def setParms

    def showMsg(self, msg, title='', state=None):
        self._debug("Sending {}".format(msg))
        if title == '':
            title = self.description
        notify2.init(title)
        notice = notify2.Notification(msg)
        notice.show()
        return
#self.message.emit(msg,state)
#def showMsg

    def n4dGetVar(self, client=None, var=''):
        ret = self.appConfig.n4dGetVar(client, var)
        return (ret)

    #def n4dQuery

    def n4dSetVar(self, client=None, var='', val={}):
        ret = self.appConfig.n4dSetVar(client, var, val)
        return (ret)

    #def n4dQuery

    def n4dDelVar(self, client=None, var=''):
        ret = self.appConfig.n4dDelVar(client, var)
        return (ret)

    #def n4dQuery

    def n4dQuery(self, n4dclass, n4dmethod, *args, **kwargs):
        ret = self.appConfig.n4dQuery(n4dclass, n4dmethod, *args, **kwargs)
        return (ret)
Esempio n. 16
0
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__(flags=Qt.WindowContextHelpButtonHint
                         | Qt.WindowCloseButtonHint | Qt.CustomizeWindowHint)

        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.setUpMainWindow()

    def setUpMainWindow(self):
        self.setWindowTitle(
            "Lab Tools 1.0 (2021 Edition) - Applications of ML in Mechatronics"
        )
        # set icon
        self.setUpIcon()

        #set up the info and start processing button
        self.inputLineEdit = QLineEdit()
        self.outputFolderLineEdit = QLineEdit()
        self.modelLineEdit = QLineEdit()
        self.browseOutputButton = QPushButton()
        self.browseInputButton = QPushButton()
        self.browseModelButton = QPushButton()
        self.startStopButton = QPushButton()
        self.useDefaultModelCheckbox = QCheckBox()

        self.inputLineEdit = self.findChild(QLineEdit, "inputLineEdit")
        self.modelLineEdit = self.findChild(QLineEdit, "modelLineEdit")
        self.outputFolderLineEdit = self.findChild(QLineEdit,
                                                   "outputFolderLineEdit")
        self.browseOutputButton = self.findChild(QPushButton,
                                                 "browseOutputButton")
        self.browseInputButton = self.findChild(QPushButton,
                                                "browseInputButton")
        self.browseModelButton = self.findChild(QPushButton,
                                                "browseModelButton")
        self.startStopButton = self.findChild(QPushButton, "startStopButton")
        self.useDefaultModelCheckbox = self.findChild(
            QCheckBox, "useDefaultModelCheckbox")
        self.chooseModelLabel = self.findChild(QLabel, "chooseModelLabel")

        #disabling model transfer capability if needed
        self._modelRPiPath = False
        if DISABLE_MODEL_TRASFER:
            self.useDefaultModelCheckbox.hide()
            self.modelLineEdit.setEnabled(1)
            self.browseModelButton.hide()
            self.chooseModelLabel.setText(self.chooseModelLabel.text() +
                                          " Name")
            # self.gridLayout = self.findChild(QGridLayout, "gridLayout")
            # self.gridLayout.removeWidget(self.browseModelButton)
            # self.gridLayout.removeWidget(self.useDefaultModelCheckbox)
            self._modelRPiPath = True

        self.startStopButton.clicked.connect(self.handleStartStopButtonClicked)
        self.browseOutputButton.clicked.connect(self.handleBrowseOutputButton)
        self.browseInputButton.clicked.connect(self.handleBrowseInputButton)
        self.browseModelButton.clicked.connect(self.handleBrowseModelButton)
        self.useDefaultModelCheckbox.stateChanged.connect(
            self.handleUseDefaultModelCheckboxStateChanged)
        self.useDefaultModelCheckbox.setChecked(True)

        #set up the log and progress bar
        self.logTextBrowser = QTextBrowser()
        self.lastLogTextLabel = QLabel()
        self.logTextBrowser = self.findChild(QTextBrowser, "logTextBrowser")
        self.progressBar = self.findChild(QProgressBar, "progressBar")
        self.clearLogButton = self.findChild(QPushButton, "clearLogButton")
        self.saveLogButton = self.findChild(QPushButton, "saveLogButton")
        self.lastLogTextLabel = self.findChild(QLabel, "lastLogTextLabel")
        self.clearLogButton.clicked.connect(self.handleClearLogButton)
        self.saveLogButton.clicked.connect(self.handleSaveLogButton)

        #set up menu bar
        self.actionHelp = self.findChild(QAction, "actionHelp")
        self.actionAbout = self.findChild(QAction, "actionAbout")
        self.actionHelp.triggered.connect(self.handleActionHelpClicked)
        self.actionAbout.triggered.connect(self.handleActionAboutClicked)

        # Add additional menu actions
        self.utilitiesMenu = self.menuBar().addMenu("Utilities")
        self.actionGetRPiIP = QAction("Get RPi IP")
        self.utilitiesMenu.addAction(self.actionGetRPiIP)
        self.actionGetRPiIP.triggered.connect(self.handleActionGetRPiIPClicked)
        self.actionUpdateRPiScript = QAction("Updare RPi Script")
        self.utilitiesMenu.addAction(self.actionUpdateRPiScript)
        self.actionUpdateRPiScript.triggered.connect(
            self.handleActionUpdateRPiScript)

        #create objects from the other classes
        self.logger = Logger(self.logTextBrowser, self.lastLogTextLabel)

        #initialize member variables
        self._b_processRunning = False

        # set up lab names
        self.setUpLabNames()

        #set up serial comms
        self.setupSerial()
        self.refreshSerialPorts()

        self.logger.log("The application is ready!", type="INFO")

    def setUpIcon(self):
        self.appIcon = QIcon("images/favicon.png")
        self.setWindowIcon(self.appIcon)

    def setUpLabNames(self):
        self.labNameComboBox = QComboBox()

        self.labNameComboBox = self.findChild(QComboBox, "labNameComboBox")
        self.labNameComboBox.currentIndexChanged.connect(
            self.handleLabNameComboboxCurrentIndexChanged)
        for code, name in utils.lab_names.items():
            self.labNameComboBox.addItem(code + ": " + name)
        self.labNameComboBox.setCurrentIndex(1)

    def setupSerial(self):
        self.refreshSerialPortsButton = QPushButton()
        self.connectDisconnectSerialButton = QPushButton()
        self.serialPortComboBox = QComboBox()

        self.refreshSerialPortsButton = self.findChild(
            QPushButton, "refreshSerialPortsButton")
        self.connectDisconnectSerialButton = self.findChild(
            QPushButton, "connectDisconnectSerialButton")
        self.serialPortComboBox = self.findChild(QComboBox,
                                                 "serialPortComboBox")
        self.refreshSerialPortsButton.clicked.connect(self.refreshSerialPorts)
        self.connectDisconnectSerialButton.clicked.connect(
            self.handleSerialConnectDisconnect)
        self._b_serialConnected = False

    def refreshSerialPorts(self):
        availablePorts = utils.find_serial_ports()
        self.serialPortComboBox.clear()
        for portName in availablePorts:
            self.serialPortComboBox.addItem(portName)

    def handleSerialConnectDisconnect(self):
        if not self.b_serialConnected:
            try:
                currentPortName = self.serialPortComboBox.currentText()
                self.port = serial.Serial(currentPortName,
                                          115200,
                                          timeout=1,
                                          write_timeout=240,
                                          bytesize=8,
                                          parity='N',
                                          stopbits=1)
                self.port.set_buffer_size(rx_size=10**3, tx_size=10**8)
                self.serialPortComboBox.setItemText(
                    self.serialPortComboBox.currentIndex(),
                    currentPortName + " (CONNECTED)")
                self.connectDisconnectSerialButton.setText("Disconnect")
                self.b_serialConnected = True
                self.refreshSerialPortsButton.setDisabled(1)
            except (OSError, serial.SerialException):
                print("Problem with Serial Connection!")
                self.logger.log(
                    "Problem with Serial Connection, Make sure you chose the right port",
                    type="ERROR")
        else:
            try:
                self.port.close()
                self.refreshSerialPorts()
                self.connectDisconnectSerialButton.setText("Connect")
                self.b_serialConnected = False
                self.refreshSerialPortsButton.setEnabled(1)
            except (OSError, serial.SerialException):
                print("Problem with Serial Connection!")
                self.logger.log("Problem with Serial Connection", type="ERROR")

    def _startButtonClicked(self):
        self.logger.log("Attempting to start the processing", type="INFO")
        if not self.b_serialConnected:
            self.logger.log(
                "Serial is not connected, Please connect serial first",
                type="ERROR")
            return
        if self.inputLineEdit.text()[-4:].lower() != ".csv":
            self.logger.log("Please select a valid input csv file",
                            type="ERROR")
            return
        if self.outputFolderLineEdit.text() == "":
            self.logger.log("Please select an output directory", type="ERROR")
            return
        self.executer = Executer(serialObj=self.port, loggerObj=self.logger)

        if self.modelLineEdit.text() != "":
            modelPath = self.modelLineEdit.text()
        else:
            modelPath = None
            if self._modelRPiPath:
                self.logger.log(
                    "Please select a valid model that is already available in the folder saved_models on the RPi",
                    type="ERROR")
                return

        #Read the Input File
        try:
            inputDataFrame = pd.read_csv(self.inputLineEdit.text())
        except:
            self.logger.log("CSV File Reading Failed, select a valid csv file",
                            type="ERROR")

        possibleInputs = list(inputDataFrame.columns)

        #Display a dialog to ask the user to choose what inputs they want
        dialog = QDialog(self)

        dialog.setWindowTitle("Select the Input Fields")
        dialogButtons = QDialogButtonBox(QDialogButtonBox.Ok
                                         | QDialogButtonBox.Cancel)
        dialogButtons.button(QDialogButtonBox.Ok).setDisabled(0)
        dialogButtons.accepted.connect(dialog.accept)
        dialogButtons.rejected.connect(dialog.reject)

        mainLayout = QVBoxLayout(dialog)
        scroll = QScrollArea(dialog)
        scroll.setWidgetResizable(True)
        layoutWidget = QWidget()
        layout = QVBoxLayout(layoutWidget)
        scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        scroll.setWidget(layoutWidget)

        chosenInputs = []
        checkboxes = []

        def handleCheckboxClicked():
            dialogButtons.button(QDialogButtonBox.Ok).setDisabled(1)
            for checkbox in checkboxes:
                if checkbox.isChecked():
                    dialogButtons.button(QDialogButtonBox.Ok).setDisabled(0)

        for input in possibleInputs:
            checkbox = QCheckBox(text=input)
            checkbox.clicked.connect(handleCheckboxClicked)
            checkbox.setChecked(True)
            checkboxes.append(checkbox)
            layout.addWidget(checkbox)

        mainLayout.addWidget(
            QLabel(text="Please select the input fields from the following:"))
        mainLayout.addWidget(scroll)
        mainLayout.addWidget(dialogButtons)
        dialog.setLayout(mainLayout)
        # dialog.setFixedHeight(400)
        if dialog.exec_() == QDialog.Accepted:
            for checkbox in checkboxes:
                if checkbox.isChecked():
                    chosenInputs.append(checkbox.text())
            self.logger.log("The chosen input fields are: " +
                            ', '.join(chosenInputs),
                            type="INFO")
        else:
            return

        self.startStopButton.setText("Stop Processing")
        self.b_processRunning = True
        executionResult = self.executer.execute(self.labNameComboBox.currentText().split(":")[0], inputDataFrame, \
                                self.outputFolderLineEdit.text(), inputFields=chosenInputs, progressBar=self.progressBar, \
                                    model=modelPath if not self._modelRPiPath else "RPI:"+modelPath)
        if executionResult == ExecutionResult.COMPLETED:
            self._stopButtonClicked(finishedProcessing=True)
        elif executionResult == ExecutionResult.INTERRUPTED or executionResult == ExecutionResult.FAILED:
            self._stopButtonClicked()
            if self.executer.reset() == ExecutionResult.FAILED:
                self.logger.log(
                    "Resetting the serial state of RPi Failed, please power cycle the RPi",
                    type="ERROR")
            else:
                self.logger.log("The serial state of RPi has been reset",
                                type="INFO")

    def _stopButtonClicked(self, finishedProcessing=False):
        self.startStopButton.setText("Start Processing")
        if finishedProcessing:
            self.logger.log("", special="ProcessingCompleted")
        else:
            self.logger.log("", special="ProcessingStopped")
        self.b_processRunning = False
        #TODO: Complete Implementing this

    def handleStartStopButtonClicked(self):
        if (self.b_processRunning):
            self.executer.requestStop()
        else:
            self._startButtonClicked()

    def handleActionHelpClicked(self):
        helpBox = QMessageBox()
        helpBox.setIcon(QMessageBox.Information)
        helpBox.setStandardButtons(QMessageBox.Ok)
        helpBox.setWindowTitle("Need Help?")
        helpBox.setText(
            "For Help, please reach out to your Instructor or TA or read the lab manual"
        )
        helpBox.setTextFormat(Qt.RichText)
        helpBox.setInformativeText(
            f"You can access the project <a href=\"{utils.docs_link}\">Manual</a> and source in the <a href=\"{utils.repo_link}\">Github Repo!</a>"
        )
        helpBox.setWindowIcon(self.appIcon)
        helpBox.exec_()

    def handleActionAboutClicked(self):
        aboutBox = QMessageBox()
        aboutBox.setIcon(QMessageBox.Information)
        aboutBox.setStandardButtons(QMessageBox.Ok)
        aboutBox.setWindowTitle("About the Software")
        aboutBox.setText(utils.license_text)
        aboutBox.setWindowIcon(self.appIcon)
        aboutBox.exec_()

    def handleBrowseInputButton(self):
        dialog = QFileDialog(self)
        dialog.setFileMode(QFileDialog.ExistingFile)
        dialog.setNameFilter("*.csv")
        if dialog.exec_():
            filePath = dialog.selectedFiles()
            if len(filePath) == 1:
                self.inputLineEdit.setText(filePath[0])

    def handleBrowseModelButton(self):
        dialog = QFileDialog(self)
        dialog.setFileMode(QFileDialog.ExistingFile)
        dialog.setNameFilter(utils.lab_model_extensions[
            self.labNameComboBox.currentText().split(":")[0]])
        if dialog.exec_():
            filePath = dialog.selectedFiles()
            if len(filePath) == 1:
                self.modelLineEdit.setText(filePath[0])

    def handleBrowseOutputButton(self):
        dialog = QFileDialog(self)
        dialog.setFileMode(QFileDialog.DirectoryOnly)
        dialog.setOption(QFileDialog.ShowDirsOnly)
        if dialog.exec_():
            folderPath = dialog.selectedFiles()
            if len(folderPath) == 1:
                self.outputFolderLineEdit.setText(folderPath[0])

    def handleSaveLogButton(self):
        dialog = QFileDialog(self)
        dialog.setFileMode(QFileDialog.AnyFile)
        dialog.AcceptMode(QFileDialog.AcceptSave)
        dialog.setNameFilter("*.txt")
        if dialog.exec_():
            filePath = dialog.selectedFiles()
            if len(filePath) == 1:
                if self.logger.saveLog(filePath[0]) != -1:
                    self.logger.log(
                        "The log has been saved, feel free to clear the log now",
                        type="SUCCESS")
                    return
        self.logger.log("Failed to save the log, please select a valid file",
                        type="ERROR")

    def handleClearLogButton(self):
        self.logger.clearLog()

    def handleUseDefaultModelCheckboxStateChanged(self):
        if self._modelRPiPath:
            return
        if not self.useDefaultModelCheckbox.checkState():
            self.modelLineEdit.setDisabled(0)
            self.browseModelButton.setDisabled(0)
        else:
            self.modelLineEdit.clear()
            self.modelLineEdit.setDisabled(1)
            self.browseModelButton.setDisabled(1)

    def handleLabNameComboboxCurrentIndexChanged(self):
        if self._modelRPiPath:
            self.modelLineEdit.setText(utils.lab_default_models[
                self.labNameComboBox.currentText().split(":")[0]])
        # Disable the model options when the lab selected is Communication Test
        if self.labNameComboBox.currentIndex() == 0:
            self.modelLineEdit.setDisabled(1)
            self.browseModelButton.setDisabled(1)
            self.modelLineEdit.setText("Model is not required")
        else:
            self.modelLineEdit.setDisabled(0)
            self.browseModelButton.setDisabled(0)

    def handleActionGetRPiIPClicked(self):
        self.logger.log("Attempting to Get Raspberry Pi IP Address",
                        type="INFO")
        if not self.b_serialConnected:
            replyMessage = "Serial is not connected, Please connect serial first"
        else:
            self.executer = Executer(serialObj=self.port,
                                     loggerObj=self.logger)
            ipaddr = self.executer.executeOther("GET_IP")
            replyMessage = (
                "Raspberry Pi IP is " + ipaddr
            ) if ipaddr != ExecutionResult.FAILED else "Failed to obtain the IP Address"
        self.logger.log(replyMessage)
        ipAddrMessage = QMessageBox()
        ipAddrMessage.setIcon(QMessageBox.Information)
        ipAddrMessage.setStandardButtons(QMessageBox.Ok)
        ipAddrMessage.setWindowTitle("Raspberry Pi IP Address")
        ipAddrMessage.setText(replyMessage)
        ipAddrMessage.setTextFormat(Qt.RichText)
        ipAddrMessage.setWindowIcon(self.appIcon)
        ipAddrMessage.exec_()

    def handleActionUpdateRPiScript(self):
        self.logger.log(
            'Attempting to "git pull" for the Raspberry Pi Python Script',
            type="INFO")
        if not self.b_serialConnected:
            replyMessage = "Serial is not connected, Please connect serial first"
        else:
            self.executer = Executer(serialObj=self.port,
                                     loggerObj=self.logger)
            result = self.executer.executeOther("UPDATE_SCRIPT")
            if result != ExecutionResult.FAILED and "FAIL" not in result:
                replyMessage = "Raspberry Pi Script has been updated. You still need to reboot or power cycle the Raspberry Pi for the updated script to run" \
                                    "\nReceived: " + result
            else:
                replyMessage = "Failed to update the RPi Script"
                if "FAIL" in result:
                    replyMessage = replyMessage + "\nReceived: " + result

        self.logger.log(replyMessage)
        ipAddrMessage = QMessageBox()
        ipAddrMessage.setIcon(QMessageBox.Information)
        ipAddrMessage.setStandardButtons(QMessageBox.Ok)
        ipAddrMessage.setWindowTitle("Raspberry Pi Script Updating Status")
        ipAddrMessage.setText(replyMessage)
        ipAddrMessage.setTextFormat(Qt.RichText)
        ipAddrMessage.setWindowIcon(self.appIcon)
        ipAddrMessage.exec_()

    @property
    def b_processRunning(self):
        return self._b_processRunning

    @property
    def b_serialConnected(self):
        return self._b_serialConnected

    @b_serialConnected.setter
    def b_serialConnected(self, newValue):
        self._b_serialConnected = newValue
        if newValue is True:
            self.logger.log("", special="SerialConnected")
        else:
            self.logger.log("", special="SerialDisconnected")

    @b_processRunning.setter
    def b_processRunning(self, newValue):
        self._b_processRunning = newValue
        if newValue is True:
            self.logger.log("", special="ProcessingStarted")

    def __del__(self):
        if self.b_serialConnected:
            self.port.close()
Esempio n. 17
0
class Window(QWidget):
    def __init__(self, app, parent=None):

        print("Window init")

        super().__init__(parent)

        # self.win_event_filter = WinEventFilter("window")
        # self.installNativeEventFilter(self.win_event_filter)

        self.app = app

        self.window_size = QtCore.QSize(400, 250)
        self.window_size_offset = QtCore.QSize(0, 150)
        self.window_position = QtCore.QPoint(0, 0)
        self.window_position_offset = QtCore.QPoint(0, 0)

        # self.setWindowFlags(
        #    QtCore.Qt.Window |
        #    QtCore.Qt.CustomizeWindowHint |
        #    QtCore.Qt.WindowTitleHint |
        #    QtCore.Qt.WindowCloseButtonHint |
        #    QtCore.Qt.WindowStaysOnTopHint
        # )

        self.setWindowFlags(self.windowFlags() |
                            QtCore.Qt.FramelessWindowHint)
        self.setWindowFlags(self.windowFlags() |
                            QtCore.Qt.WindowStaysOnTopHint)

        self.setWindowFlags(
            QtCore.Qt.FramelessWindowHint |
            QtCore.Qt.WindowStaysOnTopHint |
            QtCore.Qt.Tool)
        # hlayout = QHBoxLayout()
        # hlayout.setMargin(0)
        # hlayout.setContentsMargins(0, 0, 0, 0)
        # hlayout.setSpacing(0)

        # buttonslayout = QVBoxLayout()

        self.labels = []

        self.menuButton = QPushButton(u"\U00002261")
        self.menuLabel = QLabel("Menu")
        myFontBold = self.menuLabel.font()
        myFontBold.setBold(True)
        # buttons
        myFont = self.menuButton.font()
        myFont2 = self.menuButton.font()
        if (myFont.pointSize() > 0):
            myFont.setPointSizeF(1.25 * myFont.pointSizeF())
            myFont2.setPointSizeF(1.4 * myFont.pointSizeF())
        else:
            myFont.setPixelSize(1.25 * myFont.pixelSize())
            myFont2.setPixelSize(1.4 * myFont.pixelSize())
        self.menuLabel.setFont(myFontBold)
        width = self.menuButton.fontMetrics().boundingRect("OO").width() + 7
        height = width  # okButton.height()
        self.menuButton.setFont(myFont2)
        self.menuButton.setMaximumWidth(width)
        self.menuButton.setMinimumWidth(width)
        self.menuButton.setFlat(True)
        self.menuButton.clicked.connect(self.menuPressed)

        mainButton = QPushButton(u"\U0000239A")
        mainLabel = QLabel("Main")
        width = mainButton.fontMetrics().boundingRect("OO").width() + 7
        height = width  # okButton.height()
        mainButton.setFont(myFont2)
        mainButton.setMaximumWidth(width)
        mainButton.setMinimumWidth(width)
        mainButton.clicked.connect(self.main)
        mainButton.setFlat(True)
        setupButton = QPushButton(u"\U0001F527")
        setupLabel = QLabel("Setup")
        setupButton.setFont(myFont)
        setupButton.setFlat(True)
        setupButton.setMaximumWidth(width)
        setupButton.setMinimumWidth(width)
        setupButton.clicked.connect(self.setup)

        identifyButton = QPushButton(u"\U00002755")
        identifyLabel = QLabel("Identify")
        identifyButton.setFont(myFont)
        identifyButton.setFlat(True)
        identifyButton.setMaximumWidth(width)
        identifyButton.setMinimumWidth(width)
        identifyButton.clicked.connect(self.identify)

        self.refreshButton = QPushButton(u"\U000021BB")
        self.refreshLabel = QLabel("Detect")
        self.refreshButton.setFont(myFont)
        self.refreshButton.setFlat(True)
        self.refreshButton.setMaximumWidth(width)
        self.refreshButton.setMinimumWidth(width)
        self.refreshButton.clicked.connect(self.refreshPressed)

        aboutButton = QPushButton(u"\U00002754")
        aboutLabel = QLabel("About")
        aboutButton.setFont(myFont)
        aboutButton.setFlat(True)
        aboutButton.setMaximumWidth(width)
        aboutButton.setMinimumWidth(width)
        aboutButton.clicked.connect(self.about)

        # closeButton = QPushButton(u"\U00002573")
        closeButton = QPushButton(u"\U000026CC")
        closeLabel = QLabel("Close")
        closeButton.setFont(myFont)
        closeButton.setFlat(True)
        closeButton.setMaximumWidth(width)
        closeButton.setMinimumWidth(width)
        closeButton.clicked.connect(self.close_)

        buttongrid = QGridLayout()
        buttongrid.addWidget(self.menuButton, 0, 0)
        buttongrid.addWidget(mainButton, 1, 0)
        buttongrid.addWidget(setupButton, 2, 0)
        buttongrid.addWidget(self.refreshButton, 3, 0)
        buttongrid.addWidget(identifyButton, 4, 0)
        buttongrid.addWidget(aboutButton, 6, 0)
        buttongrid.addWidget(closeButton, 7, 0)

        buttongrid.addWidget(self.menuLabel, 0, 1)
        buttongrid.addWidget(mainLabel, 1, 1)
        buttongrid.addWidget(setupLabel, 2, 1)
        buttongrid.addWidget(self.refreshLabel, 3, 1)
        buttongrid.addWidget(identifyLabel, 4, 1)
        buttongrid.addWidget(aboutLabel, 6, 1)
        buttongrid.addWidget(closeLabel, 7, 1)
        self.labels.append(self.menuLabel)
        self.labels.append(mainLabel)
        self.labels.append(setupLabel)
        self.labels.append(self.refreshLabel)
        self.labels.append(identifyLabel)
        self.labels.append(aboutLabel)
        self.labels.append(closeLabel)
        self.menuLabel .mousePressEvent = self.menuLabelPressed
        mainLabel .mousePressEvent = self.mainLabel
        setupLabel.mousePressEvent = self.setupLabel
        self.refreshLabel.mousePressEvent = self.refreshLabelPressed
        identifyLabel.mousePressEvent = self.identifyLabel
        aboutLabel.mousePressEvent = self.aboutLabel
        closeLabel.mousePressEvent = self.closeLabel

        buttongrid.setRowStretch(0, 0)
        buttongrid.setRowStretch(1, 0)
        buttongrid.setRowStretch(2, 0)
        buttongrid.setRowStretch(3, 0)
        buttongrid.setRowStretch(4, 0)
        buttongrid.setRowStretch(5, 1)
        buttongrid.setRowStretch(6, 0)
        buttongrid.setRowStretch(7, 0)
        self.labels_set_visible(False)

        self.layout = QHBoxLayout()

        # buttonslayout.addWidget(mainButton)
        # buttonslayout.addWidget(setupButton)
        # buttonslayout.addStretch(1)
        # buttonslayout.addWidget(aboutButton)
        # hlayout.addLayout(buttonslayout)
        # hlayout.addLayout(buttongrid)

        # grid.addLayout(hlayout, 1, 1)
        buttongrid.setSpacing(0)

        self.layout.addLayout(buttongrid)

        self.body_layout = QVBoxLayout()
        self.body_layout.setContentsMargins(0, 0, 0, 1)
        self.body_layout.setSpacing(0)

        self.title_layout = QHBoxLayout()
        self.title_layout.setContentsMargins(0, 0, 0, 0)
        self.title_layout.setSpacing(0)
        self.titleLabel = QLabel("Monitor Control")
        self.titleLabel.setWordWrap(True)
        self.titleLabel.setSizeIncrement(10, 10)
        myFont = self.titleLabel.font()
        myFont.setBold(True)
        self.titleLabel.setFont(myFont)
        width = self.titleLabel.fontMetrics().boundingRect("OO").width() + 7
        height = width  # okButton.height()
        self.titleLabel.mousePressEvent = self.mainLabel

        self.backButton = QPushButton(u"\U00002190", self)
        myFont = self.backButton.font()
        myFont.setBold(True)
        self.backButton.setFont(myFont)
        self.backButton.setMaximumWidth(width)
        self.backButton.setMinimumWidth(width)
        self.backButton.setFlat(True)
        self.backButton.clicked.connect(self.main)
        self.titleLabel.setMinimumHeight(self.backButton.height())

        self.title_layout.addWidget(self.backButton, 0, QtCore.Qt.AlignVCenter)
        self.title_layout.addSpacing(20)
        self.title_layout.addWidget(self.titleLabel, 1, QtCore.Qt.AlignVCenter)
        # self.backButton.setAlignment(Qt.AlignTop)
        self.title_layout.setAlignment(QtCore.Qt.AlignTop)

        self.body_layout.addLayout(self.title_layout)

        self.main_frame = QtWidgets.QFrame(self)
        self.main_layout = QVBoxLayout()
        self.feature_brightness = FeatureWidget(
            self.main_frame, "Brightness", self.app.brightness)
        self.feature_contrast = FeatureWidget(
            self.main_frame, "Contrast", self.app.contrast)
        self.main_layout.addWidget(self.feature_brightness)
        self.main_layout.addWidget(self.feature_contrast)
        self.main_layout.addStretch(1)
        self.main_frame.setLayout(self.main_layout)
        self.main_frame.hide()
        self.body_layout.addWidget(self.main_frame, 1)

        self.setup_frame = QtWidgets.QFrame(self)

        leftButton = QPushButton("<", self.setup_frame)
        width = leftButton.fontMetrics().boundingRect("<").width() + 7
        leftButton.setFlat(True)
        leftButton.setMaximumWidth(width)
        leftButton.setMinimumWidth(width)
        leftButton.setSizePolicy(QtWidgets.QSizePolicy(
            QSizePolicy.Fixed, QSizePolicy.Expanding))

        self.setup_layout = QHBoxLayout()
        self.setup_layout.addWidget(leftButton)
        self.feature_setup_widget = FeatureSetupWidget(
            self.app, self.setup_frame)
        # hlayout.addWidget(self.feature_setup_widget, 1)
        self.feature_setup_widget.setSizePolicy(
            QSizePolicy.Expanding, QSizePolicy.Expanding)
        rightButton = QPushButton(">", self.setup_frame)
        rightButton.setFlat(True)
        rightButton.setMaximumWidth(width)
        rightButton.setMinimumWidth(width)
        rightButton.setSizePolicy(QtWidgets.QSizePolicy(
            QSizePolicy.Fixed, QSizePolicy.Expanding))
        self.setup_layout.addWidget(self.feature_setup_widget, 1)
        self.setup_layout.addWidget(rightButton)
        self.setup_layout.setContentsMargins(0, 0, 0, 0)
        self.setup_layout.setSpacing(0)
        leftButton.clicked.connect(self.feature_setup_widget.previous)
        rightButton.clicked.connect(self.feature_setup_widget.next)

        self.setup_frame.setLayout(self.setup_layout)

        # self.layout.setContentsMargins(0, 0, 0, 0)
        self.layout.setSpacing(10)
        self.body_layout.addWidget(self.setup_frame, 1)

        self.layout.addLayout(self.body_layout, 1)

        self.about_frame = QtWidgets.QFrame(self)
        self.about_layout = QVBoxLayout()
        self.aboutLabel1 = QLabel("About", self.about_frame)
        self.aboutLabel1.setWordWrap(True)
        myFont = self.aboutLabel1.font()
        myFont.setBold(True)
        self.aboutLabel1.setFont(myFont)
        about = "©️ ™️ Juno\n\nMonitor Control synchronizes your monitor hardware properties like brightness and contrast.\nThese properties can be changed by the software sliders, or monitor buttons. These changes are monitored and read, and subsequently set to the other monitors using a calibration. This will ensure an input change has the same result on all monitors.\n"
        self.aboutLabel2 = QLabel("{}".format(about), self.about_frame)
        self.aboutLabel2.setAlignment(
            QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop)
        self.aboutLabel2.setWordWrap(True)
        self.about_layout.addWidget(self.aboutLabel1)
        self.about_layout.addWidget(self.aboutLabel2, 1)
        self.about_frame.setLayout(self.about_layout)
        self.about_frame.hide()
        self.body_layout.addWidget(self.about_frame, 1)

        # self.layout.setSizeConstraint(QtGui.QLayout.setFixedSize)

        self.setLayout(self.layout)

        self.setWindowIcon(QtGui.QIcon('artifacts/icon.png'))
        # set the title
        self.setWindowTitle("Monitors Control")

        self.main()

        self.setFixedSize(400, 250)

    def labels_set_visible(self, visible):
        for label in self.labels:
            if (self.refreshLabel == label) and visible:
                self.refreshLabel.setVisible(self.refreshButton.isVisible())
            else:
                label.setVisible(visible)

    def refresh_visible(self, visible):
        if (visible):
            self.refreshButton.setVisible(visible)
            self.refreshLabel.setVisible(self.menuLabel.isVisible())
        else:
            self.refreshLabel.setVisible(visible)
            self.refreshButton.setVisible(visible)

    def focusOutEvent(self, event):
        print('Lost focus')

    def menuLabelPressed(self, event):
        self.menuPressed()

    def menuPressed(self):
        print("Menu")
        self.labels_set_visible(not self.labels[0].isVisible())

    def aboutLabel(self, event):
        self.about()

    def about(self):
        print("About")
        self.setupUpdate()

        self.setMinimumSize(200, 130)

        # self.feature_setup_widget.hide()
        self.setup_frame.hide()
        self.main_frame.hide()
        self.refresh_visible(False)
        self.backButton.show()
        self.about_frame.show()

        self.move(self.window_position)
        self.setFixedSize(self.window_size)

    def closeLabel(self, event):
        self.close_()

    def close_(self):
        print("Close {}".format(len(self.app.identifyWindows)))
        self.setupUpdate()
        if (len(self.app.identifyWindows) == 0):
            self.hide()

    def setupLabel(self, event):
        self.setup()

    def setup(self):
        print("Setup")
        self.move(self.window_position + self.window_position_offset)
        self.setFixedSize(self.window_size + self.window_size_offset)

        self.app.monitors._calibrations.loadYaml()

        self.feature_setup_widget.init()
        self.backButton.show()

        self.main_frame.hide()
        self.about_frame.hide()
        self.refresh_visible(True)
        self.setup_frame.show()

        self.setMinimumSize(200, 130)

    def setupUpdate(self):
        if (self.setup_frame.isVisible()):
            self.app.monitors._calibrations.saveYaml()

    def mainLabel(self, event):
        self.main()

    def main(self):
        print("Main")

        self.setMinimumSize(200, 130)
        self.setupUpdate()

        self.refresh_visible(False)
        self.backButton.hide()
        # self.feature_setup_widget.hide()
        self.setup_frame.hide()
        self.about_frame.hide()
        self.main_frame.hide()

        self.move(self.window_position)
        self.setFixedSize(self.window_size)

        self.main_frame.show()

    def identifyLabel(self, event):
        self.identify()

    def identify(self):
        print("Identify")

        self.app.identify()

    def refreshLabelPressed(self, event):
        self.refreshPressed()

    def refreshPressed(self):
        QApplication.setOverrideCursor(QtCore.Qt.WaitCursor)
        print("detect")
        self.feature_setup_widget.clear()
        self.app.detect()
        self.setup()
        self.feature_setup_widget.set_infos(self.app.monitors)
        self.feature_setup_widget.init()

        self.app.list_monitors()

        QApplication.restoreOverrideCursor()

    def position_show(self):
        print("position_show")
        self.app.position_next_to_tray()
        self.main()
        self.show()
        # self.requestActivate()
        # QtCore.Qt.ActiveWindowFocusReason
        self.activateWindow()
        self.setFocus(QtCore.Qt.PopupFocusReason)

    def contrast(self, value):
        # from gui
        self.app.contrast(value)

    def brightness(self, value):
        # from gui
        self.app.brightness(value)

    def set_contrast(self, value):
        # to gui
        self.feature_contrast.set_value(value)
        self.feature_setup_widget.set_contrast(value)

    def set_brightness(self, value):
        # to gui
        self.feature_brightness.set_value(value)
        self.feature_setup_widget.set_brightness(value)

    def show(self):
        # to gui
        value = self.app.monitors.get_contrast()
        if (value is not None):
            self.set_contrast(value)

        value = self.app.monitors.get_brightness()
        if (value is not None):
            self.set_brightness(value)

        self.feature_setup_widget.set_infos(self.app.monitors)

        super().show()
Esempio n. 18
0
class TrainingWindow(QWidget):

    # Dataset
    __dataset = None

    # Netwok model
    __modelList = []

    # Start training
    @Slot()
    def startTraining(self):

        # Get split value
        split = 1 - float(
            (self.__datasetSplitComboBox.currentIndex() + 1) / 10.0)

        # Get split method
        if self.__datasetSplitRandom.isChecked():
            ((x_train, y_train),
             (x_test,
              y_test)) = self.network.random_split(self.__dataset, split)
        elif self.__datasetSplitRegular.isChecked():
            ((x_train, y_train),
             (x_test,
              y_test)) = self.network.regular_split(self.__dataset, split)

        # Get epochs number
        if not self.__epochsLineEdit.text():
            ret = QMessageBox.warning(self, "Epochs number",
                                      "Please enter the number of epochs",
                                      QMessageBox.Ok)
            return
        else:
            epochs = int(self.__epochsLineEdit.text())
            self.__xAxis.setRange(0, epochs)

        # Get learning rate value
        if not self.__learningRateLineEdit.text():
            ret = QMessageBox.warning(self, "Learning rate",
                                      "Please select a learning rate",
                                      QMessageBox.Ok)
            return
        else:
            learning_rate = float(self.__learningRateLineEdit.text().replace(
                ",", "."))
            if not learning_rate:
                ret = QMessageBox.warning(
                    self, "Learning rate",
                    "The learning rate cannot be equal to zero",
                    QMessageBox.Ok)
                return

        # Get learning rate mode
        if self.__learningRateCheckBox.isChecked():
            mode = 2
        else:
            mode = 1

        # Save before training
        ret = QMessageBox.question(
            self, "Network save",
            "Would you like to save the network before the training starts?",
            QMessageBox.Yes | QMessageBox.No)
        if ret == QMessageBox.Yes:
            save_matrix_neural_network(self.network, self.networkName)
            manual_save_model_neural_network(self.network, self.networkName)
            QMessageBox.information(self, "Network save",
                                    "Network successfully saved !",
                                    QMessageBox.Ok)

        # Clearing the graph
        self.__series.clear()

        # Starting training
        length = len(x_train)
        for i in range(epochs):
            err = 0
            training_accuracy = 0
            l_rate = self.network.Learning_rate_schedule(
                mode, epochs, epochs - i + 1, learning_rate)
            for j in range(length):
                outputs = x_train[j]
                for layer in self.network.layers:
                    outputs = layer.forward_propagation(outputs)
                err += self.network.loss(y_train[j], outputs)
                training_accuracy = training_accuracy + self.network.verification_of_prediction(
                    x_train, y_train, j)
                error = self.network.loss_prime(y_train[j], outputs)
                for layer in reversed(self.network.layers):
                    error = layer.backward_propagation(error, l_rate)
            err = err / length
            training_accuracy = training_accuracy / float(length)
            self.__epochNumberLabel.setText("Epoch : " + str(i + 1) + "/" +
                                            str(epochs))
            self.__trainingAccuracyLabel.setText("Taux de precision : " +
                                                 str(training_accuracy * 100) +
                                                 "%")
            # Appending values to the chart
            self.__series.append(i, training_accuracy * 100)
            self.__chartView.repaint()
            # Auto saving network
            save_matrix_neural_network(self.network,
                                       self.networkName + "_auto")
            manual_save_model_neural_network(self.network,
                                             self.networkName + "_auto")

        # Saving trained network
        ret = QMessageBox.question(
            self, "Network save",
            "Would you like to save the trained network? ",
            QMessageBox.Yes | QMessageBox.No)
        if ret == QMessageBox.Yes:
            save_matrix_neural_network(self.network, self.networkName)
            manual_save_model_neural_network(self.network, self.networkName)
            QMessageBox.information(self, "Network save",
                                    "Network successfully saved !",
                                    QMessageBox.Ok)

        # Evaluate network and show confusion matrix
        (self.test_accuracy,
         self.matrix) = self.network.evaluate(x_test, y_test)
        self.__confusionMatrixButton.show()

    # Showing the confusion matrix
    @Slot()
    def showStats(self):
        # Creating matrix window
        self.matrixWindow = QMainWindow()
        self.matrixWindow.setFixedSize(640, 480)

        key_list = list(self.__classes.keys())
        val_list = list(self.__classes.values())

        # Creating matrix table
        self.matrixTable = QTableWidget(
            len(self.matrix) + 1,
            len(self.matrix[0]) + 1)
        for i in range(len(self.matrix)):
            self.matrixTable.setItem(
                i + 1, 0, QTableWidgetItem(str(key_list[val_list.index(i)])))
            self.matrixTable.setItem(
                0, i + 1, QTableWidgetItem(str(key_list[val_list.index(i)])))

        for i in range(len(self.matrix)):
            for j in range(len(self.matrix[0])):
                self.matrixTable.setItem(
                    i + 1, j + 1, QTableWidgetItem(str(self.matrix[i][j])))

        # Printing test accuracy
        self.matrixLabel = QLabel(
            "Test accuracy : " + str(self.test_accuracy * 100) + "%", self)
        self.matrixLabel.setFont(QFont("BebasNeue", 20, QFont.Bold))

        # Matrix window layout
        self.matrixLayout = QVBoxLayout()
        self.matrixLayout.addWidget(self.matrixTable)
        self.matrixLayout.addWidget(self.matrixLabel)

        # Matrix window groupbox
        self.matrixGroupBox = QGroupBox(self.matrixWindow)
        self.matrixGroupBox.setLayout(self.matrixLayout)

        # Showing the matrix window
        self.matrixWindow.setCentralWidget(self.matrixGroupBox)
        self.matrixWindow.show()

    def __init__(self, ds, classes, model, created, *args, **kwargs):
        super(TrainingWindow, self).__init__(*args, **kwargs)

        if created:
            # Initialising network
            self.network = Network()
            self.network.use(mean_squared_error, mean_squared_error_prime)
        else:
            self.network = model[0]

        # Getting inputs and outputs
        self.__dataset = ds
        self.__classes = classes
        #fill_missing_values(self.__dataset)
        #min_max_normalize_dataset(self.__dataset)
        ((x_train, y_train),
         (x_test, y_test)) = self.network.regular_split(self.__dataset, 0.5)

        # Getting inputs
        if len(x_train.shape) == 2:
            inputs = x_train.shape[1]
        else:
            inputs = x_train.shape[1:]
            first = inputs[0]
            second = inputs[1]
            third = inputs[2]

        # Getting expected outputs
        expected_output = y_train.shape[1]

        # Getting network name
        self.networkName = model[1]

        if created:
            # Getting model list
            self.__modelList = model[0]
            self.__modelList[0].setOutput(inputs)

            for i in range(1, len(self.__modelList)):
                # Getting the layer name
                name = self.__modelList[i].text(
                )[:len(self.__modelList[i].text()) - 6]
                activation = None
                activ_prime = None
                # Getting the activation function
                if self.__modelList[i].activation() == 0:
                    activation = sigmoid
                    activ_prime = sigmoid_prime
                elif self.__modelList[i].activation() == 1:
                    activation = tanh
                    activ_prime = tanh_prime
                elif self.__modelList[i].activation() == 2:
                    activation = rectified_linear_unit
                    activ_prime = rectified_linear_unit_prime
                elif self.__modelList[i].activation() == 3:
                    activation = softmax
                    activ_prime = softmax_prime
                # Adding layer to the network
                if name == "Dense":
                    if self.__modelList[i - 1].text()[:2] == "Fl":
                        self.network.add(
                            FullyConnectedLayer(first * second * third,
                                                self.__modelList[i].output()))
                        self.network.add(
                            ActivationLayer(activation, activ_prime))
                    else:
                        self.network.add(
                            FullyConnectedLayer(
                                self.__modelList[i - 1].output(),
                                self.__modelList[i].output()))
                        self.network.add(
                            ActivationLayer(activation, activ_prime))
                elif name == "Flatten":
                    self.network.add(FlattenLayer())
                elif name == "Convolutional":
                    self.network.add(
                        ConvLayer((first, second, third),
                                  (self.__modelList[i].kernelRows,
                                   self.__modelList[i].kernelColumns), 1))
                    self.network.add(ActivationLayer(activation, activ_prime))
                    first = first - self.__modelList[i].kernelRows + 1
                    second = second - self.__modelList[i].kernelColumns + 1

            self.network.add(
                FullyConnectedLayer(
                    self.__modelList[len(self.__modelList) - 1].output(),
                    expected_output))
            self.network.add(ActivationLayer(sigmoid, sigmoid_prime))

        # Loading Fonts
        QFontDatabase.addApplicationFont("fonts/BebasNeue-Light.ttf")

        # Window Settings
        self.setFixedSize(1280, 720)
        self.setWindowTitle("Training window")
        #background = QPixmap("images/menu")
        #palette = QPalette()
        #palette.setBrush(QPalette.Background, background)
        #self.setAttribute(Qt.WA_StyledBackground, True)
        #self.setPalette(palette)
        self.setAutoFillBackground(True)

        # Stylesheet Settings
        styleFile = QFile("stylesheets/training.qss")
        styleFile.open(QFile.ReadOnly)
        style = str(styleFile.readAll())
        self.setStyleSheet(style)

        # Title Settings
        self.title = QLabel("Training", self)
        self.title.setFont(QFont("BebasNeue", 30, QFont.Bold))
        self.title.setAlignment(Qt.AlignCenter)
        self.title.setGeometry(600, 10, 300, 120)

        # Epochs line edit settings
        self.__epochsLineEdit = QLineEdit(self)
        self.__epochsLineEdit.setValidator(QIntValidator(0, 100000, self))

        # Epochs label settings
        self.__epochsLabel = QLabel("Epoch number", self)
        self.__epochsLabel.setFont(QFont("BebasNeue", 20, QFont.Bold))

        # Learning rate line edit settings
        self.__learningRateLineEdit = QLineEdit(self)
        self.__learningRateLineEdit.setValidator(
            QDoubleValidator(0.0, 1.0, 3, self))

        # Learning rate label settings
        self.__learningRateLabel = QLabel("Learning rate", self)
        self.__learningRateLabel.setFont(QFont("BebasNeue", 20, QFont.Bold))

        # Learning rate checkboxsettings (auto or not)
        self.__learningRateCheckBox = QCheckBox("Auto adjustment", self)
        self.__learningRateCheckBox.setFont(QFont("BebasNeue", 15, QFont.Bold))

        # Dataset split settings label
        self.__datasetSplitLabel = QLabel("Dataset split percentage", self)
        self.__datasetSplitLabel.setFont((QFont("BebasNeue", 20, QFont.Bold)))

        # Dataset split mode buttons
        self.__datasetSplitRegular = QRadioButton("Regular split")
        self.__datasetSplitRandom = QRadioButton("Random split")

        # Dataset split mode buttons groupbox
        self.__datasetSplitModeButtonsLayout = QHBoxLayout(self)
        self.__datasetSplitModeButtonsGroupBox = QGroupBox(self)
        self.__datasetSplitModeButtonsGroupBox.setObjectName("setting")
        self.__datasetSplitModeButtonsLayout.addWidget(
            self.__datasetSplitRegular)
        self.__datasetSplitModeButtonsLayout.addWidget(
            self.__datasetSplitRandom)
        self.__datasetSplitModeButtonsGroupBox.setLayout(
            self.__datasetSplitModeButtonsLayout)
        self.__datasetSplitRegular.setChecked(True)

        # Dataset split combo box settings
        self.__datasetSplitComboBox = QComboBox(self)
        self.__datasetSplitComboBox.addItems(
            ['90% - 10%', '80% - 20%', '70% - 30%', '60% - 40%'])

        # Dataset split form layout settings
        self.__datasetSplitLayout = QFormLayout(self)
        self.__datasetSplitGroupBox = QGroupBox(self)
        self.__datasetSplitGroupBox.setObjectName("setting")
        self.__datasetSplitLayout.addWidget(self.__datasetSplitLabel)
        self.__datasetSplitLayout.addWidget(self.__datasetSplitComboBox)
        self.__datasetSplitGroupBox.setLayout(self.__datasetSplitLayout)

        # Epochs form layout settings
        self.__epochsFormLayout = QFormLayout(self)
        self.__epochsGroupBox = QGroupBox(self)
        self.__epochsGroupBox.setObjectName("setting")
        self.__epochsFormLayout.addWidget(self.__epochsLabel)
        self.__epochsFormLayout.addWidget(self.__epochsLineEdit)
        self.__epochsGroupBox.setLayout(self.__epochsFormLayout)

        # Learning rate form layout settings
        self.__learningRateFormLayout = QFormLayout(self)
        self.__learningRateGroupBox = QGroupBox(self)
        self.__learningRateGroupBox.setObjectName("setting")
        self.__learningRateFormLayout.addWidget(self.__learningRateLabel)
        self.__learningRateFormLayout.addWidget(self.__learningRateCheckBox)
        self.__learningRateFormLayout.addWidget(self.__learningRateLineEdit)
        self.__learningRateGroupBox.setLayout(self.__learningRateFormLayout)

        # Epochs number label
        self.__epochNumberLabel = QLabel("Epoch : ", self)
        self.__epochNumberLabel.setFont((QFont("BebasNeue", 15, QFont.Bold)))

        # Training accuracy label
        self.__trainingAccuracyLabel = QLabel("Accuracy : ", self)
        self.__trainingAccuracyLabel.setFont((QFont("BebasNeue", 15,
                                                    QFont.Bold)))

        # Training stats layout
        self.__trainingStatsLayout = QVBoxLayout(self)
        self.__trainingStatsGroupBox = QGroupBox(self)
        self.__trainingStatsLayout.addWidget(self.__epochNumberLabel)
        self.__trainingStatsLayout.addWidget(self.__trainingAccuracyLabel)
        self.__trainingStatsGroupBox.setLayout(self.__trainingStatsLayout)
        self.__trainingStatsGroupBox.setGeometry(1000, -30, 300, 150)

        # Training button settings
        self.__trainingButton = QPushButton("Start", self)
        self.__trainingButton.setCursor(Qt.PointingHandCursor)
        self.__trainingButton.setFont((QFont("BebasNeue", 30, QFont.Bold)))
        self.__trainingButton.clicked.connect(self.startTraining)

        # Go back button
        self.goBackButton = QPushButton("Back", self)
        self.goBackButton.setObjectName("retour")

        # Customising go back button
        self.goBackButton.setCursor(Qt.PointingHandCursor)
        self.goBackButton.setIcon(QIcon("images/goback_icon"))
        self.goBackButton.setIconSize(QSize(30, 30))
        self.goBackButton.setFont(QFont("BebasNeue", 20, QFont.Bold))

        # Confusion matrix button
        self.__confusionMatrixButton = QPushButton("Show confusion matrix",
                                                   self)
        self.__confusionMatrixButton.setCursor(Qt.PointingHandCursor)
        self.__confusionMatrixButton.setFont((QFont("BebasNeue", 17,
                                                    QFont.Bold)))
        self.__confusionMatrixButton.clicked.connect(self.showStats)
        self.__confusionMatrixButton.setGeometry(420, 20, 250, 80)
        self.__confusionMatrixButton.hide()

        # Parameters group box settings
        self.__parametersGroupBox = QGroupBox("Training parameters", self)
        self.__parametersGroupBox.setObjectName("parameters")
        self.__parametersLayout = QVBoxLayout(self)
        self.__parametersLayout.addWidget(self.__epochsGroupBox)
        self.__parametersLayout.addWidget(self.__datasetSplitGroupBox)
        self.__parametersLayout.addWidget(
            self.__datasetSplitModeButtonsGroupBox)
        self.__parametersLayout.addWidget(self.__learningRateGroupBox)
        self.__parametersLayout.addWidget(self.__trainingButton)
        self.__parametersLayout.addWidget(self.goBackButton)
        self.__parametersGroupBox.setLayout(self.__parametersLayout)
        self.__parametersGroupBox.setGeometry(0, 0, 400, 720)

        # Chart axis settings
        self.__xAxis = QtCharts.QValueAxis()
        self.__xAxis.setRange(0, 5)

        self.__yAxis = QtCharts.QValueAxis()
        self.__yAxis.setRange(0, 100)

        # Chart settings
        self.__series = QtCharts.QLineSeries()
        self.__chart = QtCharts.QChart()
        self.__chart.addAxis(self.__xAxis, Qt.AlignBottom)
        self.__chart.addAxis(self.__yAxis, Qt.AlignLeft)
        self.__chart.addSeries(self.__series)
        self.__series.attachAxis(self.__xAxis)
        self.__series.attachAxis(self.__yAxis)
        self.__chart.setTitle("Accuracy")
        self.__chartView = QtCharts.QChartView(self.__chart)
        self.__chartView.setRenderHint(QPainter.Antialiasing)

        # Chart layout settings
        self.__chartLayout = QVBoxLayout(self)
        self.__chartGroupBox = QGroupBox(self)
        self.__chartGroupBox.setObjectName("chart")
        self.__chartLayout.addWidget(self.__chartView)
        self.__chartGroupBox.setLayout(self.__chartLayout)
        self.__chartGroupBox.setGeometry(390, 100, 900, 600)

        # Update timer settings
        #self.__timer = QTimer(self)
        #self.__timer.timeout.connect(self.autoSave)
        #self.__timer.start(1000)


#app = QApplication(sys.argv)
#window = TrainingWindow()
#window.show()
#app.exec_()
Esempio n. 19
0
class VideoPlayer(QWidget):
    def __init__(self, aPath, parent=None):
        super(VideoPlayer, self).__init__(parent)

        self.setAttribute(Qt.WA_NoSystemBackground, True)
        self.setAcceptDrops(True)
        self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.StreamPlayback)
        self.mediaPlayer.mediaStatusChanged.connect(self.printMediaData)
        self.mediaPlayer.setVolume(80)
        self.videoWidget = QVideoWidget(self)

        self.lbl = QLineEdit('00:00:00')
        self.lbl.setReadOnly(True)
        self.lbl.setFixedWidth(70)
        self.lbl.setUpdatesEnabled(True)
        self.lbl.setStyleSheet(stylesheet(self))
        self.lbl.selectionChanged.connect(lambda: self.lbl.setSelection(0, 0))

        self.elbl = QLineEdit('00:00:00')
        self.elbl.setReadOnly(True)
        self.elbl.setFixedWidth(70)
        self.elbl.setUpdatesEnabled(True)
        self.elbl.setStyleSheet(stylesheet(self))
        self.elbl.selectionChanged.connect(
            lambda: self.elbl.setSelection(0, 0))

        self.playButton = QPushButton()
        self.playButton.setEnabled(False)
        self.playButton.setFixedWidth(32)
        self.playButton.setStyleSheet("background-color: black")
        self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
        self.playButton.clicked.connect(self.play)

        self.positionSlider = QSlider(Qt.Horizontal, self)
        self.positionSlider.setStyleSheet(stylesheet(self))
        self.positionSlider.setRange(0, 100)
        self.positionSlider.sliderMoved.connect(self.setPosition)
        self.positionSlider.setSingleStep(2)
        self.positionSlider.setPageStep(20)
        self.positionSlider.setAttribute(Qt.WA_TranslucentBackground, True)

        self.clip = QApplication.clipboard()
        self.process = QProcess(self)
        self.process.readyRead.connect(self.dataReady)
        self.process.finished.connect(self.playFromURL)

        self.myurl = ""

        controlLayout = QHBoxLayout()
        controlLayout.setContentsMargins(5, 0, 5, 0)
        controlLayout.addWidget(self.playButton)
        controlLayout.addWidget(self.lbl)
        controlLayout.addWidget(self.positionSlider)
        controlLayout.addWidget(self.elbl)

        layout = QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(self.videoWidget)
        layout.addLayout(controlLayout)

        self.setLayout(layout)

        self.myinfo = "©2016\nAxel Schneider\n\nMouse Wheel = Zoom\nUP = Volume Up\nDOWN = Volume Down\n" + \
                "LEFT = < 1 Minute\nRIGHT = > 1 Minute\n" + \
                "SHIFT+LEFT = < 10 Minutes\nSHIFT+RIGHT = > 10 Minutes"

        self.widescreen = True

        #### shortcuts ####
        self.shortcut = QShortcut(QKeySequence("q"), self)
        self.shortcut.activated.connect(self.handleQuit)
        self.shortcut = QShortcut(QKeySequence("u"), self)
        self.shortcut.activated.connect(self.playFromURL)

        self.shortcut = QShortcut(QKeySequence("y"), self)
        self.shortcut.activated.connect(self.getYTUrl)

        self.shortcut = QShortcut(QKeySequence("o"), self)
        self.shortcut.activated.connect(self.openFile)
        self.shortcut = QShortcut(QKeySequence(" "), self)
        self.shortcut.activated.connect(self.play)
        self.shortcut = QShortcut(QKeySequence("f"), self)
        self.shortcut.activated.connect(self.handleFullscreen)
        self.shortcut = QShortcut(QKeySequence("i"), self)
        self.shortcut.activated.connect(self.handleInfo)
        self.shortcut = QShortcut(QKeySequence("s"), self)
        self.shortcut.activated.connect(self.toggleSlider)
        self.shortcut = QShortcut(QKeySequence(Qt.Key_Right), self)
        self.shortcut.activated.connect(self.forwardSlider)
        self.shortcut = QShortcut(QKeySequence(Qt.Key_Left), self)
        self.shortcut.activated.connect(self.backSlider)
        self.shortcut = QShortcut(QKeySequence(Qt.Key_Up), self)
        self.shortcut.activated.connect(self.volumeUp)
        self.shortcut = QShortcut(QKeySequence(Qt.Key_Down), self)
        self.shortcut.activated.connect(self.volumeDown)
        self.shortcut = QShortcut(
            QKeySequence(Qt.ShiftModifier + Qt.Key_Right), self)
        self.shortcut.activated.connect(self.forwardSlider10)
        self.shortcut = QShortcut(QKeySequence(Qt.ShiftModifier + Qt.Key_Left),
                                  self)
        self.shortcut.activated.connect(self.backSlider10)

        self.mediaPlayer.setVideoOutput(self.videoWidget)
        self.mediaPlayer.stateChanged.connect(self.mediaStateChanged)
        self.mediaPlayer.positionChanged.connect(self.positionChanged)
        self.mediaPlayer.durationChanged.connect(self.durationChanged)
        self.mediaPlayer.error.connect(self.handleError)

        print("QT5 Player started")
        print("press 'o' to open file (see context menu for more)")
        self.suspend_screensaver()

    def mouseDoubleClickEvent(self, event):
        self.handleFullscreen()

    def playFromURL(self):
        self.mediaPlayer.pause()
        self.myurl = self.clip.text()
        self.mediaPlayer.setMedia(QMediaContent(QUrl(self.myurl)))
        self.playButton.setEnabled(True)
        self.mediaPlayer.play()
        self.hideSlider()
        print(self.myurl)

    def getYTUrl(self):
        cmd = "youtube-dl -g -f best " + self.clip.text()
        print("grabbing YouTube URL")
        self.process.start(cmd)

    def dataReady(self):
        self.myurl = str(self.process.readAll(), encoding='utf8').rstrip()  ###
        self.myurl = self.myurl.partition("\n")[0]
        print(self.myurl)
        self.clip.setText(self.myurl)
        self.playFromURL()

    def suspend_screensaver(self):
        'suspend linux screensaver'
        proc = subprocess.Popen(
            'gsettings set org.gnome.desktop.screensaver idle-activation-enabled false',
            shell=True)
        proc.wait()

    def resume_screensaver(self):
        'resume linux screensaver'
        proc = subprocess.Popen(
            'gsettings set org.gnome.desktop.screensaver idle-activation-enabled true',
            shell=True)
        proc.wait()

    def openFile(self):
        fileName, _ = QFileDialog.getOpenFileName(
            self, "Open Movie",
            QDir.homePath() + "/Videos",
            "Media (*.webm *.mp4 *.ts *.avi *.mpeg *.mpg *.mkv *.VOB *.m4v *.3gp *.mp3 *.m4a *.wav *.ogg *.flac *.m3u *.m3u8)"
        )

        if fileName != '':
            self.loadFilm(fileName)
            print("File loaded")

    def play(self):
        if self.mediaPlayer.state() == QMediaPlayer.PlayingState:
            self.mediaPlayer.pause()
        else:
            self.mediaPlayer.play()

    def mediaStateChanged(self, state):
        if self.mediaPlayer.state() == QMediaPlayer.PlayingState:
            self.playButton.setIcon(self.style().standardIcon(
                QStyle.SP_MediaPause))
        else:
            self.playButton.setIcon(self.style().standardIcon(
                QStyle.SP_MediaPlay))

    def positionChanged(self, position):
        self.positionSlider.setValue(position)
        mtime = QTime(0, 0, 0, 0)
        mtime = mtime.addMSecs(self.mediaPlayer.position())
        self.lbl.setText(mtime.toString())

    def durationChanged(self, duration):
        self.positionSlider.setRange(0, duration)
        mtime = QTime(0, 0, 0, 0)
        mtime = mtime.addMSecs(self.mediaPlayer.duration())
        self.elbl.setText(mtime.toString())

    def setPosition(self, position):
        self.mediaPlayer.setPosition(position)

    def handleError(self):
        self.playButton.setEnabled(False)
        print("Error: ", self.mediaPlayer.errorString())

    def handleQuit(self):
        self.mediaPlayer.stop()
        self.resume_screensaver()
        print("Goodbye ...")
        app.quit()

    def contextMenuRequested(self, point):
        menu = QMenu()
        actionFile = menu.addAction(QIcon.fromTheme("video-x-generic"),
                                    "open File (o)")
        actionclipboard = menu.addSeparator()
        actionURL = menu.addAction(QIcon.fromTheme("browser"),
                                   "URL from Clipboard (u)")
        actionclipboard = menu.addSeparator()
        actionYTurl = menu.addAction(QIcon.fromTheme("youtube"),
                                     "URL from YouTube (y)")
        actionclipboard = menu.addSeparator()
        actionToggle = menu.addAction(QIcon.fromTheme("next"),
                                      "show / hide Slider (s)")
        actionFull = menu.addAction(QIcon.fromTheme("view-fullscreen"),
                                    "Fullscreen (f)")
        action169 = menu.addAction(QIcon.fromTheme("tv-symbolic"), "16 : 9")
        action43 = menu.addAction(QIcon.fromTheme("tv-symbolic"), "4 : 3")
        actionSep = menu.addSeparator()
        actionInfo = menu.addAction(QIcon.fromTheme("help-about"), "Info (i)")
        action5 = menu.addSeparator()
        actionQuit = menu.addAction(QIcon.fromTheme("application-exit"),
                                    "Exit (q)")

        actionFile.triggered.connect(self.openFile)
        actionQuit.triggered.connect(self.handleQuit)
        actionFull.triggered.connect(self.handleFullscreen)
        actionInfo.triggered.connect(self.handleInfo)
        actionToggle.triggered.connect(self.toggleSlider)
        actionURL.triggered.connect(self.playFromURL)
        actionYTurl.triggered.connect(self.getYTUrl)
        action169.triggered.connect(self.screen169)
        action43.triggered.connect(self.screen43)
        menu.exec_(self.mapToGlobal(point))

    def wheelEvent(self, event):
        mwidth = self.frameGeometry().width()
        mheight = self.frameGeometry().height()
        mleft = self.frameGeometry().left()
        mtop = self.frameGeometry().top()
        mscale = event.angleDelta().y() / 5
        if self.widescreen == True:
            self.setGeometry(mleft, mtop, mwidth + mscale,
                             round((mwidth + mscale) / 1.778))
        else:
            self.setGeometry(mleft, mtop, mwidth + mscale,
                             round((mwidth + mscale) / 1.33))
        #elif self.positionSlider.hasFocus():
        #    self.positionSlider.value = self.positionSlider.value + 5

    def screen169(self):
        self.widescreen = True
        mwidth = self.frameGeometry().width()
        mheight = self.frameGeometry().height()
        mleft = self.frameGeometry().left()
        mtop = self.frameGeometry().top()
        mratio = 1.778
        self.setGeometry(mleft, mtop, mwidth, round(mwidth / mratio))

    def screen43(self):
        self.widescreen = False
        mwidth = self.frameGeometry().width()
        mheight = self.frameGeometry().height()
        mleft = self.frameGeometry().left()
        mtop = self.frameGeometry().top()
        mratio = 1.33
        self.setGeometry(mleft, mtop, mwidth, round(mwidth / mratio))

    def handleFullscreen(self):
        if self.windowState() & Qt.WindowFullScreen:
            QApplication.setOverrideCursor(Qt.ArrowCursor)
            self.showNormal()
            print("no Fullscreen")
        else:
            self.showFullScreen()
            QApplication.setOverrideCursor(Qt.BlankCursor)
            print("Fullscreen entered")

    def handleInfo(self):
        msg = QMessageBox.about(self, "QT5 Player", self.myinfo)

    def toggleSlider(self):
        if self.positionSlider.isVisible():
            self.hideSlider()
        else:
            self.showSlider()

    def hideSlider(self):
        self.playButton.hide()
        self.lbl.hide()
        self.positionSlider.hide()
        self.elbl.hide()
        mwidth = self.frameGeometry().width()
        mheight = self.frameGeometry().height()
        mleft = self.frameGeometry().left()
        mtop = self.frameGeometry().top()
        if self.widescreen == True:
            self.setGeometry(mleft, mtop, mwidth, round(mwidth / 1.778))
        else:
            self.setGeometry(mleft, mtop, mwidth, round(mwidth / 1.33))

    def showSlider(self):
        self.playButton.show()
        self.lbl.show()
        self.positionSlider.show()
        self.elbl.show()
        mwidth = self.frameGeometry().width()
        mheight = self.frameGeometry().height()
        mleft = self.frameGeometry().left()
        mtop = self.frameGeometry().top()
        if self.widescreen == True:
            self.setGeometry(mleft, mtop, mwidth, round(mwidth / 1.55))
        else:
            self.setGeometry(mleft, mtop, mwidth, round(mwidth / 1.33))

    def forwardSlider(self):
        self.mediaPlayer.setPosition(self.mediaPlayer.position() + 1000 * 60)

    def forwardSlider10(self):
        self.mediaPlayer.setPosition(self.mediaPlayer.position() + 10000 * 60)

    def backSlider(self):
        self.mediaPlayer.setPosition(self.mediaPlayer.position() - 1000 * 60)

    def backSlider10(self):
        self.mediaPlayer.setPosition(self.mediaPlayer.position() - 10000 * 60)

    def volumeUp(self):
        self.mediaPlayer.setVolume(self.mediaPlayer.volume() + 10)
        print("Volume: " + str(self.mediaPlayer.volume()))

    def volumeDown(self):
        self.mediaPlayer.setVolume(self.mediaPlayer.volume() - 10)
        print("Volume: " + str(self.mediaPlayer.volume()))

    def mousePressEvent(self, evt):
        self.oldPos = evt.globalPos()

    def mouseMoveEvent(self, evt):
        delta = QPoint(evt.globalPos() - self.oldPos)
        self.move(self.x() + delta.x(), self.y() + delta.y())
        self.oldPos = evt.globalPos()

    def dragEnterEvent(self, event):
        if event.mimeData().hasUrls():
            event.accept()
        elif event.mimeData().hasText():
            event.accept()
        else:
            event.ignore()

    def dropEvent(self, event):
        print("drop")
        if event.mimeData().hasUrls():
            url = event.mimeData().urls()[0].toString()
            print("url = ", url)
            self.mediaPlayer.stop()
            self.mediaPlayer.setMedia(QMediaContent(QUrl(url)))
            self.playButton.setEnabled(True)
            self.mediaPlayer.play()
        elif event.mimeData().hasText():
            mydrop = event.mimeData().text()
            ### YouTube url
            if "youtube" in mydrop:
                print("is YouTube", mydrop)
                self.clip.setText(mydrop)
                self.getYTUrl()
            else:
                ### normal url
                print("generic url = ", mydrop)
                self.mediaPlayer.setMedia(QMediaContent(QUrl(mydrop)))
                self.playButton.setEnabled(True)
                self.mediaPlayer.play()
                self.hideSlider()

    def loadFilm(self, f):
        self.mediaPlayer.setMedia(QMediaContent(QUrl.fromLocalFile(f)))
        self.playButton.setEnabled(True)
        self.mediaPlayer.play()

    def printMediaData(self):
        if self.mediaPlayer.mediaStatus() == 6:
            if self.mediaPlayer.isMetaDataAvailable():
                res = str(self.mediaPlayer.metaData("Resolution")).partition(
                    "PyQt5.QtCore.QSize(")[2].replace(", ",
                                                      "x").replace(")", "")
                print("%s%s" % ("Video Resolution = ", res))
                if int(res.partition("x")[0]) / int(
                        res.partition("x")[2]) < 1.5:
                    self.screen43()
                else:
                    self.screen169()
            else:
                print("no metaData available")

    def openFileAtStart(self, filelist):
        matching = [s for s in filelist if ".myformat" in s]
        if len(matching) > 0:
            self.loadFilm(matching)
Esempio n. 20
0
class App(QWidget):
    def __init__(self, bk, prefs):
        super().__init__()

        self.bk = bk
        self.prefs = prefs
        self.update = False

        # Install translator for the DOCXImport plugin dialog.
        # Use the Sigil language setting unless manually overridden.
        plugin_translator = QTranslator()
        if prefs['language_override'] is not None:
            print('Plugin preferences language override in effect')
            qmf = '{}_{}'.format(bk._w.plugin_name.lower(),
                                 prefs['language_override'])
        else:
            qmf = '{}_{}'.format(bk._w.plugin_name.lower(), bk.sigil_ui_lang)
        print(
            qmf,
            os.path.join(bk._w.plugin_dir, bk._w.plugin_name, 'translations'))
        plugin_translator.load(
            qmf,
            os.path.join(bk._w.plugin_dir, bk._w.plugin_name, 'translations'))
        print(QCoreApplication.instance().installTranslator(plugin_translator))

        self._ok_to_close = False

        self.FTYPE_MAP = {
            'smap': {
                'title': _translate('App', 'Select custom style-map file'),
                'defaultextension': '.txt',
                'filetypes': 'Text Files (*.txt);;All files (*.*)',
            },
            'css': {
                'title': _translate('App', 'Select custom CSS file'),
                'defaultextension': '.css',
                'filetypes': 'CSS Files (*.css)',
            },
            'docx': {
                'title': _translate('App', 'Select DOCX file'),
                'defaultextension': '.docx',
                'filetypes': 'DOCX Files (*.docx)',
            },
        }

        # Check online github files for newer version
        if self.prefs['check_for_updates']:
            self.update, self.newversion = self.check_for_update()
        self.initUI()

    def initUI(self):
        main_layout = QVBoxLayout(self)

        self.setWindowTitle('DOCXImport')
        self.upd_layout = QVBoxLayout()
        self.update_label = QLabel()
        self.update_label.setAlignment(Qt.AlignCenter)
        self.upd_layout.addWidget(self.update_label)
        self.get_update_button = QPushButton()
        self.get_update_button.clicked.connect(self.get_update)
        self.upd_layout.addWidget(self.get_update_button)
        main_layout.addLayout(self.upd_layout)
        if not self.update:
            self.update_label.hide()
            self.get_update_button.hide()

        self.details_grid = QGridLayout()
        self.epub2_select = QRadioButton()
        self.epub2_select.setText('EPUB2')
        self.epubType = QButtonGroup()
        self.epubType.addButton(self.epub2_select)
        self.details_grid.addWidget(self.epub2_select, 0, 0, 1, 1)
        self.checkbox_get_updates = QCheckBox()
        self.details_grid.addWidget(self.checkbox_get_updates, 0, 1, 1, 1)
        self.epub3_select = QRadioButton()
        self.epub3_select.setText('EPUB3')
        self.epubType.addButton(self.epub3_select)
        self.details_grid.addWidget(self.epub3_select, 1, 0, 1, 1)
        main_layout.addLayout(self.details_grid)
        self.checkbox_get_updates.setChecked(self.prefs['check_for_updates'])
        if self.prefs['epub_version'] == '2.0':
            self.epub2_select.setChecked(True)
        elif self.prefs['epub_version'] == '3.0':
            self.epub3_select.setChecked(True)
        else:
            self.epub2_select.setChecked(True)

        self.groupBox = QGroupBox()
        self.groupBox.setTitle('')
        self.verticalLayout_2 = QVBoxLayout(self.groupBox)
        self.docx_grid = QGridLayout()
        self.docx_label = QLabel()
        self.docx_grid.addWidget(self.docx_label, 0, 0, 1, 1)
        self.docx_path = QLineEdit()
        self.docx_grid.addWidget(self.docx_path, 1, 0, 1, 1)
        self.choose_docx_button = QPushButton()
        self.choose_docx_button.setText('...')
        self.docx_grid.addWidget(self.choose_docx_button, 1, 1, 1, 1)
        self.verticalLayout_2.addLayout(self.docx_grid)
        self.choose_docx_button.clicked.connect(
            lambda: self.fileChooser('docx', self.docx_path))
        if len(self.prefs['lastDocxPath']):
            self.docx_path.setText(self.prefs['lastDocxPath'])
        self.docx_path.setEnabled(False)

        self.smap_grid = QGridLayout()
        self.checkbox_smap = QCheckBox(self.groupBox)
        self.smap_grid.addWidget(self.checkbox_smap, 0, 0, 1, 1)
        self.cust_smap_path = QLineEdit(self.groupBox)
        self.smap_grid.addWidget(self.cust_smap_path, 1, 0, 1, 1)
        self.choose_smap_button = QPushButton(self.groupBox)
        self.choose_smap_button.setText('...')
        self.smap_grid.addWidget(self.choose_smap_button, 1, 1, 1, 1)
        self.verticalLayout_2.addLayout(self.smap_grid)
        self.checkbox_smap.setChecked(self.prefs['useSmap'])
        self.checkbox_smap.stateChanged.connect(lambda: self.chkBoxActions(
            self.checkbox_smap, self.choose_smap_button))
        self.choose_smap_button.clicked.connect(
            lambda: self.fileChooser('smap', self.cust_smap_path, self.
                                     checkbox_smap, self.choose_smap_button))
        if len(self.prefs['useSmapPath']):
            self.cust_smap_path.setText(self.prefs['useSmapPath'])
        self.cust_smap_path.setEnabled(False)
        self.chkBoxActions(self.checkbox_smap, self.choose_smap_button)

        self.css_grid = QGridLayout()
        self.checkbox_css = QCheckBox(self.groupBox)
        self.css_grid.addWidget(self.checkbox_css, 0, 0, 1, 1)
        self.cust_css_path = QLineEdit(self.groupBox)
        self.css_grid.addWidget(self.cust_css_path, 1, 0, 1, 1)
        self.choose_css_button = QPushButton(self.groupBox)
        self.choose_css_button.setText('...')
        self.css_grid.addWidget(self.choose_css_button, 1, 1, 1, 1)
        self.verticalLayout_2.addLayout(self.css_grid)
        self.checkbox_css.setChecked(self.prefs['useCss'])
        self.checkbox_css.stateChanged.connect(lambda: self.chkBoxActions(
            self.checkbox_css, self.choose_css_button))
        self.choose_css_button.clicked.connect(
            lambda: self.fileChooser('css', self.cust_css_path, self.
                                     checkbox_css, self.choose_css_button))
        if len(self.prefs['useCssPath']):
            self.cust_css_path.setText(self.prefs['useCssPath'])
        self.cust_css_path.setEnabled(False)
        self.chkBoxActions(self.checkbox_css, self.choose_css_button)

        main_layout.addWidget(self.groupBox)
        self.checkbox_debug = QCheckBox()
        main_layout.addWidget(self.checkbox_debug)
        self.checkbox_debug.setChecked(self.prefs['debug'])

        spacerItem = QSpacerItem(20, 15, QSizePolicy.Minimum,
                                 QSizePolicy.Expanding)
        main_layout.addItem(spacerItem)

        button_box = QDialogButtonBox(QDialogButtonBox.Ok
                                      | QDialogButtonBox.Cancel)
        button_box.accepted.connect(self._ok_clicked)
        button_box.rejected.connect(self._cancel_clicked)
        main_layout.addWidget(button_box)
        self.retranslateUi(self)
        if self.prefs['qt_geometry'] is not None:
            try:
                self.restoreGeometry(
                    QByteArray.fromHex(
                        self.prefs['qt_geometry'].encode('ascii')))
            except:
                pass
        self.show()

    def retranslateUi(self, App):
        self.update_label.setText(_translate('App', 'Plugin Update Available'))
        self.get_update_button.setText(_translate('App',
                                                  'Go to download page'))
        self.checkbox_get_updates.setText(
            _translate('App', 'Check for plugin updates'))
        self.docx_label.setText(_translate('App', 'DOCX File to import'))
        self.checkbox_smap.setText(_translate('App', 'Use Custom Style Map'))
        self.checkbox_css.setText(_translate('App', 'Use Custom CSS'))
        self.checkbox_debug.setText(
            _translate('App',
                       'Debug Mode (change takes effect next plugin run)'))

    def fileChooser(self, ftype, qlineedit, qcheck=None, qbutton=None):
        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        title = self.FTYPE_MAP[ftype]['title']
        startfolder = self.prefs['lastDir'][ftype]
        ffilter = self.FTYPE_MAP[ftype]['filetypes']
        inpath, _ = QFileDialog.getOpenFileName(self,
                                                title,
                                                startfolder,
                                                ffilter,
                                                options=options)
        if len(inpath):
            qlineedit.setEnabled(True)
            qlineedit.setText(os.path.normpath(inpath))
            self.prefs['lastDir'][ftype] = os.path.dirname(inpath)
            qlineedit.setEnabled(False)
        else:
            if qcheck is not None:
                qcheck.setChecked(False)
            if qbutton is not None:
                qbutton.setEnabled(False)

    def chkBoxActions(self, chk, btn):
        btn.setEnabled(chk.isChecked())

    def cmdDo(self):
        global _DETAILS
        self.prefs['qt_geometry'] = self.saveGeometry().toHex().data().decode(
            'ascii')
        self.prefs['check_for_updates'] = self.checkbox_get_updates.isChecked()
        self.prefs['epub_version'] = self.epubType.checkedButton().text(
        )[-1] + '.0'
        self.prefs['debug'] = self.checkbox_debug.isChecked()
        _DETAILS['vers'] = self.epubType.checkedButton().text()[-1] + '.0'
        self.prefs['useSmap'] = self.checkbox_smap.isChecked()
        if self.checkbox_smap.isChecked():
            if len(self.cust_smap_path.text()):
                self.prefs['useSmapPath'] = self.cust_smap_path.text()
                _DETAILS['smap'] = (self.checkbox_smap.isChecked(),
                                    self.cust_smap_path.text())
            else:
                # Message box that no file is selected
                return
        self.prefs['useCss'] = self.checkbox_css.isChecked()
        if self.checkbox_css.isChecked():
            if len(self.cust_css_path.text()):
                self.prefs['useCssPath'] = self.cust_css_path.text()
                _DETAILS['css'] = (self.checkbox_css.isChecked(),
                                   self.cust_css_path.text())
            else:
                # Message box that no file is selected
                return
        if len(self.docx_path.text()):
            self.prefs['lastDocxPath'] = self.docx_path.text()
            _DETAILS['docx'] = self.docx_path.text()
        else:
            # Message box that no file is selected
            return

    def check_for_update(self):
        '''Use updatecheck.py to check for newer versions of the plugin'''
        chk = UpdateChecker(self.prefs['last_time_checked'], self.bk._w)
        update_available, online_version, time = chk.update_info()
        # update preferences with latest date/time/version
        self.prefs['last_time_checked'] = time
        if online_version is not None:
            self.prefs['last_online_version'] = online_version
        if update_available:
            return (True, online_version)
        return (False, online_version)

    def get_update(self):
        url = DOWNLOAD_PAGE
        if self.update:
            latest = '/tag/v{}'.format(self.newversion)
            url = url + latest
        webbrowser.open_new_tab(url)

    def _ok_clicked(self):
        self._ok_to_close = True
        self.cmdDo()
        self.bk.savePrefs(self.prefs)
        QCoreApplication.instance().quit()

    def _cancel_clicked(self):
        self._ok_to_close = True
        '''Close aborting any changes'''
        self.prefs['qt_geometry'] = self.saveGeometry().toHex().data().decode(
            'ascii')
        self.prefs['check_for_updates'] = self.checkbox_get_updates.isChecked()
        self.prefs['debug'] = self.checkbox_debug.isChecked()
        self.bk.savePrefs(self.prefs)
        QCoreApplication.instance().quit()

    def closeEvent(self, event):
        if self._ok_to_close:
            event.accept()  # let the window close
        else:
            self._cancel_clicked()
Esempio n. 21
0
class CameraPanel(QWidget):
    __obj = None

    def __init__(self, n_camera, app: QApplication, *args, **kwargs):
        if CameraPanel.__obj is not None:
            raise type(
                'InstanceExists', (Exception, ),
                {})('A CameraPanel instance has already been constructed.')
        CameraPanel.__obj = self
        super().__init__(*args, **kwargs)
        self.cameras = []
        self.box = QVBoxLayout()
        self.setLayout(self.box)

        Configuration(n_camera, self)
        TrafficMonitor(n_camera)
        FrameRateMonitor(n_camera)
        FrameDropMonitor(n_camera)

        self.connectButton = QPushButton("Connect")
        self.connectButton.clicked.connect(self.connectRemote)
        self.reconnecting = QLabel("Disconnected. Trying to reconnect")
        self.reconnecting.setWordWrap(True)
        self.total_traffic = QLabel("0.000 KB/s")
        self.restart_remote = QPushButton("Restart Remote")
        self.restart_remote.setSizePolicy(QSizePolicy.Maximum,
                                          QSizePolicy.Expanding)
        self.restart_remote.clicked.connect(self.restartRemote)
        self.scan = QPushButton("Scan")
        self.scan.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Expanding)
        self.scan.clicked.connect(Configuration().scan)

        self.top_frame = QFrame()
        self.top_frame.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Maximum)
        self.top_grid = QGridLayout()
        self.top_grid.setContentsMargins(0, 0, 0, 0)
        self.top_frame.setLayout(self.top_grid)

        self.top_grid.addWidget(self.connectButton, 0, 1)
        self.top_grid.addWidget(self.reconnecting, 0, 1)
        self.top_grid.addWidget(self.total_traffic, 0, 1)
        self.top_grid.addWidget(self.restart_remote, 0, 2)
        self.top_grid.addWidget(self.scan, 0, 0)

        self.total_traffic.hide()
        self.reconnecting.hide()

        self.box.addWidget(self.top_frame)

        self.timer = QTimer()
        self.timer.timeout.connect(self.updateTraffic)
        self.timer.start(100)

        for i in range(n_camera):
            self.cameras.append(Camera(i, app))

        main_splitter = QSplitter(Qt.Horizontal)
        main_splitter.addWidget(self.cameras[0])
        if n_camera == 2:
            main_splitter.addWidget(self.cameras[1])
        elif n_camera == 3:
            sub_splitter = QSplitter(Qt.Horizontal)
            sub_splitter.addWidget(self.cameras[1])
            sub_splitter.addWidget(self.cameras[2])
            main_splitter.addWidget(sub_splitter)
        elif n_camera == 4:
            sub_splitter = QSplitter(Qt.Horizontal)
            sub_sub_splitter = QSplitter(Qt.Horizontal)
            sub_splitter.addWidget(sub_sub_splitter)
            sub_sub_splitter.addWidget(self.cameras[1])
            sub_sub_splitter.addWidget(self.cameras[2])
            sub_splitter.addWidget(self.cameras[3])
            main_splitter.addWidget(sub_splitter)

        self.box.addWidget(main_splitter)

    def connectRemote(self):
        """
        This function blocks until TCP connection succeeds.
        Call with caution
        """
        if Configuration().connect():
            self.connectButton.hide()
            self.total_traffic.show()
            for cam in self.cameras:
                cam.startReceiving()
                cam.mode_selection.setEnabled(True)
                cam.updateMode(cam.mode_selection.currentIndex())

    def restartRemote(self):
        os.system(
            f'ssh root@{REMOTE_IP_ADDR} systemctl restart vision-server.service'
        )
        if self.connectButton.isVisible():
            self.connectRemote()
        else:
            Configuration().reconnect()

    def updateTraffic(self):
        self.total_traffic.setText('{:<4} KB/s'.format(
            round(TrafficMonitor().total / 1024, 2)))
Esempio n. 22
0
class TrainWindow(QWidget):
    '''
    The TrainWindow class is a PySide2 Graphical User Interface (GUI) window
    that is called by MainWindow class in order to configure a custom training
    session and initiates training for a selected Precision-Level.
    '''
    def __init__(self, debug=False):
        '''
        The constructor.
        Sets the size of the window and configurations for a training session.
        Calls setButtons function to populate window with button.
        '''
        super().__init__()

        self.debug = debug

        self._TRAIN_WIN_H = 500
        self._TRAIN_WIN_W = 500

        self.model_name = ''
        self._model_list = []
        self._label_list = []
        self._precision_level = 1

        self._path_to_dataset = ''
        self._path_to_label_list = ''
        self._is_valid_dataset = False
        self.buttonConnected = False

        self.label_process = None

        self._is_model_ready = False
        self._is_dataset_linked = False
        self._is_dataset_labelled = False
        self._is_labellist_linked = False

        self.label_train_process = None
        self.label_val_process = None

        self.setWindowTitle('Train')
        self.setGeometry(self._TRAIN_WIN_W * 2, 0, self._TRAIN_WIN_W,
                         self._TRAIN_WIN_H)
        self.setFixedSize(self._TRAIN_WIN_W, self._TRAIN_WIN_H)

        self.setButtons()

    def setButtons(self):
        '''A Mutator function that defines all buttons in TrainWindow.'''
        self.p1_button = QPushButton('P1', self)
        self.p1_button.setGeometry(0, 0, 50, 100)
        self.p1_button.setStyleSheet(
            'background-color: rgba(180,180,180,255);')

        self.p2_button = QPushButton('P2', self)
        self.p2_button.setGeometry(50, 0, 50, 100)

        self.p3_button = QPushButton('P3', self)
        self.p3_button.setGeometry(100, 0, 50, 100)

        # Model dropdown menu to select Precision Level specific model
        self.model_selector = QComboBox(self)
        self.model_selector.setGeometry(self._TRAIN_WIN_W - 150, 0, 150, 100)
        self.model_selector.setStyleSheet('background-color: red;')
        self.populateModelSelector()

        self.model_selector_label = QLabel(self)
        self.model_selector_label.setText('Choose Model =')
        self.model_selector_label.move(220, 40)

        # Labeller button to initiate labelme
        self.label_button = QPushButton('Label Dataset', self)
        self.label_button.setIcon(QIcon('img/label.png'))
        self.label_button.setIconSize(QSize(50, 50))
        self.label_button.setGeometry(0, 200, self._TRAIN_WIN_W / 2, 100)
        self.label_button.setStyleSheet(
            'background-color: rgba(0,200,10,255);')
        if self._precision_level == 1:
            self.label_button.hide()

        self.generate_button = QPushButton('Generate Dataset', self)
        self.generate_button.setIcon(QIcon('img/label.png'))
        self.generate_button.setIconSize(QSize(50, 50))
        self.generate_button.setGeometry(self._TRAIN_WIN_W / 2, 200,
                                         self._TRAIN_WIN_W / 2, 100)
        self.generate_button.setStyleSheet(
            'background-color: rgba(0,200,10,255);')
        if self._precision_level == 1:
            self.generate_button.hide()

        # Labeller button to initiate labelme
        self.validate_button = QPushButton('Validate Dataset', self)
        self.validate_button.setIcon(QIcon('img/validate.png'))
        self.validate_button.setIconSize(QSize(50, 50))
        self.validate_button.setGeometry(self._TRAIN_WIN_W / 2, 300,
                                         self._TRAIN_WIN_W / 2, 100)

        # Dataset button to prompt input via FileDialogue
        self.dataset_button = QPushButton('Choose Dataset', self)
        self.dataset_button.setIcon(QIcon('img/dataset.png'))
        self.dataset_button.setIconSize(QSize(50, 50))
        self.dataset_button.setGeometry(0, 300, self._TRAIN_WIN_W / 2, 100)
        self.dataset_button.setStyleSheet('background-color: red;')

        # Start Training button to start and display training process
        self.train_button = QPushButton('Train', self)
        self.train_button.setIcon(QIcon('img/train.png'))
        self.train_button.setIconSize(QSize(75, 75))
        self.train_button.setGeometry(0, self._TRAIN_WIN_H - 100,
                                      self._TRAIN_WIN_W, 100)
        self.train_button.setStyleSheet(
            'background-color: rgba(180,180,180,255);')

        # Set Label List
        self.list_button = QPushButton('Choose Label List', self)
        self.list_button.setIcon(QIcon('img/label_list.png'))
        self.list_button.setIconSize(QSize(75, 75))
        self.list_button.setGeometry(0, 100, self._TRAIN_WIN_W, 100)
        self.list_button.setStyleSheet('background-color: rgba(200,10,0,255);')

        self.p1_button.clicked.connect(self.setP1)
        self.p2_button.clicked.connect(self.setP2)
        self.p3_button.clicked.connect(self.setP3)

        self.model_selector.activated.connect(self.setModel)
        self.dataset_button.clicked.connect(self.setDataset)
        self.label_button.clicked.connect(self.runLabelme)
        self.generate_button.clicked.connect(self.conformDatasetToCOCO)
        self.validate_button.clicked.connect(self.validateDataset)
        self.list_button.clicked.connect(self.setLabelList)

    def setP1(self):
        '''A function that is triggered by the button labelled, P1.'''
        self._precision_level = 1
        self.populateModelSelector()
        self.initModel()
        self.label_button.hide()
        self.generate_button.hide()
        self.p1_button.setStyleSheet(
            'background-color: rgba(180,180,180,255);')
        self.p2_button.setStyleSheet('background-color: white;')
        self.p3_button.setStyleSheet('background-color: white;')
        self.disconnectTrainingButton()
        print('Set Precision Level at: ', self._precision_level)

    def setP2(self):
        '''A function that is triggered by the button labelled, P2.'''
        self._precision_level = 2
        self.populateModelSelector()
        self.initModel()
        self.label_button.show()
        self.generate_button.show()
        self.p2_button.setStyleSheet(
            'background-color: rgba(180,180,180,255);')
        self.p1_button.setStyleSheet('background-color: white;')
        self.p3_button.setStyleSheet('background-color: white;')
        self.disconnectTrainingButton()
        print('Set Precision Level at: ', self._precision_level)

    def setP3(self):
        '''A function that is triggered by the button labelled, P3.'''
        self._precision_level = 3
        self.populateModelSelector()
        self.initModel()
        self.label_button.show()
        self.generate_button.show()
        self.p3_button.setStyleSheet(
            'background-color: rgba(180,180,180,255);')
        self.p1_button.setStyleSheet('background-color: white;')
        self.p2_button.setStyleSheet('background-color: white;')
        self.disconnectTrainingButton()
        print('Set Precision Level at: ', self._precision_level)

    def setModel(self, index):
        '''A function that is triggered by the DropDown Menu labelled, Model.'''
        self.model_name = self.model_selector.itemText(index)

        self.model_selector.setStyleSheet(
            'background-color: rgba(0,200,10,255);')
        self._is_model_ready = True
        self.validateTraining()
        print('Set Model to ', self.model_name)

    def setLabelList(self):
        '''A function that is triggered by the button labelled, Choose Label List.'''
        if not self.debug:
            input_classes_filepath, ok = QFileDialog.getOpenFileName(
                self, 'Set the .txt to use', os.path.abspath('../data'),
                'Text Files (*.txt)')
        else:
            input_classes_filepath = '../data/label_list/coco_classes.txt'
            ok = True

        if ok:
            self._path_to_label_list = input_classes_filepath
            self._label_list = [
                line.rstrip('\n') for line in open(input_classes_filepath)
            ]
        else:
            print('No label list set.')
            return
        self.list_button.setStyleSheet('background-color: rgba(0,150,10,255);')
        self._is_labellist_linked = True
        self.validateTraining()

    def setDataset(self):
        '''A function that is triggered by the button labelled, Choose Dataset.'''
        if not self.debug:
            new_filepath_to_dataset = (QFileDialog.getExistingDirectory(
                self, 'Set directory of the dataset',
                os.path.abspath('../data'), QFileDialog.ShowDirsOnly
                | QFileDialog.DontResolveSymlinks))

        else:
            new_filepath_to_dataset = '../data/datasets'

        if os.path.isdir(new_filepath_to_dataset):
            self._path_to_dataset = new_filepath_to_dataset
            # Set button color to green
            self._is_dataset_linked = True
            self.dataset_button.setStyleSheet(
                'background-color: rgba(0,200,10,255);')
        else:
            # Set button color to red
            print('Dataset path does not exist.')
            self.dataset_button.setStyleSheet('background-color: red;')

        self.validateTraining()

    def runLabelme(self):
        '''A function that is triggered by the button labelled, Label Dataset.'''
        self.label_process = subprocess.Popen(['labelme'])
        self.validateTraining()

    def initModel(self):
        '''
        A Mutator function that sets the model_name to the first model available
        whenever the precision level changes.
        '''
        self.model_name = self._model_list[0]
        self._is_model_ready = True
        print('Set Model to ', self.model_name)

    def validateTraining(self):
        '''
        A Mutator function that evaulates necessary boolean flags that are all
        required to allow proper training given a certain requested precision level.
        '''
        # Perform 4 checks to ensure all data is available for Training to start without issue.

        if not self._is_model_ready:
            print('No model provided. Please choose Model.')
            self.train_button.setStyleSheet(
                'background-color: rgba(180,180,180,255);')
            self.disconnectTrainingButton()
            return
        if not self._is_dataset_linked:
            print('Dataset directory not provided. Please choose Dataset.')
            self.train_button.setStyleSheet(
                'background-color: rgba(180,180,180,255);')
            self.disconnectTrainingButton()
            return
        if not self._is_labellist_linked:
            print('Label List not provided. Please choose Label List.')
            self.train_button.setStyleSheet(
                'background-color: rgba(180,180,180,255);')
            self.disconnectTrainingButton()
            return

        if not self._is_dataset_labelled:
            print(
                'Dataset not properly restructured. Please restructure Dataset.'
            )
            self.train_button.setStyleSheet(
                'background-color: rgba(180,180,180,255);')
            self.disconnectTrainingButton()
            return

        # Precision Level 1 only requires 4 checks.
        if self._precision_level == 1:
            print('Precision 1 Training Ready.')
            self.train_button.setStyleSheet('background-color: white;')
            self.connectTrainingButton()
            return

        if not self._is_dataset_labelled:
            print('Dataset not labelled properly. Please label Dataset.')
            self.train_button.setStyleSheet(
                'background-color: rgba(180,180,180,255);')
            self.disconnectTrainingButton()
            return

        self.train_button.setStyleSheet('background-color: white;')
        self.connectTrainingButton()

    def validateDataset(self):
        '''A function that is triggered by the button labelled, Validate Dataset.'''
        if self._precision_level == 1:
            trainDirExists = os.path.exists(self._path_to_dataset + '/train')
            valDirExists = os.path.exists(self._path_to_dataset + '/val')
            # Check if the dataset folder has the following structure
            if trainDirExists and valDirExists:
                self._is_dataset_labelled = True
                self.validate_button.setStyleSheet(
                    'background-color: rgba(0,200,10,255);')
            else:
                self._is_dataset_labelled = False
                print('[ERROR] - Please ensure there is ' +
                      '/train and /val sub-directories ' +
                      'in the selected dataset directory.')
        elif self._precision_level == 2:
            isDatasetNamedRight = os.path.basename(
                self._path_to_dataset) == 'custom_dataset'
            trainDirExists = os.path.exists(self._path_to_dataset +
                                            '/train_dataset')
            valDirExists = os.path.exists(self._path_to_dataset +
                                          '/val_dataset')
            # Check if the dataset folder has the following structure
            if trainDirExists and valDirExists and isDatasetNamedRight:
                self._is_dataset_labelled = True
                self.validate_button.setStyleSheet(
                    'background-color: rgba(0,200,10,255);')
            else:
                self._is_dataset_labelled = False
                print('[ERROR] - Please ensure there is ' +
                      '/train_dataset and /val_dataset sub-directories' +
                      'in the selected dataset directory.')
        elif self._precision_level == 3:
            isDatasetNamedRight = os.path.basename(
                self._path_to_dataset) == 'custom_dataset'
            trainDirExists = os.path.exists(self._path_to_dataset +
                                            '/train_dataset')
            valDirExists = os.path.exists(self._path_to_dataset +
                                          '/val_dataset')
            # Check if the dataset folder has the following structure
            if trainDirExists and valDirExists and isDatasetNamedRight:
                self._is_dataset_labelled = True
                self.validate_button.setStyleSheet(
                    'background-color: rgba(0,200,10,255);')
            else:
                self._is_dataset_labelled = False
                print('[ERROR] - Please ensure there is ' +
                      '/train_dataset and /val_dataset sub-directories ' +
                      'in the selected dataset directory.')

        self.validateTraining()

    def startTraining(self):
        '''A function that is triggered by the button labelled, Train.'''
        self.disconnectTrainingButton()
        self.train_button.setText('Training In Progress')
        self.train_button.updateGeometry()

        if self._precision_level == 1:
            p1_trainer = P1Trainer(self._path_to_dataset, self.model_name,
                                   self._label_list)
            p1_trainer.train(False)
        elif self._precision_level == 2:
            p2_trainer = P2Trainer(self._path_to_dataset, self.model_name,
                                   self._label_list)
            p2_trainer.train(False)
        else:
            p3_trainer = P3Trainer(self._path_to_dataset, self.model_name,
                                   self._label_list)
            p3_trainer.train(False)

        self.train_button.setText('Train')
        self.train_button.updateGeometry()

    def conformDatasetToCOCO(self):
        '''A function that is triggered by the button labelled, Generate Dataset.'''
        if not self.debug:
            path_to_labelled = QFileDialog.getExistingDirectory(
                self, 'Select your labeled dataset.',
                os.path.abspath('../data'), QFileDialog.ShowDirsOnly
                | QFileDialog.DontResolveSymlinks)
        else:
            path_to_labelled = '../data/datasets/p2p3_dummy_dataset'
        # Check if every image in given folder
        trainDirExists = os.path.exists(path_to_labelled + '/train_dataset')
        valDirExists = os.path.exists(path_to_labelled + '/val_dataset')

        outputTrainDir = '../data/datasets/custom_dataset/train_dataset'
        outputValDir = '../data/datasets/custom_dataset/val_dataset'

        if trainDirExists and valDirExists:
            self.label_train_process = subprocess.Popen([
                'python', 'dataset/labelme2coco.py', '--labels',
                self._path_to_label_list, path_to_labelled + '/train_dataset',
                outputTrainDir
            ])
            if not self.debug:
                self.label_train_process.communicate()
            self.label_val_process = subprocess.Popen([
                'python', 'dataset/labelme2coco.py', '--labels',
                self._path_to_label_list, path_to_labelled + '/val_dataset',
                outputValDir
            ])
            if not self.debug:
                self.label_val_process.communicate()
        else:
            print('Faulty labelled dataset detected.')

    def populateModelSelector(self):
        '''
        A Mutator function that populates the DropDown Menu labelled, Choose
        Model with all available pretrained models from PyTorch model zoo.
        '''
        # Implement different model list based on different precision level.
        if self._precision_level == 1:
            self._model_list = [
                line.rstrip('\n') for line in open('./lists/p1_model_list.txt')
            ]
        elif self._precision_level == 2:
            self._model_list = [
                line.rstrip('\n') for line in open('./lists/p2_model_list.txt')
            ]
        elif self._precision_level == 3:
            self._model_list = [
                line.rstrip('\n') for line in open('./lists/p3_model_list.txt')
            ]

        self.model_selector.clear()
        for model in self._model_list:
            self.model_selector.addItem(model)

    def connectTrainingButton(self):
        '''
        A Mutator function that allows the button labelled, Train, to be used by
        the user.
        '''
        if not self.buttonConnected:
            self.train_button.clicked.connect(self.startTraining)
            self.buttonConnected = True

    def disconnectTrainingButton(self):
        '''
        A Mutator function that disallows the button labelled, Train, to be used by
        the user.
        '''
        if self.buttonConnected:
            try:
                self.train_button.clicked.disconnect(self.startTraining)
            except Exception:
                pass
            self.buttonConnected = False
Esempio n. 23
0
class TriageView(QScrollArea, View):
    def __init__(self, parent, data):
        QScrollArea.__init__(self, parent)
        View.__init__(self)
        View.setBinaryDataNavigable(self, True)
        self.setupView(self)
        self.data = data
        self.currentOffset = 0
        self.byteView = None
        self.fullAnalysisButton = None
        self.importsWidget = None

        container = QWidget(self)
        layout = QVBoxLayout()

        entropyGroup = QGroupBox("Entropy", container)
        entropyLayout = QVBoxLayout()
        entropyLayout.addWidget(
            entropy.EntropyWidget(entropyGroup, self, self.data))
        entropyGroup.setLayout(entropyLayout)
        layout.addWidget(entropyGroup)

        hdr = None
        try:
            if self.data.view_type == "PE":
                hdr = headers.PEHeaders(self.data)
            elif self.data.view_type != "Raw":
                hdr = headers.GenericHeaders(self.data)
        except:
            log.log_error(traceback.format_exc())

        if hdr is not None:
            headerGroup = QGroupBox("Headers", container)
            headerLayout = QVBoxLayout()
            headerWidget = headers.HeaderWidget(headerGroup, hdr)
            headerLayout.addWidget(headerWidget)
            headerGroup.setLayout(headerLayout)
            layout.addWidget(headerGroup)

        if self.data.executable:
            importExportSplitter = QSplitter(Qt.Horizontal)

            importGroup = QGroupBox("Imports", container)
            importLayout = QVBoxLayout()
            self.importsWidget = imports.ImportsWidget(importGroup, self,
                                                       self.data)
            importLayout.addWidget(self.importsWidget)
            importGroup.setLayout(importLayout)
            importExportSplitter.addWidget(importGroup)

            exportGroup = QGroupBox("Exports", container)
            exportLayout = QVBoxLayout()
            exportLayout.addWidget(
                exports.ExportsWidget(exportGroup, self, self.data))
            exportGroup.setLayout(exportLayout)
            importExportSplitter.addWidget(exportGroup)

            layout.addWidget(importExportSplitter)

            if self.data.view_type != "PE":
                segmentsGroup = QGroupBox("Segments", container)
                segmentsLayout = QVBoxLayout()
                segmentsWidget = sections.SegmentsWidget(
                    segmentsGroup, self.data)
                segmentsLayout.addWidget(segmentsWidget)
                segmentsGroup.setLayout(segmentsLayout)
                layout.addWidget(segmentsGroup)
                if len(segmentsWidget.segments) == 0:
                    segmentsGroup.hide()

            sectionsGroup = QGroupBox("Sections", container)
            sectionsLayout = QVBoxLayout()
            sectionsWidget = sections.SectionsWidget(sectionsGroup, self.data)
            sectionsLayout.addWidget(sectionsWidget)
            sectionsGroup.setLayout(sectionsLayout)
            layout.addWidget(sectionsGroup)
            if len(sectionsWidget.sections) == 0:
                sectionsGroup.hide()

            buttonLayout = QHBoxLayout()
            buttonLayout.addStretch(1)
            self.loadDynamicButton = QPushButton("Load Dynamic Imports")
            self.loadDynamicButton.clicked.connect(
                self.importsWidget.scanDynamic)
            buttonLayout.addWidget(self.loadDynamicButton)
            self.fullAnalysisButton = QPushButton("Start Full Analysis")
            self.fullAnalysisButton.clicked.connect(self.startFullAnalysis)
            buttonLayout.addWidget(self.fullAnalysisButton)
            layout.addLayout(buttonLayout)
            layout.addStretch(1)
        else:
            self.byteView = byte.ByteView(self, self.data)
            layout.addWidget(self.byteView, 1)

        container.setLayout(layout)
        self.setWidgetResizable(True)
        self.setWidget(container)

        if self.fullAnalysisButton is not None and Settings().get_string(
                "analysis.mode", data) == "full":
            self.fullAnalysisButton.hide()

    def getData(self):
        return self.data

    def getCurrentOffset(self):
        if self.byteView is not None:
            return self.byteView.getCurrentOffset()
        return self.currentOffset

    def getSelectionOffsets(self):
        if self.byteView is not None:
            return self.byteView.getSelectionOffsets()
        return (self.currentOffset, self.currentOffset)

    def setCurrentOffset(self, offset):
        self.currentOffset = offset
        UIContext.updateStatus(True)

    def getFont(self):
        return binaryninjaui.getMonospaceFont(self)

    def navigate(self, addr):
        if self.byteView:
            return self.byteView.navigate(addr)
        return False

    def startFullAnalysis(self):
        Settings().set_string("analysis.mode", "full", self.data)
        for f in self.data.functions:
            if f.analysis_skipped:
                f.reanalyze()
        self.data.update_analysis()
        self.fullAnalysisButton.hide()

    def navigateToFileOffset(self, offset):
        if self.byteView is None:
            addr = self.data.get_address_for_data_offset(offset)
            view_frame = ViewFrame.viewFrameForWidget(self)
            if view_frame is None:
                return
            if addr is None:
                view_frame.navigate("Hex:Raw", offset)
            else:
                view_frame.navigate(
                    "Linear:" + view_frame.getCurrentDataType(), addr)
        else:
            if self.data == self.data.file.raw:
                addr = offset
            else:
                addr = self.data.get_address_for_data_offset(offset)
            if addr is None:
                view_frame = ViewFrame.viewFrameForWidget(self)
                if view_frame is not None:
                    view_frame.navigate("Hex:Raw", offset)
            else:
                self.byteView.navigate(addr)
                self.byteView.setFocus(Qt.OtherFocusReason)

    def focusInEvent(self, event):
        if self.byteView is not None:
            self.byteView.setFocus(Qt.OtherFocusReason)
Esempio n. 24
0
class Form(QDialog):
    def __init__(self, parent=None):
        self.round = 0
        self.lcd = QLCDNumber(5)
        self.lcd2 = QLCDNumber(5)
        self.clock = QLCDNumber(5)
        super(Form, self).__init__(parent)
        self.setWindowTitle("Pomodoro")
        # Create widgets
        self.slider = QSlider(Qt.Horizontal)
        self.slider.setRange(1, 99)
        self.slider.setValue(25)
        self.slider2 = QSlider(Qt.Horizontal)
        self.slider2.setRange(1, 99)
        self.slider2.setValue(5)
        self.count = self.slider.value() * 60
        self.rest = self.slider2.value() * 60
        self.taskbar_count = 0
        self.taskbar2_count = 0
        self.text = QLabel("How long should the work period be?")
        self.text2 = QLabel("How long should the rest period be?")
        self.work = QLabel("WORK")
        self.pause = QLabel("REST")
        self.rounds = QLabel("Number of rounds: " + str(self.round))
        self.work.setAlignment(Qt.AlignHCenter)
        self.work.setFont(QFont("Times", 18, QFont.Bold))
        self.pause.setAlignment(Qt.AlignHCenter)
        self.pause.setFont(QFont("Times", 18, QFont.Bold))
        self.button = QPushButton("Start timer")
        self.button2 = QPushButton("Stop timer")
        self.reset = QPushButton("Reset rounds")
        self.lcd.display("25:00")
        self.lcd2.display("05:00")
        mins = 25
        secs = "00"
        self.clock.display(f"{mins}:{secs}")
        self.slider.valueChanged.connect(self.first_display)
        self.slider2.valueChanged.connect(self.second_display)
        self.slider.valueChanged.connect(self.clock_display)
        self.button2.hide()
        self.work.hide()
        self.pause.hide()
        self.clock.hide()
        # Create layout and add widgets
        layout = QVBoxLayout()
        layout.addWidget(self.text)
        layout.addWidget(self.lcd)
        layout.addWidget(self.slider)
        layout.addWidget(self.text2)
        layout.addWidget(self.lcd2)
        layout.addWidget(self.slider2)
        layout.addWidget(self.button)
        layout.addWidget(self.button2)
        layout.addWidget(self.work)
        layout.addWidget(self.pause)
        layout.addWidget(self.clock)
        layout.addWidget(self.rounds)
        layout.addWidget(self.reset)
        # Set dialog layout
        self.setLayout(layout)
        self.systemtray_icon = QSystemTrayIcon(QIcon("snake.png"))
        self.systemtray_icon.show()
        self.systemtray_icon.activated.connect(self.icon_activated)
        self.menu = QMenu(parent)
        self.exit_action = self.menu.addAction("Exit")
        self.systemtray_icon.setContextMenu(self.menu)
        self.exit_action.triggered.connect(self.slot_exit)
        # Add signals
        self.slider.valueChanged.connect(self.count_func)
        self.slider2.valueChanged.connect(self.count_func)
        self.button.clicked.connect(self.button_update)
        self.button.clicked.connect(self.timer_func)
        self.button.clicked.connect(self.round_count)
        self.button2.clicked.connect(self.stop)
        self.reset.clicked.connect(self.reset_rounds)

    def reset_rounds(self):
        self.round = 0
        self.rounds.setText("Number of rounds: " + str(self.round))

    def round_count(self):
        self.round += 1
        self.rounds.setText("Number of rounds: " + str(self.round))

    def icon_activated(self, reason):
        if reason in (QSystemTrayIcon.Trigger, QSystemTrayIcon.DoubleClick):
            self.show()

    def closeEvent(self, event):
        self.hide()
        event.ignore()

    def slot_exit(self):
        QApplication.exit(0)

    def first_display(self):
        minute = str(self.slider.sliderPosition())
        second = ":00"
        leading_zero = "0"
        if self.slider.sliderPosition() >= 10:
            self.lcd.display(minute + second)
        else:
            self.lcd.display(leading_zero + minute + second)

    def second_display(self):
        minute = str(self.slider2.sliderPosition())
        second = ":00"
        leading_zero = "0"
        if self.slider2.sliderPosition() >= 10:
            self.lcd2.display(minute + second)
        else:
            self.lcd2.display(leading_zero + minute + second)

    def clock_display(self):
        minute = str(self.slider.sliderPosition())
        second = ":00"
        leading_zero = "0"
        if self.slider.sliderPosition() >= 10:
            self.clock.display(minute + second)
        else:
            self.clock.display(leading_zero + minute + second)

    def count_func(self):
        self.count = self.slider.sliderPosition() * 60
        self.rest = self.slider2.sliderPosition() * 60

    def countdown(self):
        minute, second = divmod(self.count, 60)
        zero = "0"
        show = self.work.show()
        if second < 10 and minute < 10:
            self.clock.display(zero + str(minute) + ":" + zero + str(second))
        elif second < 10:
            self.clock.display(str(minute) + ":" + zero + str(second))
        elif minute < 10:
            self.clock.display(zero + str(minute) + ":" + str(second))
        else:
            self.clock.display(str(minute) + ":" + str(second))
        self.count -= 1
        if self.count < -1:
            self.work.hide()
            self.taskbar_rest()
            show = self.pause.show()
            minute, second = divmod(self.rest, 60)
            zero = "0"
            if self.rest == self.slider2.value() * 60:
                self.show()
            if second < 10 and minute < 10:
                self.clock.display(zero + str(minute) + ":" + zero +
                                   str(second))
            elif second < 10:
                self.clock.display(str(minute) + ":" + zero + str(second))
            elif minute < 10:
                self.clock.display(zero + str(minute) + ":" + str(second))
            else:
                self.clock.display(str(minute) + ":" + str(second))
            self.rest -= 1
            if self.rest < -1:
                self.clock.display("00:00")
                self.taskbar_work()
                self.timer.stop()
                self.stop()
        show

    def timer_func(self):
        timer = QTimer()
        self.timer = timer
        self.timer.timeout.connect(self.countdown)
        self.timer.start(1000)

    def button_update(self):
        self.button.hide()
        self.text.hide()
        self.lcd.hide()
        self.slider.hide()
        self.text2.hide()
        self.lcd2.hide()
        self.slider2.hide()
        self.reset.hide()
        self.clock.show()
        self.button2.show()
        self.work.show()

    def taskbar_rest(self):
        if self.taskbar_count == 0:
            self.systemtray_icon.showMessage("PAUSE", "Time to rest!",
                                             QSystemTrayIcon.Information,
                                             500000)
            self.taskbar_count = 1

    def taskbar_work(self):
        if self.taskbar2_count == 0:
            self.systemtray_icon.showMessage("WORK", "Break over!",
                                             QSystemTrayIcon.Information,
                                             500000)
            self.taskbar2_count = 1

    def stop(self):
        self.timer.stop()
        self.button2.hide()
        self.work.hide()
        self.pause.hide()
        self.clock.hide()
        self.count = self.slider.value() * 60
        self.rest = self.slider2.value() * 60
        self.clock.display(str(self.slider.value()) + ":00")
        self.button.show()
        self.text.show()
        self.lcd.show()
        self.slider.show()
        self.text2.show()
        self.lcd2.show()
        self.slider2.show()
        self.reset.show()
        self.show()
        self.taskbar_count = 0
        self.taskbar2_count = 0
Esempio n. 25
0
class MainWrapper(QWidget):
    def __init__(self):
        super(MainWrapper, self).__init__()
        self.monthNames = [
            'January', 'February', 'March', 'April', 'May', 'June', 'July',
            'August', 'September', 'October', 'November', 'December'
        ]
        self.metrics = None
        self.state = State()
        self.addListeners()
        self.buildUI()
        self.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)

    def loadNewFile(self):
        fileName = self.getCsvFileName()
        if fileName:
            parser = CSVParser()
            self.transactionMap = parser.parseCsv(fileName)
            allMonths = list(self.transactionMap.keys())
            allMonths.sort()
            self.monthsList = allMonths
            self.loadMonth(allMonths[-1])
            if len(allMonths) > 1:
                self.monthDecreaseButton.show()
            self.addMetricsButton()

    def getCsvFileName(self):
        fname, success = QFileDialog.getOpenFileName(
            None, 'Open CSV/XLSX Statement', '', 'CSV (*.csv *.CSV, *.xlsx)')
        if success:
            return fname

    def addFile(self):
        fileName = self.getCsvFileName()
        if fileName:
            parser = CSVParser()
            newTransactionMap = parser.parseCsv(fileName)
            self.transactionMap = parser.addTransactionMap(
                self.transactionMap, newTransactionMap)
            allMonths = list(self.transactionMap.keys())
            allMonths.sort()
            self.monthsList = allMonths
            self.loadMonth(self.currentMonth)

    def addListeners(self):
        self.state.addSubscriber(Events.update_total, self.setTotalDisplay)
        self.state.addSubscriber(Events.metrics_close, self.onMetricsClose)

    def loadMonth(self, monthText):
        monthNumber = int(monthText.split('-')[1])
        self.monthTitle.setText(self.monthNames[monthNumber - 1] + ' ' +
                                monthText.split('-')[0])
        prevCode = None if self.currentMonth == 'Month' else self.currentMonth
        self.currentMonth = monthText
        clearLayout(self.dataDisplayWrapper)
        self.dataDisplay = DataDisplay(self.state,
                                       self.transactionMap[self.currentMonth],
                                       self.currentMonth,
                                       prevCode=prevCode)
        self.dataDisplay.setSizePolicy(QSizePolicy.MinimumExpanding,
                                       QSizePolicy.Maximum)

        self.dataDisplayWrapper.addWidget(self.dataDisplay)

    def loadPreviousMonth(self):
        currentIndex = self.monthsList.index(self.currentMonth)
        if currentIndex > 0:
            newMonth = self.monthsList[currentIndex - 1]
            self.loadMonth(newMonth)
            self.monthIncreaseButton.show()
            if currentIndex == 1:
                self.monthDecreaseButton.hide()

    def loadNextMonth(self):
        currentIndex = self.monthsList.index(self.currentMonth)
        if currentIndex < len(self.monthsList) - 1:
            newMonth = self.monthsList[currentIndex + 1]
            self.loadMonth(newMonth)
            self.monthDecreaseButton.show()
            if currentIndex == len(self.monthsList) - 2:
                self.monthIncreaseButton.hide()

    def setTotalDisplay(self, transactionTotal, categoryTotal):
        self.totalDisplay.setText('Total: ${} / {}'.format(
            transactionTotal, categoryTotal))
        if transactionTotal <= categoryTotal:
            self.totalDisplay.setStyleSheet(
                "QLabel { color : rgb(67,160,71); }")
        else:
            self.totalDisplay.setStyleSheet(
                "QLabel { color : rgba(244, 67, 54, 255); }")

    def buildUI(self):
        self.closeButton = QPushButton('close')
        self.closeButton.setShortcut('Ctrl+W')
        self.closeButton.clicked.connect(self.onClose)
        self.closeButton.setFixedSize(0, 0)

        self.buildTitleLayout()
        self.buildMonthDisplayLayout()
        self.buildHeaderWidget()

        self.headerLayout = QVBoxLayout()
        self.headerLayout.addLayout(self.titleLayout)
        self.headerLayout.addLayout(self.monthDisplayLayout)
        self.headerLayout.addWidget(self.categoryHeaderWidget)
        self.headerLayout.addWidget(self.closeButton)

        self.headerLayoutWrapperWidget = QWidget()
        self.headerLayoutWrapperWidget.setLayout(self.headerLayout)
        self.headerLayoutWrapperWidget.setMaximumHeight(100)

        self.dataDisplayWrapper = QHBoxLayout()

        self.mainWrapperLayout = QVBoxLayout()
        self.mainWrapperLayout.addWidget(self.headerLayoutWrapperWidget)
        self.mainWrapperLayout.addLayout(self.dataDisplayWrapper)

        self.setLayout(self.mainWrapperLayout)

        self.setMinimumWidth(450)

    def buildTitleLayout(self):
        self.appTitle = QLabel(self)
        self.appTitle.setText("App Title")
        self.appTitle.setFont(boldFont)

        self.chooseFileButton = QPushButton("choose file")
        self.chooseFileButton.clicked.connect(self.loadNewFile)
        self.chooseFileButton.setShortcut('Ctrl+O')
        self.chooseFileButton.setContextMenuPolicy(Qt.CustomContextMenu)
        self.connect(self.chooseFileButton,
                     SIGNAL('customContextMenuRequested(const QPoint &)'),
                     self.chooseFileContextMenu)
        self.chooseFileButton.setMaximumWidth(90)

        self.metricsButton = QPushButton('metrics')
        self.metricsButton.clicked.connect(self.openMetrics)
        self.metricsButton.setShortcut('Ctrl+M')
        self.metricsButton.setMaximumWidth(80)

        self.titleLayout = QHBoxLayout()
        self.titleLayout.addWidget(self.appTitle)
        self.titleLayout.addWidget(self.chooseFileButton)

    def buildMonthDisplayLayout(self):
        self.monthTitle = QLabel(self)
        self.currentMonth = 'Month'
        self.monthTitle.setText(self.currentMonth)
        self.monthTitle.setMaximumWidth(115)
        self.monthTitle.setAlignment(Qt.AlignCenter)

        self.monthIncreaseButton = QPushButton('>')
        self.monthIncreaseButton.clicked.connect(self.loadNextMonth)
        self.monthDecreaseButton = QPushButton('<')
        self.monthDecreaseButton.clicked.connect(self.loadPreviousMonth)
        self.monthIncreaseButton.setMaximumWidth(20)
        self.monthDecreaseButton.setMaximumWidth(20)
        self.monthIncreaseButton.hide()
        self.monthDecreaseButton.hide()

        self.monthDisplayWrapper = QHBoxLayout()
        self.monthDisplayWrapper.addWidget(self.monthDecreaseButton)
        self.monthDisplayWrapper.addWidget(self.monthTitle)
        self.monthDisplayWrapper.addWidget(self.monthIncreaseButton)

        self.monthDisplayLayout = QHBoxLayout()
        self.monthDisplayLayout.addLayout(self.monthDisplayWrapper)

    def buildHeaderWidget(self):
        self.categoriesTitle = QLabel(self)
        self.categoriesTitle.setText('Categories')
        self.categoriesTitle.setMaximumWidth(88)
        self.categoriesTitle.setFont(boldFont)

        self.categoriesAddButton = QPushButton('+')
        self.categoriesAddButton.setMaximumWidth(20)
        self.categoriesAddButton.clicked.connect(self.promptAddCategory)
        self.categoriesAddButton.setToolTip('Add Category')
        self.categoriesAddButton.setContextMenuPolicy(Qt.CustomContextMenu)
        self.connect(self.categoriesAddButton,
                     SIGNAL('customContextMenuRequested(const QPoint &)'),
                     self.categoriesAddContextMenu)

        self.sumTransactions = 0
        self.totalDisplay = QLabel(self)
        self.totalDisplay.setText('Total: - / -')
        self.totalDisplay.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        self.totalDisplay.setFont(boldFont)

        self.categoryHeaderLayout = QHBoxLayout()
        self.categoryHeaderLayout.addWidget(self.categoriesTitle)
        self.categoryHeaderLayout.addWidget(self.categoriesAddButton)
        self.categoryHeaderLayout.addWidget(self.totalDisplay)
        self.categoryHeaderLayout.setMargin(0)

        self.categoryHeaderWidget = QWidget()
        self.categoryHeaderWidget.setLayout(self.categoryHeaderLayout)

    def promptAddCategory(self):
        modal = CategoryModal()
        data = modal.getData()
        if data:
            self.state.next(Events.add_category, data)

    def categoriesAddContextMenu(self):
        menu = QMenu(self)
        removeAction = QAction('Remove All')
        removeAction.triggered.connect(self.removeAllCategories)
        menu.addAction(removeAction)
        menu.exec_(QCursor.pos())

    def removeAllCategories(self):
        self.state.next(Events.remove_all_categories)

    def chooseFileContextMenu(self):
        if hasattr(self, 'dataDisplay'):
            menu = QMenu(self)
            addStatementAction = QAction('Add Statement')
            addStatementAction.triggered.connect(self.addFile)
            menu.addAction(addStatementAction)
            menu.exec_(QCursor.pos())

    def openMetrics(self):
        if not self.metrics:
            self.metrics = MainMetrics(self.state, self.transactionMap)
        self.metrics.show()
        self.metrics.activateWindow()

    def onMetricsClose(self):
        self.metrics.hide()
        self.metrics.deleteLater()
        self.metrics = None

    def addMetricsButton(self):
        self.titleLayout.removeWidget(self.chooseFileButton)
        self.titleLayout.addWidget(self.metricsButton)
        self.titleLayout.addWidget(self.chooseFileButton)

    def onClose(self):
        sys.exit()
Esempio n. 26
0
class QClickEdit(QWidget):
    """Displays text, changes to the specified user input field when clicked
    on, then reverts to text again when the widget loses focus.

    Self.input_widget holds the Qt user input widget. Any of the functions
    inherent to the widget can be executed, though compatability with this
    module cannot be guaranteed. Self.text holds the value displayed when a
    QClickEdit object is out of focus. Text is displayed as a QPushButton
    widget with flat text. When a QClickEdit widget is clicked on, it hides
    the text and displays the underlying Qt user input widget. When the user
    clicks elseware or the input widget loses focus, a QClickEdit widget
    reverts back to the flat text in self.text, displaying the current value
    of the underlying widget.

    Input widgets currently supported: QSpinBox, QLineEdit, QTimeEdit, and
    QComboBox.

    Values can be set for QClickEdit widgets, regardless of the type of input
    widget used, with the function setValue(), and values can be returned with
    getValue(). QLineEdit and QComboBox return as a string, QSpinBox returns
    as an integer, and QTimeEdit returns as a QTime Object.

    """

    # Registry saves instances of this class to iterate through them and
    # determine when to freeze edit fields
    _registry = []

    # Registry to keep track of which widgets have modified mousePressEvent()
    # functions, so they don't get rewritten every time a new QClickEdit object
    # is created.
    _top_widgets_modified = []

    def __init__(self, current_value, type_of_field=False, suffix=False,
                 parent=None):
        """Arguments:

        current_value -- The desired default value of the input widget
        type_of_field -- Optional argument - This string will precede the
                         displayed current value
        suffix -- suffix to follow current value displayed when self.text is
                  visible.
        """
        if not (isinstance(type_of_field, str) or (type_of_field is False)):
            raise TypeError("type_of_field argument is a descriptive prefix and must be a string")
        if not (isinstance(suffix, str) or (suffix is False)):
            raise TypeError("Suffix must be a string")

        QWidget.__init__(self)

        self.suffix = suffix

        self.layout = QHBoxLayout()
        self.setLayout(self.layout)
        self.layout.setMargin(0)
        self.layout.setContentsMargins(0, 0, 0, 0)
        if type_of_field:
            self.layout.addWidget(QLabel(type_of_field + ": ", self))

        self.destroyed.connect(lambda: self._registry.remove(self))
        self._registry.append(self)

        self._createInputWidget()
        self._createTextWidget()
        self.setValue(current_value)

        top_widgets = QApplication.topLevelWidgets()

        for tw in top_widgets:
            if tw in self._top_widgets_modified:
                continue
            self._top_widgets_modified.append(tw)
            original_MPE = tw.mousePressEvent
            MPE = partial(self._topWidgetMousePressEvent, tw, original_MPE)
            tw.mousePressEvent = MPE

    # Private Functions #

    def _topWidgetMousePressEvent(self, parent, original_mousePressEvent,
                                  event):
        """Overrides a class's mouse press event while still triggering the
        original mouse press event. self._freezeInputPrecheck() runs
        afterwards.
        """
        original_mousePressEvent(event)

        self._freezeInputPrecheck()

    def _setToEdit(self):
        """When the text of this QClickEdit object is clicked upon, this
        function is triggered, which reverts the input field of any other
        QClickEdit object in the window to flat text with
        _freezeInputPrecheck(), then displays the input field of this object
        """
        self._freezeInputPrecheck()
        self._showInputField()

    def _freezeInputPrecheck(self):
        """Runs _showText() for any input widgets not under mouse"""
        for ClickEdit_widget in self._registry:
            if (ClickEdit_widget.input_widget.isVisible()) and \
               (not ClickEdit_widget.input_widget.underMouse()):
                ClickEdit_widget._showText()

    def _createTextWidget(self):
        """Creates QPushButton widget that will display the current value as
        text when self.input_widget is not displayed."""
        self.text = QPushButton("-", self)
        self.text.setStyleSheet("text-align: left; margin: 2")
        self.text.setFlat(True)
        text = self._addSuffix(self.getValue())
        self.text.setText(text)

        self.text.clicked.connect(self._setToEdit)

        self.layout.addWidget(self.text)

    def _createInputWidget(self):
        """Creates the user input widget as determined by the child class,
        changes this object's focusOutEvent function, then hides the input
        widget."""
        self.input_widget = self.widget_()
        self.input_widget.focusOutEvent = self.focusOutEvent
        self.layout.addWidget(self.input_widget)
        self.input_widget.hide()

    def _addSuffix(self, current_value):
        """Adds specified suffix to displayed text"""
        if self.suffix:
            text = str(current_value) + ' ' + self.suffix
        else:
            text = str(current_value)
        return text

    def _showInputField(self):
        """Hides self.text and displays the input widget"""
        self.text.hide()
        self.input_widget.show()

    def _showText(self):
        """Hides the input widget and displays self.text"""
        self.input_widget.hide()
        self.text.show()

    ##########################################
    # Public Functions (modified inherited) ###
    ##########################################
    def focusOutEvent(self, event):
        """Runs the original Qt focusOutEvent function, then runs
        self._freezeInputPrecheck, which determines the display state of each
        QClickEdit object in the window.

        The original focusOutEvent function is executed to ensure that any
        modifications to it from outside the QClickEdit module will still run.
        """
        super(QClickEdit, self).focusOutEvent(event)
        self._freezeInputPrecheck()
Esempio n. 27
0
class main(QWidget):
    def __init__(self, parent=None):
        super(main, self).__init__(parent)
        self.setup()  # connections, widgets, layouts, etc.

        self.blksize = 2**20  # 1 MB; must be divisible by 16
        self.ext = '.enc'  # extension is appended to encrypted files
        self.path = ''
        self.encrypted = []  # to highlight done files in list
        self.decrypted = []

        self.clipboard = QApplication.clipboard()
        self.timeout = None  # to clear message label, see setMessage

        # this program was just an excuse to play with QprogressBar
        if not hash(os.urandom(11)) % 11:
            QTimer().singleShot(50, self.windDown)

        # various random hints
        hints = [
            'Freshly encrypted files can be renamed in the table!',
            'Clipboard is always cleared on program close!',
            'Keys can contain emoji if you <em>really</em> want: \U0001f4e6',
            'Keys can contain emoji if you <em>really</em> want: \U0001F511',
            'This isn\'t a tip, I just wanted to say hello!',
            'Keys can be anywhere from 8 to 4096 characters long!',
            'This program was just an excuse to play with the progress bars!',
            'Select \'Party\' in the hash button for progress bar fun!',
            ('Did you know you can donate one or all of your vital organs to '
             'the Aperture Science Self-Esteem Fund for Girls? It\'s true!'),
            ('It\'s been {:,} days since Half-Life 2: Episode '
             'Two'.format(int((time.time() - 1191988800) / 86400))),
            'I\'m version {}!'.format(VERSION),
            'I\'m version {}.whatever!'.format(VERSION.split('.')[0]),
            ('Brought to you by me, I\'m <a href="https://orthallelous.word'
             'press.com/">Orthallelous!</a>'),
            #'Brought to you by me, I\'m Htom Sirveaux!',
            'I wonder if there\'s beer on the sun',
            'Raspberry World: For all your raspberry needs. Off the beltline',
            #'I\'ve plummented to my death and I can\'t get up',
            '<em>NOT</em> compatible with the older version!',
            ('Hello there, fellow space travellers! Until somebody gives me '
             'some new lines in KAS, that is all I can say. - Bentusi Exchange'
             )
        ]
        if not hash(os.urandom(9)) % 4:
            self.extraLabel.setText(random.choice(hints))

    def genKey(self):
        "generate a random key"
        n = self.keySizeSB.value()
        char = string.printable.rstrip()  #map(chr, range(256))
        while len(char) < n:
            char += char
        key = ''.join(random.sample(char, n))
        self.keyInput.setText(key)

    def showKey(self, state=None):
        "hide/show key characters"
        if state is None: state = bool(self.showKeyCB.checkState())
        else: state = bool(state)
        if state: self.keyInput.setEchoMode(QLineEdit.Normal)
        else: self.keyInput.setEchoMode(QLineEdit.PasswordEchoOnEdit)

    def getFolder(self):
        "open file dialog and fill file table"
        path = QFileDialog(directory=self.path).getExistingDirectory()
        if not path: return
        self.path = str(path)
        self.populateTable(self.path)
        self.encrypted, self.decrypted = [], []
        return

    def resizeEvent(self, event):
        self.showFolder(self.path)  # update how the folder is shown

    def splitterChanged(self, pos):
        self.showFolder(self.path)  # likewise

    def showFolder(self, path):
        "displays current path, truncating as needed"
        if not path: return

        ell, sl = '\u2026', os.path.sep  # ellipsis, slash chars
        lfg, rfg = Qt.ElideLeft, Qt.ElideRight
        lst, wdh = os.path.basename(path), self.folderLabel.width()

        path = path.replace(os.path.altsep or '\\', sl)
        self.folderLabel.setToolTip(path)

        # truncate folder location
        fnt = QFontMetrics(self.folderLabel.font())
        txt = str(fnt.elidedText(path, lfg, wdh))

        if len(txt) <= 1:  # label is way too short
            self.folderLabel.setText('\u22ee' if txt != sl else txt)
            return  # but when would this happen?

        # truncate some more (don't show part of a folder name)
        if len(txt) < len(path) and txt[1] != sl:
            txt = ell + sl + txt.split(sl, 1)[-1]

            # don't truncate remaining folder name from the left
            if txt[2:] != lst and len(txt[2:]) < len(lst) + 2:
                txt = str(fnt.elidedText(ell + sl + lst, rfg, wdh))
        # you'd think len(txt) < len(lst) would work, but no; you'd be wrong

        self.folderLabel.setText(txt)

    def populateTable(self, path):
        "fill file table with file names"
        self.showFolder(path)

        names = []
        for n in os.listdir(path):
            if os.path.isdir(os.path.join(path, n)): continue  # folder
            names.append(n)

        self.folderTable.clearContents()
        self.folderTable.setRowCount(len(names))
        self.folderTable.setColumnCount(1)

        if not names:  # no files in this folder, inform user
            self.setMessage('This folder has no files')
            return

        self.folderTable.blockSignals(True)
        selEnab = Qt.ItemIsSelectable | Qt.ItemIsEnabled
        for i, n in enumerate(names):
            item = QTableWidgetItem()
            item.setText(n)
            item.setToolTip(n)
            item.setFlags(selEnab)

            # color code encrypted/decrypted files
            if n in self.encrypted:
                item.setTextColor(QColor(211, 70, 0))
                # allowed encrypted filenames to be changed
                item.setFlags(selEnab | Qt.ItemIsEditable)
            if n in self.decrypted:
                item.setForeground(QColor(0, 170, 255))
            self.folderTable.setItem(i, 0, item)
        if len(names) > 5:
            self.setMessage('{:,} files'.format(len(names)), 7)
        self.folderTable.blockSignals(False)
        return

    def editFileName(self, item):
        "change file name"
        new, old = str(item.text()), str(item.toolTip())

        result = QMessageBox.question(
            self, 'Renaming?',
            ("<p align='center'>Do you wish to rename<br>" +
             '<span style="color:#d34600;">{}</span>'.format(old) +
             "<br>to<br>" +
             '<span style="color:#ef4b00;">{}</span>'.format(new) +
             '<br>?</p>'))

        self.folderTable.blockSignals(True)
        if any(i in new for i in '/?<>:*|"^'):
            self.setMessage('Invalid character in name', 7)
            item.setText(old)
        elif result == QMessageBox.Yes:
            oold = os.path.join(self.path, old)
            try:
                os.rename(oold, os.path.join(self.path, new))
                self.encrypted.remove(old)
                self.encrypted.append(new)
                item.setToolTip(new)
            except Exception as err:
                self.setMessage(str(err), 9)
                item.setText(old)
                item.setToolTip(old)
                self.encrypted.remove(new)
                self.encrypted.append(old)
        else:
            item.setText(old)
        self.folderTable.blockSignals(False)

    def setMessage(self, message, secs=4, col=None):
        "show a message for a few seconds - col must be rgb triplet tuple"
        if self.timeout:  # https://stackoverflow.com/a/21081371
            self.timeout.stop()
            self.timeout.deleteLater()

        if col is None: color = 'rgb(255, 170, 127)'
        else:
            try:
                color = 'rgb({}, {}, {})'.format(*col)
            except:
                color = 'rgb(255, 170, 127)'

        self.messageLabel.setStyleSheet('background-color: {};'.format(color))
        self.messageLabel.setText(message)
        self.messageLabel.setToolTip(message)

        self.timeout = QTimer()
        self.timeout.timeout.connect(self.clearMessage)
        self.timeout.setSingleShot(True)
        self.timeout.start(secs * 1000)

    def clearMessage(self):
        self.messageLabel.setStyleSheet('')
        self.messageLabel.setToolTip('')
        self.messageLabel.setText('')

    def getName(self):
        "return file name of selected"
        items = self.folderTable.selectedItems()
        names = [str(i.text()) for i in items]
        if names: return names[0]  # only the first selected file
        else: return ''

    def showKeyLen(self, string):
        "displays a tooltip showing length of key"
        s = len(string)
        note = '{:,} character{}'.format(s, '' if s == 1 else 's')
        tip = QToolTip
        pos = self.genKeyButton.mapToGlobal(QPoint(0, 0))

        if s < self.minKeyLen:
            note = '<span style="color:#c80000;">{}</span>'.format(note)
        else:
            note = '<span style="color:#258f22;">{}</span>'.format(note)
        tip.showText(pos, note)

    def lock(self, flag=True):
        "locks buttons if True"
        stuff = [
            self.openButton,
            self.encryptButton,
            self.decryptButton,
            self.genKeyButton,
            self.hashButton,
            self.showKeyCB,
            self.copyButton,
            self.keyInput,
            self.keySizeSB,
            self.folderTable,
        ]
        for i in stuff:
            i.blockSignals(flag)
            i.setEnabled(not flag)
        return

    def _lerp(self, v1, v2, numPts=10):
        "linearly interpolate from v1 to v2\nFrom Orthallelous"
        if len(v1) != len(v2): raise ValueError("different dimensions")
        D, V, n = [], [], abs(numPts)
        for i, u in enumerate(v1):
            D.append(v2[i] - u)
        for i in range(n + 1):
            vn = []
            for j, u in enumerate(v1):
                vn.append(u + D[j] / float(n + 2) * i)
            V.append(tuple(vn))
        return V

    def weeeeeee(self):
        "party time"
        self.lock()
        self.setMessage('Party time!', 2.5)
        a, b, c = self.encryptPbar, self.decryptPbar, self.hashPbar
        process, sleep = app.processEvents, time.sleep

        am, bm, cm = a.minimum(), b.minimum(), c.minimum()
        ax, bx, cx = a.maximum(), b.maximum(), c.maximum()
        a.reset()
        b.reset()
        c.reset()

        loops = self._lerp((am, bm, cm), (ax, bx, cx), 100)
        ivops = loops[::-1]

        # up and up!
        for i in range(3):
            for j, k, l in loops:
                a.setValue(int(j))
                b.setValue(int(k))
                c.setValue(int(l))
                process()
                sleep(0.01)

        a.setValue(ax)
        b.setValue(bx)
        c.setValue(cx)
        sleep(0.25)
        a.setValue(am)
        b.setValue(bm)
        c.setValue(cm)

        # snake!
        self.setMessage('Snake time!')
        self.messageLabel.setStyleSheet('background-color: rgb(127,170,255);')
        for i in range(2):
            for j, k, l in loops:
                a.setValue(int(j))
                process()
                sleep(0.002)
            process()
            a.setInvertedAppearance(True)
            process()
            for j, k, l in ivops:
                a.setValue(int(j))
                process()
                sleep(0.002)

            for j, k, l in loops:
                b.setValue(int(k))
                process()
                sleep(0.002)
            process()
            b.setInvertedAppearance(False)
            process()
            for j, k, l in ivops:
                b.setValue(int(k))
                process()
                sleep(0.002)

            for j, k, l in loops:
                c.setValue(int(l))
                process()
                sleep(0.002)
            process()
            c.setInvertedAppearance(True)
            process()
            for j, k, l in ivops:
                c.setValue(int(l))
                process()
                sleep(0.002)

            process()
            b.setInvertedAppearance(True)
            process()
            for j, k, l in loops:
                b.setValue(int(k))
                process()
                sleep(0.002)
            process()
            b.setInvertedAppearance(False)
            process()
            for j, k, l in ivops:
                b.setValue(int(k))
                process()
                sleep(0.002)
            process()

            a.setInvertedAppearance(False)
            b.setInvertedAppearance(True)
            c.setInvertedAppearance(False)
        for j, k, l in loops:
            a.setValue(int(j))
            process()
            sleep(0.002)
        process()
        a.setInvertedAppearance(True)
        process()
        for j, k, l in ivops:
            a.setValue(int(j))
            process()
            sleep(0.002)

        # bars
        sleep(0.5)
        self.setMessage('Bars!')
        process()
        self.messageLabel.setStyleSheet('background-color: rgb(127,255,170);')
        for i in range(2):
            a.setValue(ax)
            time.sleep(0.65)
            a.setValue(am)
            sleep(0.25)
            process()
            b.setValue(bx)
            time.sleep(0.65)
            b.setValue(bm)
            sleep(0.25)
            process()
            c.setValue(cx)
            time.sleep(0.65)
            c.setValue(cm)
            sleep(0.25)
            process()
            b.setValue(bx)
            time.sleep(0.65)
            b.setValue(bm)
            sleep(0.25)
            process()

        # okay, enough
        process()
        a.setValue(ax)
        b.setValue(bx)
        c.setValue(cx)
        #a.setValue(am); b.setValue(bm); c.setValue(cm)
        a.setInvertedAppearance(False)
        b.setInvertedAppearance(True)
        c.setInvertedAppearance(False)
        self.lock(False)
        return

    def windDown(self, note=None):
        "silly deload on load"
        if note is None: note = 'Loading...'
        self.lock()
        self.setMessage(note)
        self.messageLabel.setStyleSheet('background-color: rgb(9, 190, 130);')
        a, b, c = self.encryptPbar, self.decryptPbar, self.hashPbar
        am, bm, cm = a.minimum(), b.minimum(), c.minimum()
        ax, bx, cx = a.maximum(), b.maximum(), c.maximum()
        a.reset()
        b.reset()
        c.reset()
        loops = self._lerp((ax, bx, cx), (am, bm, cm), 100)
        for j, k, l in loops:
            a.setValue(int(j))
            b.setValue(int(k))
            c.setValue(int(l))
            app.processEvents()
            time.sleep(0.02)
        a.reset()
        b.reset()
        c.reset()
        self.lock(False)
        self.clearMessage()

    def genHash(self, action):
        "generate hash of selected file and display it"
        name, t0 = self.getName(), time.perf_counter()

        # mark what hash was used in the drop-down menu
        for i in self.hashButton.menu().actions():
            if i == action: i.setIconVisibleInMenu(True)
            else: i.setIconVisibleInMenu(False)

        if str(action.text()) == 'Party':
            self.weeeeeee()
            self.windDown('Winding down...')
            return
        if not name:
            self.setMessage('No file selected')
            return
        if not os.path.exists(os.path.join(self.path, name)):
            self.setMessage('File does not exist')
            return

        self.lock()
        hsh = self.hashFile(os.path.join(self.path, name),
                            getattr(hashlib, str(action.text())))
        self.lock(False)
        #hsh = str(action.text()) + ': ' + hsh
        self.hashLabel.setText(hsh)
        self.hashLabel.setToolTip(hsh)
        self.extraLabel.setText(
            str(action.text()) + ' hash took ' +
            self.secs_fmt(time.perf_counter() - t0))

    def setCancel(self):
        "cancel operation"
        self._requestStop = True

    def showCancelButton(self, state=False):
        "show/hide cancel button"
        self.cancelButton.blockSignals(not state)
        self.cancelButton.setEnabled(state)
        if state:
            self.cancelButton.show()
            self.keyInput.hide()
            self.genKeyButton.hide()
            self.keySizeSB.hide()
        else:
            self.cancelButton.hide()
            self.keyInput.show()
            self.genKeyButton.show()
            self.keySizeSB.show()

    def hashFile(self, fn, hasher):
        "returns the hash value of a file"
        hsh, blksize = hasher(), self.blksize
        fsz, csz = os.path.getsize(fn), 0.0

        self.hashPbar.reset()
        self.showCancelButton(True)
        prog, title = '(# {:.02%}) {}', self.windowTitle()
        with open(fn, 'rb') as f:
            while 1:
                blk = f.read(blksize)
                if not blk: break
                hsh.update(blk)

                csz += blksize
                self.hashPbar.setValue(int(round(csz * 100.0 / fsz)))
                app.processEvents()
                self.setWindowTitle(prog.format(csz / fsz, title))
                if self._requestStop: break

        self.hashPbar.setValue(self.hashPbar.maximum())
        self.setWindowTitle(title)
        self.showCancelButton(False)

        if self._requestStop:
            self.setMessage('Hashing canceled!')
            self.hashPbar.setValue(self.hashPbar.minimum())
            self._requestStop = False
            return
        return hsh.hexdigest()

    def hashKey(self, key, salt=b''):
        "hashes a key for encrypting/decrypting file"
        salt = salt.encode() if type(salt) != bytes else salt
        key = key.encode() if type(key) != bytes else key
        p = app.processEvents
        self.setMessage('Key Hashing...', col=(226, 182, 249))
        p()
        key = hashlib.pbkdf2_hmac('sha512', key, salt, 444401)
        p()
        self.clearMessage()
        p()
        return hashlib.sha3_256(key).digest()  # AES requires a 32 char key

    def encrypt(self):
        "encrypt selected file with key"
        name, t0 = self.getName(), time.perf_counter()
        if not name:
            self.setMessage('No file selected')
            return
        if not os.path.exists(os.path.join(self.path, name)):
            self.setMessage('File does not exist')
            return
        key = str(self.keyInput.text())
        if len(key) < self.minKeyLen:
            self.setMessage(('Key must be at least '
                             '{} characters long').format(self.minKeyLen))
            return

        self.lock()
        gn = self.encryptFile(key, os.path.join(self.path, name))
        if not gn:
            self.lock(False)
            return
        self.encrypted.append(os.path.basename(gn))
        self.lock(False)

        self.populateTable(self.path)  # repopulate folder list
        bn, tt = os.path.basename(gn), time.perf_counter() - t0
        self.setMessage('Encrypted, saved "{}"'.format(bn, 13))
        self.extraLabel.setText('Encrypting took ' + self.secs_fmt(tt))

    def encryptFile(self, key, fn):
        "encrypts a file using AES (MODE_GCM)"
        chars = ''.join(map(chr, range(256))).encode()
        chk = AES.block_size
        sample = random.sample
        iv = bytes(sample(chars, chk * 2))
        salt = bytes(sample(chars * 2, 256))

        vault = AES.new(self.hashKey(key, salt), AES.MODE_GCM, iv)
        fsz = os.path.getsize(fn)
        del key
        blksize = self.blksize
        gn = fn + self.ext

        fne = os.path.basename(fn).encode()
        fnz = len(fne)
        if len(fne) % chk: fne += bytes(sample(chars, chk - len(fne) % chk))

        csz = 0.0  # current processed value
        self.encryptPbar.reset()
        prog, title = '({:.02%}) {}', self.windowTitle()
        self.showCancelButton(True)

        with open(fn, 'rb') as src, open(gn, 'wb') as dst:
            dst.write(bytes([0] * 16))  # spacer for MAC written at end
            dst.write(iv)
            dst.write(salt)  # store iv, salt
            # is it safe to store MAC, iv, salt plain right in file?
            # can't really store them encrypted,
            # or elsewhere in this model of single file encryption?
            # can't have another file for the file to lug around

            # store file size, file name length
            dst.write(vault.encrypt(struct.pack('<2Q', fsz, fnz)))
            dst.write(vault.encrypt(fne))  # store filename

            while 1:
                dat = src.read(blksize)
                if not dat: break
                elif len(dat) % chk:  # add padding
                    fil = chk - len(dat) % chk
                    dat += bytes(sample(chars, fil))
                dst.write(vault.encrypt(dat))

                csz += blksize  # show progress
                self.encryptPbar.setValue(int(round(csz * 100.0 / fsz)))
                self.setWindowTitle(prog.format(csz / fsz, title))
                app.processEvents()

                if self._requestStop: break
            if not self._requestStop:
                stuf = random.randrange(23)  # pack in more stuffing
                fing = b''.join(bytes(sample(chars, 16)) for i in range(stuf))
                dst.write(vault.encrypt(fing))  # and for annoyance

                dst.seek(0)
                dst.write(vault.digest())  # write MAC
                self.hashLabel.setText('MAC: ' + vault.hexdigest())

        self.encryptPbar.setValue(self.encryptPbar.maximum())
        self.setWindowTitle(title)
        self.showCancelButton(False)

        if self._requestStop:
            self.setMessage('Encryption canceled!')
            self.encryptPbar.setValue(self.encryptPbar.minimum())
            self._requestStop = False
            os.remove(gn)
            return
        return gn

    def decrypt(self):
        "encrypt selected file with key"
        name, t0 = self.getName(), time.perf_counter()
        if not name:
            self.setMessage('No file selected')
            return
        if not os.path.exists(os.path.join(self.path, name)):
            self.setMessage('File does not exist')
            return
        key = str(self.keyInput.text())
        if len(key) < self.minKeyLen:
            self.setMessage(('Key must be at least '
                             '{} characters long').format(self.minKeyLen))
            return

        self.lock()
        gn = self.decryptFile(key, os.path.join(self.path, name))
        if not gn:
            self.lock(False)
            return
        self.decrypted.append(os.path.basename(gn))
        self.lock(False)

        self.populateTable(self.path)  # repopulate folder list
        bn, tt = os.path.basename(gn), time.perf_counter() - t0
        self.setMessage('Decrypted, saved "{}"'.format(bn, 13))
        self.extraLabel.setText('Decrypting took ' + self.secs_fmt(tt))

    def decryptFile(self, key, fn):
        "decrypts a file using AES (MODE_GCM)"
        blksize = self.blksize
        gn = hashlib.md5(os.path.basename(fn).encode()).hexdigest()
        gn = os.path.join(self.path, gn)  # temporary name
        if os.path.exists(gn):
            self.setMessage('file already exists')
            return

        self.decryptPbar.reset()
        csz = 0.0  # current processed value
        chk, fnsz = AES.block_size, os.path.getsize(fn)
        prog, title = '({:.02%}) {}', self.windowTitle()
        try:
            with open(fn, 'rb') as src, open(gn, 'wb') as dst:
                # extract iv, salt
                MAC = src.read(16)
                iv = src.read(AES.block_size * 2)
                salt = src.read(256)
                vault = AES.new(self.hashKey(key, salt), AES.MODE_GCM, iv)
                self.showCancelButton(True)

                # extract file size, file name length
                sizes = src.read(struct.calcsize('<2Q'))
                fsz, fnz = struct.unpack('<2Q', vault.decrypt(sizes))

                # extract filename; round up fnz to nearest chk
                rnz = fnz if not fnz % chk else fnz + chk - fnz % chk
                rfn = vault.decrypt(src.read(rnz))[:fnz].decode()
                self.setMessage('Found "{}"'.format(rfn), 13, (255, 211, 127))

                while 1:
                    dat = src.read(blksize)
                    if not dat: break
                    dst.write(vault.decrypt(dat))

                    csz += blksize  # show progress
                    self.decryptPbar.setValue(int(round(csz * 100.0 / fnsz)))
                    self.setWindowTitle(prog.format(1 - (csz / fnsz), title))
                    app.processEvents()
                    if self._requestStop: break

                if not self._requestStop: dst.truncate(fsz)  # remove padding
            if not self._requestStop:
                vault.verify(MAC)
                self.hashLabel.setText('')

        except (ValueError, KeyError) as err:
            os.remove(gn)
            self.setMessage('Invalid decryption!')
            self.setWindowTitle(title)
            self.showCancelButton(False)
            return
        except Exception as err:
            os.remove(gn)
            self.setMessage('Invalid key or file!')
            self.setWindowTitle(title)
            self.showCancelButton(False)
            return
        self.decryptPbar.setValue(self.decryptPbar.maximum())
        self.setWindowTitle(title)
        self.showCancelButton(False)

        if self._requestStop:
            self.setMessage('Decryption canceled!')
            self.decryptPbar.setValue(self.decryptPbar.minimum())
            self._requestStop = False
            os.remove(gn)
            return

        # restore original file name
        name, ext = os.path.splitext(rfn)
        count = 1
        fn = os.path.join(self.path, name + ext)
        while os.path.exists(fn):
            fn = os.path.join(self.path, name + '_{}'.format(count) + ext)
            count += 1
        os.rename(gn, fn)  # restore original name
        return fn  # saved name

    def copyKeyHash(self, action):
        "copies either the key or the hash to clipboard"
        act = str(action.text()).lower()

        if 'key' in act: txt = str(self.keyInput.text())
        elif 'hash' in act: txt = str(self.hashLabel.text())
        else:
            self.setMessage('Invalid copy selection')
            return

        if not txt:
            self.setMessage('Empty text; Nothing to copy')
            return

        if 'key' in act: self.setMessage('Key copied to clipboard')
        elif 'hash' in act: self.setMessage('Hash copied to clipboard')
        else:
            self.setMessage('Invalid copy selection')
            return

        self.clipboard.clear()
        self.clipboard.setText(txt)

    def secs_fmt(self, s):
        "6357 -> '1h 45m 57s'"
        Y, D, H, M = 31556952, 86400, 3600, 60
        y = int(s // Y)
        s -= y * Y
        d = int(s // D)
        s -= d * D
        h = int(s // H)
        s -= h * H
        m = int(s // M)
        s -= m * M

        r = (str(int(s)) if int(s) == s else str(round(s, 3))) + 's'

        if m: r = str(m) + 'm ' + r
        if h: r = str(h) + 'h ' + r
        if d: r = str(d) + 'd ' + r
        if y: r = str(y) + 'y ' + r
        return r.strip()

    def closeEvent(self, event):
        self.clipboard.clear()

    def setup(self):
        "constructs the gui"
        Fixed = QSizePolicy()
        MinimumExpanding = QSizePolicy(QSizePolicy.MinimumExpanding,
                                       QSizePolicy.MinimumExpanding)
        self.minKeyLen = 8
        self.maxKeyLen = 4096

        self.splitter = QSplitter(self)
        self.splitter.setOrientation(Qt.Horizontal)
        self.splitter.splitterMoved.connect(self.splitterChanged)

        # left column
        self.leftColumn = QWidget()
        self.vl01 = QVBoxLayout()

        # left column - first item (0; horizonal layout 0)
        self.hl00 = QHBoxLayout()
        self.hl00.setSpacing(5)

        self.openButton = QPushButton('&Open')
        self.openButton.setToolTip('Open folder')
        self.openButton.setMinimumSize(60, 20)
        self.openButton.setMaximumSize(60, 20)
        self.openButton.setSizePolicy(Fixed)
        self.openButton.clicked.connect(self.getFolder)
        #ico = self.style().standardIcon(QStyle.SP_DirIcon)
        #self.openButton.setIcon(ico)

        self.folderLabel = QLabel()
        self.folderLabel.setMinimumSize(135, 20)
        self.folderLabel.setMaximumSize(16777215, 20)
        self.folderLabel.setSizePolicy(MinimumExpanding)
        self.hl00.insertWidget(0, self.openButton)
        self.hl00.insertWidget(1, self.folderLabel)

        # left column - second item (1)
        self.folderTable = QTableWidget()
        self.folderTable.setMinimumSize(200, 32)
        self.folderTable.horizontalHeader().setVisible(False)
        self.folderTable.horizontalHeader().setStretchLastSection(True)
        self.folderTable.verticalHeader().setVisible(False)
        self.folderTable.verticalHeader().setDefaultSectionSize(15)
        self.folderTable.itemChanged.connect(self.editFileName)

        # left column - third item (2)
        self.extraLabel = QLabel()
        self.extraLabel.setMinimumSize(200, 20)
        self.extraLabel.setMaximumSize(16777215, 20)
        self.extraLabel.setSizePolicy(MinimumExpanding)
        self.extraLabel.setTextInteractionFlags(Qt.LinksAccessibleByMouse)

        # finalize left column
        self.vl01.insertLayout(0, self.hl00)
        self.vl01.insertWidget(1, self.folderTable)
        self.vl01.insertWidget(2, self.extraLabel)
        self.leftColumn.setLayout(self.vl01)

        # right column
        self.rightColumn = QWidget()
        self.vl02 = QVBoxLayout()

        # right column - first item (0)
        self.messageLabel = QLabel()
        self.messageLabel.setMinimumSize(290, 20)
        self.messageLabel.setMaximumSize(16777215, 20)
        self.messageLabel.setSizePolicy(MinimumExpanding)
        self.messageLabel.setAlignment(Qt.AlignCenter)

        # right column - second item (2; horizontal layout 1)
        self.hl01 = QHBoxLayout()
        self.hl01.setSpacing(5)

        self.encryptButton = QPushButton('&Encrypt')  #\U0001F512
        self.encryptButton.setToolTip('Encrypt selected file')
        self.encryptButton.setMinimumSize(60, 20)
        self.encryptButton.setMaximumSize(60, 20)
        self.encryptButton.setSizePolicy(Fixed)
        self.encryptButton.clicked.connect(self.encrypt)

        self.encryptPbar = QProgressBar()
        self.encryptPbar.setMinimumSize(225, 20)
        self.encryptPbar.setMaximumSize(16777215, 20)
        self.encryptPbar.setSizePolicy(MinimumExpanding)
        self.encryptPbar.setTextVisible(False)

        palette = self.encryptPbar.palette()  # color of progress bar
        color = QColor(211, 70, 0)
        palette.setColor(QPalette.Highlight, color)
        self.encryptPbar.setPalette(palette)

        self.hl01.insertWidget(0, self.encryptButton)
        self.hl01.insertWidget(1, self.encryptPbar)

        # right column - third item (3; horizontal layout 2)
        self.hl02 = QHBoxLayout()
        self.hl02.setSpacing(5)

        self.cancelButton = QPushButton('C&ANCEL')
        self.cancelButton.setToolTip('Cancels current operation')
        self.cancelButton.setMinimumSize(70, 24)
        self.cancelButton.setMaximumSize(70, 24)
        self.cancelButton.setSizePolicy(Fixed)
        self.cancelButton.clicked.connect(self.setCancel)
        font = self.cancelButton.font()
        font.setBold(True)
        self.cancelButton.setFont(font)
        self.cancelButton.blockSignals(True)
        self.cancelButton.setEnabled(False)
        self.cancelButton.hide()
        self._requestStop = False

        self.keyInput = QLineEdit()
        self.keyInput.setMinimumSize(225, 20)
        self.keyInput.setMaximumSize(16777215, 20)
        self.keyInput.setSizePolicy(MinimumExpanding)
        self.keyInput.setPlaceholderText('key')
        self.keyInput.setMaxLength(self.maxKeyLen)
        self.keyInput.setAlignment(Qt.AlignCenter)
        self.keyInput.textEdited.connect(self.showKeyLen)

        self.genKeyButton = QPushButton('&Gen Key')  #\U0001F511
        self.genKeyButton.setToolTip('Generate a random key')
        self.genKeyButton.setMinimumSize(60, 20)
        self.genKeyButton.setMaximumSize(60, 20)
        self.genKeyButton.setSizePolicy(Fixed)
        self.genKeyButton.clicked.connect(self.genKey)

        self.keySizeSB = QSpinBox()
        self.keySizeSB.setToolTip('Length of key to generate')
        self.keySizeSB.setRange(32, 1024)
        self.keySizeSB.setMinimumSize(40, 20)
        self.keySizeSB.setMaximumSize(40, 20)
        self.keySizeSB.setSizePolicy(Fixed)
        self.keySizeSB.setAlignment(Qt.AlignCenter)
        self.keySizeSB.setButtonSymbols(QSpinBox.NoButtons)
        self.keySizeSB.setWrapping(True)

        self.hl02.insertWidget(0, self.cancelButton)
        self.hl02.insertWidget(1, self.keyInput)
        self.hl02.insertWidget(2, self.genKeyButton)
        self.hl02.insertWidget(3, self.keySizeSB)

        # right column - fourth item (4; horizontal layout 3)
        self.hl03 = QHBoxLayout()
        self.hl03.setSpacing(5)

        self.decryptButton = QPushButton('&Decrypt')  #\U0001F513
        self.decryptButton.setToolTip('Decrypt selected file')
        self.decryptButton.setMinimumSize(60, 20)
        self.decryptButton.setMaximumSize(60, 20)
        self.decryptButton.setSizePolicy(Fixed)
        self.decryptButton.clicked.connect(self.decrypt)

        self.decryptPbar = QProgressBar()
        self.decryptPbar.setMinimumSize(225, 20)
        self.decryptPbar.setMaximumSize(16777215, 20)
        self.decryptPbar.setSizePolicy(MinimumExpanding)
        self.decryptPbar.setTextVisible(False)
        self.decryptPbar.setInvertedAppearance(True)

        palette = self.decryptPbar.palette()  # color of progress bar
        color = QColor(0, 170, 255)
        palette.setColor(QPalette.Highlight, color)
        self.decryptPbar.setPalette(palette)

        self.hl03.insertWidget(0, self.decryptButton)
        self.hl03.insertWidget(1, self.decryptPbar)

        # right column - fifth item (7; horizontal layout 4)
        self.hl04 = QHBoxLayout()
        self.hl04.setSpacing(5)

        self.showKeyCB = QCheckBox('&Show Key')
        self.showKeyCB.setToolTip('Show/Hide key value')
        self.showKeyCB.setMinimumSize(75, 20)
        self.showKeyCB.setMaximumSize(75, 20)
        self.showKeyCB.setSizePolicy(Fixed)
        self.showKeyCB.clicked.connect(self.showKey)
        self.showKeyCB.setChecked(True)

        self.hashPbar = QProgressBar()
        self.hashPbar.setMinimumSize(150, 20)
        self.hashPbar.setMaximumSize(16777215, 20)
        self.hashPbar.setSizePolicy(MinimumExpanding)
        self.hashPbar.setTextVisible(False)

        palette = self.hashPbar.palette()  # color of progress bar
        color = QColor(31, 120, 73)
        palette.setColor(QPalette.Highlight, color)
        self.hashPbar.setPalette(palette)

        self.hashButton = QPushButton('&Hash')
        self.hashButton.setToolTip('Determine file hash')
        self.hashButton.setMinimumSize(60, 20)
        self.hashButton.setMaximumSize(60, 20)
        self.hashButton.setSizePolicy(Fixed)

        menu = QMenu(self.hashButton)
        ico = self.style().standardIcon(QStyle.SP_DialogYesButton)
        for alg in sorted(
                filter(lambda x: 'shake' not in x,
                       hashlib.algorithms_guaranteed),
                key=lambda n:
            (len(n), sorted(hashlib.algorithms_guaranteed).index(n))):
            menu.addAction(
                ico, alg
            )  # drop shake algs as their .hexdigest requires an argument - the rest don't
        menu.addAction(ico, 'Party')
        for i in menu.actions():
            i.setIconVisibleInMenu(False)
        self.hashButton.setMenu(menu)
        menu.triggered.connect(self.genHash)

        self.hl04.insertWidget(0, self.showKeyCB)
        self.hl04.insertWidget(1, self.hashPbar)
        self.hl04.insertWidget(2, self.hashButton)

        # right column - sixth item (8; horizontal layout 5)
        self.hl05 = QHBoxLayout()
        self.hl05.setSpacing(5)

        self.copyButton = QPushButton('&Copy')  #\U0001F4CB
        self.copyButton.setToolTip('Copy key or hash to clipboard')
        self.copyButton.setMinimumSize(60, 20)
        self.copyButton.setMaximumSize(60, 20)
        self.copyButton.setSizePolicy(Fixed)

        menu2 = QMenu(self.copyButton)
        menu2.addAction('Copy Key')
        menu2.addAction('Copy Hash')
        self.copyButton.setMenu(menu2)
        menu2.triggered.connect(self.copyKeyHash)

        self.hashLabel = QLabel()
        self.hashLabel.setMinimumSize(225, 20)
        self.hashLabel.setMaximumSize(16777215, 20)
        self.hashLabel.setSizePolicy(MinimumExpanding)
        self.hashLabel.setTextFormat(Qt.PlainText)
        self.hashLabel.setAlignment(Qt.AlignCenter)
        self.hashLabel.setTextInteractionFlags(Qt.TextSelectableByMouse)

        self.hl05.insertWidget(0, self.copyButton)
        self.hl05.insertWidget(1, self.hashLabel)

        # finalize right column
        self.vl02.insertWidget(0, self.messageLabel)
        self.vl02.insertSpacerItem(1, QSpacerItem(0, 0))
        self.vl02.insertLayout(2, self.hl01)
        self.vl02.insertLayout(3, self.hl02)
        self.vl02.insertLayout(4, self.hl03)
        self.vl02.insertSpacerItem(5, QSpacerItem(0, 0))
        self.vl02.insertWidget(6, QFrame())
        self.vl02.insertLayout(7, self.hl04)
        self.vl02.insertLayout(8, self.hl05)
        self.rightColumn.setLayout(self.vl02)

        # finalize main window
        self.splitter.insertWidget(0, self.leftColumn)
        self.splitter.insertWidget(1, self.rightColumn)

        layout = QHBoxLayout(self)
        layout.addWidget(self.splitter)
        self.setLayout(layout)

        self.setWindowTitle('Simple File Encryptor/Decryptor')
        self.resize(self.sizeHint())
Esempio n. 28
0
class UpdateDialog(QDialog):
    def __init__(self, *args, **kwargs):
        super(UpdateDialog, self).__init__(*args, **kwargs)
        self.setAttribute(Qt.WA_DeleteOnClose)
        self.setWindowTitle("版本检查")
        self.setFixedSize(240, 120)
        layout = QVBoxLayout()
        self.current_version_message = QLabel("当前版本:", self)
        self.current_version_message.setAlignment(Qt.AlignCenter)
        layout.addWidget(self.current_version_message)

        self.last_version_message = QLabel("最新版本:检查中...", self)
        self.last_version_message.setAlignment(Qt.AlignCenter)
        layout.addWidget(self.last_version_message)

        #  启动更新的信息提示
        self.run_message = QLabel("", self)
        self.run_message.setWordWrap(True)
        self.run_message.hide()
        self.run_message.setAlignment(Qt.AlignCenter)
        self.run_message.setStyleSheet("color:rgb(200,50,50)")
        layout.addWidget(self.run_message)

        opts_layout = QHBoxLayout()
        self.update_button = QPushButton("立即更新")
        self.update_button.clicked.connect(self.exit_for_updating)
        self.close_button = QPushButton("下次更新")
        self.close_button.clicked.connect(self.close)
        opts_layout.addWidget(self.update_button)
        opts_layout.addWidget(self.close_button)
        layout.addLayout(opts_layout)
        self.update_button.hide()
        self.setLayout(layout)

        # 检测最新版本
        app = QApplication.instance()
        self.network_manager = getattr(app, "_network")

        self._get_last_version()

    def _get_last_version(self):
        """ 获取最新版本号 """
        # 获取当前版本号
        json_file = os.path.join(BASE_DIR, "classini/update_{}.json".format(SYS_BIT))
        if not os.path.exists(json_file):
            self.current_version_message.setText("当前版本:检测失败.")
            self.last_version_message.setText("最新版本:检测失败.")
            self.close_button.setText("关闭")
            return

        with open(json_file, "r", encoding="utf-8") as jf:
            update_json = json.load(jf)

        self.current_version_message.setText("当前版本:{}".format(update_json["VERSION"]))

        url = SERVER + "check_version/?version={}&sys_bit={}".format(update_json["VERSION"], SYS_BIT)
        request = QNetworkRequest(url=QUrl(url))

        reply = self.network_manager.get(request)
        reply.finished.connect(self.last_version_back)

    def last_version_back(self):
        """ 检测版本结果 """
        reply = self.sender()
        if reply.error():
            reply.deleteLater()
            self.last_version_message.setText("最新版本:检测失败.")
            return
        data = reply.readAll().data()
        u_data = json.loads(data.decode("utf-8"))
        if u_data["update_needed"]:
            for_update_file = os.path.join(BASE_DIR, "classini/for_update_{}.json".format(SYS_BIT))
            # 写入待更新信息
            f_data = {
                "VERSION": u_data["last_version"],
                "SERVER": u_data["file_server"],
                "FILES": u_data["update_files"]
            }
            with open(for_update_file, "w", encoding="utf-8") as f:
                json.dump(f_data, f, indent=4, ensure_ascii=False)
            self.update_button.show()
        else:
            self.update_button.hide()
            self.close_button.setText("关闭")
        self.last_version_message.setText("最新版本:{}".format(u_data["last_version"]))
        reply.deleteLater()

    def exit_for_updating(self):
        """ 退出当前程序,启动更新更新 """
        script_file = os.path.join(BASE_DIR, "AutoUpdate.exe")
        if SYS_BIT == "admin":
            script_file = os.path.join(BASE_DIR, "AutoAdminUpdate.exe")
        is_close = True
        if os.path.exists(script_file):
            try:
                Popen(script_file, shell=False)
            except OSError as e:
                self.run_message.setText(str(e))
                is_close = False
        else:
            self.run_message.setText("更新程序丢失...")
            is_close = False
        self.run_message.show()
        if is_close:
            sys.exit()

    def closeEvent(self, event):
        """ 下次更新 """
        for_update_file = os.path.join(BASE_DIR, "classini/for_update_{}.json".format(SYS_BIT))
        if os.path.exists(for_update_file):
            os.remove(for_update_file)
        super(UpdateDialog, self).closeEvent(event)
Esempio n. 29
0
class RootWindow(QWidget):
    """Root window for Enigma Qt GUI"""
    def __init__(self, enigma_api, cursor_handler):
        """Initializes Root QT window widgets
        :param enigma_api: {EnigmaAPI} Shared EnigmaAPI object
        """
        super().__init__()

        # QT WINDOW SETTINGS ==================================================

        self.setWindowIcon(QIcon(BASE_DIR + "enigma_200px.png"))
        main_layout = QVBoxLayout(self)
        self.setLayout(main_layout)

        # SAVE ATTRIBUTES =====================================================

        self.__enigma_api = enigma_api
        logging.info("Qt GUI initialized with EnigmaAPI settings:\n%s",
                     str(enigma_api))

        # MENU BAR ============================================================

        menu = QMenuBar(self)
        save_load_menu = menu.addMenu("Save/load settings")
        save_load_menu.addAction("Save settings", self.save_config)
        save_load_menu.addAction("Load settings", self.load_config)
        menu.addAction("Export message", self.export_message)

        # ROTORS INDICATOR ====================================================

        logging.info("Generating rotor and reflector indicators...")
        self.__rotors = _RotorsHandlerWidget(
            self,
            self.__enigma_api.positions,
            self.__enigma_api.generate_rotate_callback,
            self.__enigma_api.rotate_reflector,
            enigma_api,
            self.refresh_gui,
            enigma_api.reflector_position,
        )

        # LIGHTBOARD FRAME ====================================================

        logging.info("Adding Lightboard...")
        self.__lightboard = _LightboardWidget(self, self.__enigma_api.charset)

        # INPUT OUTPUT FOR ENCRYPTION/DECRYPTION ==============================

        logging.info("Adding I/O textboxes...")
        self.__output_textbox = _OutputTextBoxWidget(
            self, self.__lightboard.light_up, enigma_api.letter_group)
        self.__input_textbox = _InputTextBoxWidget(
            self, enigma_api.encrypt, self.__output_textbox.insert,
            self.__output_textbox, self.__rotors.set_positions,
            enigma_api.letter_group, enigma_api.revert_by,
            enigma_api.buffer_full,
            enigma_api.data()["charset"], cursor_handler)

        # PLUGBOARD BUTTONS ===================================================

        logging.info("Adding Plugboard button")
        self.__plug_button = QPushButton("Plugboard")
        self.__plug_button.setToolTip("Edit plugboard letter pairs")
        self.__plug_button.clicked.connect(self.__open_plugboard_window)

        # SHOW WIDGETS ========================================================

        logging.info("Showing all widgets...")
        main_layout.addWidget(menu, alignment=Qt.AlignTop)
        main_layout.addWidget(self.__rotors, alignment=Qt.AlignBottom)
        main_layout.addWidget(self.__lightboard)
        main_layout.addWidget(
            QLabel("INPUT", self, styleSheet="font-size: 20px"),
            alignment=Qt.AlignCenter,
        )
        main_layout.addWidget(self.__input_textbox)
        main_layout.addWidget(
            QLabel("OUTPUT", self, styleSheet="font-size: 20px"),
            alignment=Qt.AlignCenter,
        )
        main_layout.addWidget(self.__output_textbox)
        main_layout.addWidget(self.__plug_button)

        self.refresh_gui()
        self.show()

    def __open_plugboard_window(self):
        """Opens the plugboard menu"""
        logging.info("Opening Plugboard menu...")
        old_pairs = self.__enigma_api.plug_pairs()

        plugboard = PlugboardWindow(self, self.__enigma_api)
        plugboard.exec()

        logging.info("Closing plugboard...")

        new_pairs = self.__enigma_api.plug_pairs()
        if old_pairs != new_pairs:
            logging.info('New plug pairs set to "%s"', str(new_pairs))
        else:
            logging.info("No changes to plug pairs...")

        del plugboard

    def refresh_gui(self):
        """Refreshes main window GUI based on new EnigmaAPI settings"""
        logging.info("Refreshing GUI components...")
        self.setWindowTitle(self.__enigma_api.model())
        self.__input_textbox.clear()
        self.__input_textbox.set_charset(self.__enigma_api.data()["charset"])

        if self.__enigma_api.data(
        )["plugboard"]:  # If current model has a plugboard
            logging.info("Showing Plugboard button...")
            self.__plug_button.show()
        else:
            logging.info("Hiding Plugboard button...")
            self.__plug_button.hide()

        # Arrange lightbulbs to new layout
        self.__lightboard.regenerate_bulbs(self.__enigma_api.data()["layout"])

    def load_config(self):
        """Loads EnigmaAPI settings from a config file and refershes GUI"""
        dialog = QFileDialog(self)
        filename = dialog.getOpenFileName(self, "Load settings",
                                          QDir.homePath(),
                                          "Enigma config (*.json)")[0]

        if filename:
            try:
                self.__enigma_api.load_from(filename)
                logging.info('Successfully loaded config from file "%s"',
                             filename)
            except (FileNotFoundError, JSONDecodeError) as error:
                QMessageBox.critical(
                    self,
                    "Load config",
                    "Error retrieving data from "
                    "selected file!\nError message:\n\n %s" % repr(error),
                )
                logging.error('Failed to load config from file "%s"',
                              filename,
                              exc_info=True)
                return
            except Exception as error:
                QMessageBox.critical(
                    self,
                    "Load config",
                    "Following error occured during "
                    "applying loaded settings:\n%s" % repr(error),
                )
                logging.error(
                    "Unable to load config from file, keeping old settings...",
                    exc_info=True,
                )
                return

            # Refresh gui after loading setings
            self.__rotors.generate_rotors()
            self.__input_textbox.blockSignals(True)
            self.refresh_gui()
            self.__input_textbox.blockSignals(False)
            self.__rotors.set_positions()
            logging.info('Checkpoint set to "%s"',
                         str(self.__enigma_api.positions()))
            self.__enigma_api.set_checkpoint()
        else:
            logging.info("No load file selected...")

    def save_config(self):
        """Collects data from EnigmaAPI and saves it to selected filename"""
        dialog = QFileDialog(self)
        dialog.setDefaultSuffix("json")
        filename = dialog.getSaveFileName(self, "Save settings",
                                          QDir.homePath(),
                                          "Enigma config (*.json)")[0]

        # To prevent from saving files without a file extension...
        if filename and not findall(r"\.json$", filename.lower()):
            filename += ".json"
            logging.info(
                ".json file extension for save file not found, adding...")

        if filename:
            self.__enigma_api.save_to(filename)
        else:
            logging.info("No save file selected...")

    def export_message(self):
        """Opens a dialog to get the save location, exports current Enigma
        settings and encrypted message to the file"""
        dialog = QFileDialog(self)
        filename = dialog.getSaveFileName(self, "Save Enigma message",
                                          QDir.homePath(), "*.txt")[0]

        if filename and not findall(r"\.txt$", filename):
            filename += ".txt"
            logging.info(
                ".txt file extension for save file not found, adding...")

        if filename:
            logging.info('Exporing message to "%s"...', filename)
            with open(filename, "w") as file:
                message = "\n".join(wrap(self.__output_textbox.text(), 29))
                file.write("%s\n%s\n" % (str(self.__enigma_api), message))
Esempio n. 30
0
class PenSetWidget(QWidget):

    penSizeTrigger = Signal(int)
    penColorTrigger = Signal(str)
    fontChangeTrigger = Signal(QFont)

    def __init__(self, parent=None):
        super().__init__(parent)

        self.paddingX = 5
        self.paddingY = 2
        self.iconWidth = self.iconHeight = 24
        self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
        self.setWindowFlags(Qt.ToolTip)

        self.initWindows()

        self.prevSizeButton = self.penSize1
        self.penSize1.setChecked(True)
        self.presentColor.setStyleSheet('QPushButton { background-color: %s; }' % PENCOLOR)

    def generateButtons(self, parent=None):
        """ Generate buttons due to colorDic """
        self.colorButtons = []
        for color in self.colorList:
            button = QPushButton(parent)
            button.setObjectName(color[0])
            button.setStyleSheet('QPushButton { background-color: %s; }' % color[1])
            button.setFixedSize(self.iconWidth / 2, self.iconHeight / 2)
            button.setCheckable(True)
            self.colorButtons.append(button)

    def initWindows(self):
        self.mainLayout = QHBoxLayout()
        self.setLayout(self.mainLayout)
        self.mainLayout.setSpacing(0)
        self.mainLayout.setContentsMargins(5, 2, 5, 2)

        self.initPenSizeButtons()
        self.initFontWidget()
        self.initPenColorButtons()

        self.separator = QFrame(self)
        self.separator.setFrameShape(QFrame.VLine)
        self.separator.setFrameShadow(QFrame.Sunken)

        self.mainLayout.addWidget(self.penSize)
        self.mainLayout.addWidget(self.changeFontButton)
        self.mainLayout.addWidget(self.separator)

        self.mainLayout.addWidget(self.colorSet)

    def initPenSizeButtons(self):
        self.penSize = QWidget(self)
        self.penSizeLayout = QHBoxLayout()
        self.penSize.setLayout(self.penSizeLayout)
        # adjust pen size
        self.penSize1 = QPushButton(self.penSize)
        self.penSize1.setIcon(QIcon(":/resource/icon/pensize1.png"))
        self.penSize1.setObjectName('1')
        self.penSize1.setFixedSize(self.iconWidth, self.iconHeight)
        self.penSize1.setCheckable(True)

        self.penSize2 = QPushButton(self.penSize)
        self.penSize2.setIcon(QIcon(":/resource/icon/pensize2.png"))
        self.penSize2.setObjectName('2')
        self.penSize2.setFixedSize(self.iconWidth, self.iconHeight)
        self.penSize2.setCheckable(True)

        self.penSize3 = QPushButton(self.penSize)
        self.penSize3.setIcon(QIcon(":/resource/icon/pensize3.png"))
        self.penSize3.setObjectName('3')
        self.penSize3.setFixedSize(self.iconWidth, self.iconHeight)
        self.penSize3.setCheckable(True)

        self.sizeButtonGroup = QButtonGroup(self.penSize)
        self.sizeButtonGroup.addButton(self.penSize1)
        self.sizeButtonGroup.addButton(self.penSize2)
        self.sizeButtonGroup.addButton(self.penSize3)
        self.sizeButtonGroup.buttonClicked.connect(self.sizeButtonToggled)

        self.penSizeLayout.addWidget(self.penSize1)
        self.penSizeLayout.addWidget(self.penSize2)
        self.penSizeLayout.addWidget(self.penSize3)

        self.penSizeLayout.setSpacing(5)
        self.penSizeLayout.setContentsMargins(0, 0, 0, 0)

    def initPenColorButtons(self):
        self.colorSet = QWidget(self)
        self.colorLayout = QHBoxLayout()
        self.colorLayout.setSpacing(5)
        self.colorLayout.setContentsMargins(5, 0, 5, 0)
        self.colorSet.setLayout(self.colorLayout)

        self.presentColor = QPushButton(self.colorSet)
        self.presentColor.setFixedSize(self.iconWidth, self.iconHeight)
        self.presentColor.setEnabled(False)

        # adjust pen color

        self.colorPick = QWidget(self.colorSet)
        self.colorGrid = QGridLayout()
        self.colorGrid.setSpacing(0)
        self.colorGrid.setContentsMargins(5, 0, 5, 0)
        self.colorPick.setLayout(self.colorGrid)

        self.colorList = [('white'       ,       '#ffffff'),
                          ('red'         ,       '#ff0000'),
                          ('green'       ,       '#00ff00'),
                          ('blue'        ,       '#0000ff'),
                          ('cyan'        ,       '#00ffff'),
                          ('magenta'     ,       '#ff00ff'),
                          ('yellow'      ,       '#ffff00'),
                          ('gray'        ,       '#a0a0a4'),

                          ('black'       ,       '#000000'),
                          ('darkRed'     ,       '#800000'),
                          ('darkGreen'   ,       '#008000'),
                          ('darkBlue'    ,       '#000080'),
                          ('darkCyan'    ,       '#008080'),
                          ('darkMagenta' ,       '#800080'),
                          ('darkYellow'  ,       '#808000'),
                          ('darkGray'    ,       '#808080')]

        self.generateButtons()

        self.colorButtonGroup = QButtonGroup(self)
        for button in self.colorButtons:
            self.colorButtonGroup.addButton(button)
        self.colorButtonGroup.buttonClicked.connect(self.colorButtonToggled)

        # set the layout
        tmp = 0
        for x in range(0, 2):
            for y in range(0, int(len(self.colorList) / 2)):
                self.colorGrid.addWidget(self.colorButtons[tmp], x, y)
                tmp += 1

        self.colorGrid.setSpacing(0)
        self.colorGrid.setContentsMargins(0, 0, 0, 0)

        self.colorLayout.addWidget(self.presentColor)
        self.colorLayout.addWidget(self.colorPick)

    def initFontWidget(self):
        self.fontDialog = QFontDialog()
        self.changeFontButton = QPushButton(self)
        self.fontDialog.setCurrentFont(QFont('Sans serif'))
        self.changeFontButton.setText('{0} {1}'.format(self.fontDialog.currentFont().family(),
                                                       self.fontDialog.currentFont().pointSize()))
        self.changeFontButton.clicked.connect(self.fontButtonClicked)

    def showFontWidget(self):
        self.changeFontButton.show()
        self.penSize1.hide()
        self.penSize2.hide()
        self.penSize3.hide()

    def showPenWidget(self):
        self.changeFontButton.hide()
        self.penSize1.show()
        self.penSize2.show()
        self.penSize3.show()

    # slots
    def colorButtonToggled(self, button):
        self.presentColor.setStyleSheet('QPushButton { background-color: %s; }' % button.objectName())
        self.penColorTrigger.emit(button.objectName())

    def sizeButtonToggled(self, button):
        self.penSizeTrigger.emit(int(button.objectName()) * 2)

    def fontButtonClicked(self):
        ok = True
        font = QFontDialog.getFont(self)
        if font[1]:
            self.changeFontButton.setText('{0} {1}'.format(font[0].family(),
                                                           font[0].pointSize()))
            self.fontChangeTrigger.emit(font[0])