Example #1
0
class ConfigWidget(QWidget):

    def __init__(self, plugin_action):
        QWidget.__init__(self)
        self.plugin_action = plugin_action
        layout = QVBoxLayout(self)
        self.setLayout(layout)

        # --- Directory Options ---
        directory_group_box = QGroupBox(_('Default Unpack Directory:'), self)
        layout.addWidget(directory_group_box)
        directory_group_box_layout = QVBoxLayout()
        directory_group_box.setLayout(directory_group_box_layout)

        # Directory path Textbox
        # Load the textbox with the current preference setting
        self.directory_txtBox = QLineEdit(plugin_prefs['Unpack_Folder'], self)
        self.directory_txtBox.setToolTip(_('<p>Default directory to extract files to'))
        directory_group_box_layout.addWidget(self.directory_txtBox)
        self.directory_txtBox.setReadOnly(True)

        # Folder select button
        directory_button = QPushButton(_('Select/Change Unpack Directory'), self)
        directory_button.setToolTip(_('<p>Select/Change directory to extract files to.'))
        # Connect button to the getDirectory function
        directory_button.clicked.connect(self.getDirectory)
        directory_group_box_layout.addWidget(directory_button)
        self.default_folder_check = QCheckBox(_('Always use the Default Unpack Directory'), self)
        self.default_folder_check.setToolTip(_('<p>When unchecked... you will be prompted to select a destination '+
                                                                                'directory for the extracted content each time you use Mobiunpack.'))
        directory_group_box_layout.addWidget(self.default_folder_check)
        # Load the checkbox with the current preference setting
        self.default_folder_check.setChecked(plugin_prefs['Always_Use_Unpack_Folder'])

        misc_group_box = QGroupBox(_('Default settings:'), self)
        layout.addWidget(misc_group_box)
        misc_group_box_layout = QVBoxLayout()
        misc_group_box.setLayout(misc_group_box_layout)

        self.use_hd_images = QCheckBox(_('Always use HD images if present'), self)
        self.use_hd_images.setToolTip(_('<p>When checked... any HD images present in the kindlebook '+
                                                                                'will be used for creating the ePub.'))
        misc_group_box_layout.addWidget(self.use_hd_images)
        # Load the checkbox with the current preference setting
        self.use_hd_images.setChecked(plugin_prefs['Use_HD_Images'])

        combo_label = QLabel('Select epub version output:', self)
        misc_group_box_layout.addWidget(combo_label)
        self.epub_version_combobox = QComboBox()
        self.epub_version_combobox.setToolTip(_('<p>Select the type of OPF file to create.'))
        misc_group_box_layout.addWidget(self.epub_version_combobox)
        self.epub_version_combobox.addItems(['Auto-detect', 'ePub2', 'ePub3'])
        if plugin_prefs['Epub_Version'] == 'A':
            self.epub_version_combobox.setCurrentIndex(0)
        else:
            self.epub_version_combobox.setCurrentIndex(int(plugin_prefs['Epub_Version'])-1)

    def save_settings(self):
        # Save current dialog sttings back to JSON config file
            plugin_prefs['Unpack_Folder'] = unicode(self.directory_txtBox.displayText())
            plugin_prefs['Always_Use_Unpack_Folder'] = self.default_folder_check.isChecked()
            plugin_prefs['Use_HD_Images'] = self.use_hd_images.isChecked()
            if unicode(self.epub_version_combobox.currentText()) == 'Auto-detect':
                plugin_prefs['Epub_Version'] = 'A'
            else:
                plugin_prefs['Epub_Version'] = unicode(self.epub_version_combobox.currentText())[4:]

    def getDirectory(self):
        c = choose_dir(self, _(PLUGIN_NAME + 'dir_chooser'),
                _('Select Default Directory To Unpack Kindle Book/Mobi To'))
        if c:
            self.directory_txtBox.setReadOnly(False)
            self.directory_txtBox.setText(c)
            self.directory_txtBox.setReadOnly(True)

    def validate(self):
        # This is just to catch the situation where somone might
        # manually enter a non-existent path in the Default path textbox.
        # Shouldn't be possible at this point.
        if not os.path.exists(self.directory_txtBox.text()):
            errmsg = '<p>The path specified for the Default Unpack folder does not exist.</p>' \
                        '<p>Your latest preference changes will <b>NOT</b> be saved!</p>' + \
                        '<p>You should configure again and make sure your settings are correct.'
            error_dialog(None, _(PLUGIN_NAME + ' v' + PLUGIN_VERSION),
                                    _(errmsg), show=True)
            return False
        return True
class PunctDialog(Dialog):
    def __init__(self, parent):
        self.prefs = self.prefsPrep()
        self.criteria = None
        self.parent = parent
        self.help_file_name = '{0}_smarten_help.html'.format(PLUGIN_SAFE_NAME)
        Dialog.__init__(self, _('Smarten Punctuation (the sequel)'), 'toolbag_smarter_dialog', parent)

    def setup_ui(self,):
        layout = QVBoxLayout(self)
        self.setLayout(layout)

        help_layout = QHBoxLayout()
        layout.addLayout(help_layout)
        # Add hyperlink to a help file at the right. We will replace the correct name when it is clicked.
        help_label = QLabel('<a href="http://www.foo.com/">Plugin Help</a>', self)
        help_label.setTextInteractionFlags(Qt.LinksAccessibleByMouse | Qt.LinksAccessibleByKeyboard)
        help_label.setAlignment(Qt.AlignRight)
        help_label.linkActivated.connect(self.help_link_activated)
        help_layout.addWidget(help_label)

        self.edu_quotes = QCheckBox(_('Smarten Quotation marks'), self)
        layout.addWidget(self.edu_quotes)
        self.edu_quotes.setChecked(self.prefs['edu_quotes'])
        self.edu_quotes.stateChanged.connect(self.quotes_gui_changes)

        exceptions_group_box = QGroupBox('', self)
        layout.addWidget(exceptions_group_box)
        exceptions_group_box_layout = QVBoxLayout()
        exceptions_group_box.setLayout(exceptions_group_box_layout)
        self.use_file = QCheckBox(_('Use custom apostrophe exceptions file'), self)
        exceptions_group_box_layout.addWidget(self.use_file)
        if not self.edu_quotes.isChecked():
            self.use_file.setDisabled(True)
        else:
            self.use_file.setChecked(self.prefs['use_file'])
        self.use_file.stateChanged.connect(self.use_file_gui_changes)

        path_layout = QHBoxLayout()
        exceptions_group_box_layout.addLayout(path_layout)
        self.file_path = QLineEdit('', self)
        if not self.edu_quotes.isChecked() and not self.use_file.isChecked():
            self.file_path.setReadOnly(True)
        else:
            self.file_path.setText(self.prefs['file_path'])
            self.file_path.setReadOnly(True)
        path_layout.addWidget(self.file_path)
        self.file_button = QPushButton('...', self)
        self.file_button.clicked.connect(self.getFile)
        path_layout.addWidget(self.file_button)
        if not self.edu_quotes.isChecked() and not self.use_file.isChecked():
            self.file_button.setDisabled(True)

        combo_layout = QVBoxLayout()
        layout.addLayout(combo_layout)
        label = QLabel(_('(em|en)-dash settings'), self)
        combo_layout.addWidget(label)
        self.dashes_combo = QComboBox()
        combo_layout.addWidget(self.dashes_combo)
        values = [_('Do not educate dashes'), _('-- = emdash (no endash support)'),
                  _('-- = emdash | --- = endash'), _('--- = emdash | -- = endash')]
        self.dashes_combo.addItems(values)
        self.dashes_combo.setCurrentIndex(self.prefs['dashes'])
        # self.dashes_combo.currentIndexChanged.connect(self.update_gui)

        self.ellipses = QCheckBox(_('Smarten ellipses'), self)
        layout.addWidget(self.ellipses)
        self.ellipses.setChecked(self.prefs['ellipses'])

        self.unicode = QCheckBox(_('Educate with unicode characters (instead of entities)'), self)
        layout.addWidget(self.unicode)
        self.unicode.setChecked(self.prefs['unicode'])

        layout.addSpacing(10)
        button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        button_box.accepted.connect(self._ok_clicked)
        button_box.rejected.connect(self.reject)
        layout.addWidget(button_box)

    def getFile(self):
        unique_dlg_name = '{0}plugin:smarter_choose_dialog'.format(PLUGIN_SAFE_NAME)
        caption = _('Select custom apostrophe exceptions file')
        filters = [('Text files', ['txt'])]
        c = choose_files(self, unique_dlg_name, caption, filters, all_files=True)

        if c:
            self.file_path.setReadOnly(False)
            self.file_path.setText(c[0])
            self.file_path.setReadOnly(True)

    def _ok_clicked(self):
        quotes_setting = 'q' if self.edu_quotes.isChecked() else ''
        if self.dashes_combo.currentIndex() == 0:
            dash_setting = ''
        elif self.dashes_combo.currentIndex() == 1:
            dash_setting = 'd'
        elif self.dashes_combo.currentIndex() == 2:
            dash_setting = 'i'
        elif self.dashes_combo.currentIndex() == 3:
            dash_setting = 'D'
        else:
            dash_setting = ''
        ellipses_setting = 'e' if self.ellipses.isChecked() else ''
        smarty_attr = quotes_setting + dash_setting + ellipses_setting
        if smarty_attr == '':
            smarty_attr = '0'

        self.file_path.setReadOnly(False)
        if self.use_file.isChecked() and not len(self.file_path.displayText()):
            self.file_path.setReadOnly(True)
            return error_dialog(self.parent, _('Error'), '<p>' +
                    _('Must select a custom exception file'), det_msg='', show=True)
        if self.use_file.isChecked():
            apos_exception_file = unicode(self.file_path.displayText())
            if not os.path.exists(apos_exception_file):
                apos_exception_file = None
        else:
            apos_exception_file = None
        self.file_path.setReadOnly(True)
        apos_words_list = []
        if apos_exception_file is not None:
            apos_words_list = self.parseExceptionsFile(os.path.normpath(apos_exception_file))
        self.criteria = (smarty_attr, self.unicode.isChecked(), apos_words_list)
        self.savePrefs()
        self.accept()

    def getCriteria(self):
        return self.criteria

    def quotes_gui_changes(self):
        if self.edu_quotes.isChecked():
            self.use_file.setDisabled(False)
            if self.use_file.isChecked():
                self.file_button.setDisabled(False)
        else:
            self.use_file.setChecked(False)
            self.file_path.setReadOnly(False)
            self.file_path.clear()
            self.file_path.setReadOnly(True)
            self.use_file.setDisabled(True)
            self.file_button.setDisabled(True)

    def use_file_gui_changes(self):
        if self.use_file.isChecked():
            self.file_button.setDisabled(False)
        else:
            self.file_path.setReadOnly(False)
            self.file_path.clear()
            self.file_path.setReadOnly(True)
            self.file_button.setDisabled(True)

    def prefsPrep(self):
        from calibre.utils.config import JSONConfig
        plugin_prefs = JSONConfig('plugins/{0}_SmarterPunct_settings'.format(PLUGIN_SAFE_NAME))
        plugin_prefs.defaults['edu_quotes'] = True
        plugin_prefs.defaults['use_file'] = False
        plugin_prefs.defaults['file_path'] = ''
        plugin_prefs.defaults['dashes'] = 1
        plugin_prefs.defaults['ellipses'] = True
        plugin_prefs.defaults['unicode'] = True
        return plugin_prefs

    def savePrefs(self):
        self.prefs['edu_quotes'] = self.edu_quotes.isChecked()
        self.prefs['use_file'] = self.use_file.isChecked()
        self.prefs['file_path'] = unicode(self.file_path.displayText()) if len(self.file_path.displayText()) else ''
        self.prefs['dashes'] = self.dashes_combo.currentIndex()
        self.prefs['ellipses'] = self.ellipses.isChecked()
        self.prefs['unicode'] = self.unicode.isChecked()

    def help_link_activated(self, url):
        def get_help_file_resource():
            # Copy the HTML helpfile to the plugin directory each time the
            # link is clicked in case the helpfile is updated in newer plugins.
            file_path = os.path.join(config_dir, 'plugins', self.help_file_name)
            with open(file_path,'w') as f:
                f.write(load_resource('resources/{}'.format(self.help_file_name)))
            return file_path
        url = 'file:///' + get_help_file_resource()
        open_url(QUrl(url))

    def parseExceptionsFile(self, filename):
        import os, codecs, chardet
        words_list = []
        bytes = min(32, os.path.getsize(filename))
        raw = open(filename, 'rb').read(bytes)
        if raw.startswith(codecs.BOM_UTF8):
            enc = 'utf-8-sig'
        else:
            result = chardet.detect(raw)
            enc = result['encoding']
        try:
            with codecs.open(filename, encoding=enc, mode='r') as fd:
                words_list = [line.rstrip() for line in fd]
            words_list = filter(None, words_list)
            print('Exceptions list:', words_list)
        except:
            pass
        return words_list
Example #3
0
class EvalWizardStep1Window(QMainWindow):

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

        self.setMinimumSize(QSize(900, 500))
        self.setWindowTitle("Diarization - Diarize Files (Step 1 of 2)")

        centralWidget = QWidget(self)
        self.setCentralWidget(centralWidget)

        gridLayout = QGridLayout(self)
        centralWidget.setLayout(gridLayout)

        title = QLabel("Select the files to be diarized:", self)
        title.setAlignment(QtCore.Qt.AlignCenter)

        open_files_btn = QPushButton("Select .wav File(s)", self)
        open_files_btn.clicked.connect(self._select_wav_files)

        self._filenames_list = QListWidget(self)
        self._filenames_list.setAlternatingRowColors(True)

        self._output_directory = QLineEdit(self)
        self._output_directory.setReadOnly(True)
        self._output_directory.setDisabled(True)

        open_dir_btn = QPushButton("Select Output Directory", self)
        open_dir_btn.clicked.connect(self._select_output_directory)

        self._network_location = QLineEdit(self)
        self._network_location.setReadOnly(True)
        self._network_location.setDisabled(True)

        open_network_btn = QPushButton("Select Evaluation Neural Network", self)
        open_network_btn.clicked.connect(self._select_network)

        next_btn = QPushButton("Next", self)
        next_btn.clicked.connect(self._next_actions)

        gridLayout.setRowStretch(0, 1)
        gridLayout.addWidget(title, 1, 1)
        gridLayout.setRowStretch(1, 1)
        gridLayout.addWidget(self._filenames_list, 2, 0, 1, 3)
        gridLayout.addWidget(open_files_btn, 2, 3, 1, 1)
        gridLayout.addWidget(self._output_directory, 3, 0, 1, 3)
        gridLayout.addWidget(open_dir_btn, 3, 3, 1, 1)
        gridLayout.addWidget(self._network_location, 4, 0, 1, 3)
        gridLayout.addWidget(open_network_btn, 4, 3, 1, 1)
        gridLayout.setRowStretch(49, 1)
        gridLayout.addWidget(next_btn, 50, 3)

    def _next_actions(self):
        try:
            # Clean Input a Bit
            # # Change variables to string type
            wav_files = [str(self._filenames_list.item(i).text()) for i in range(self._filenames_list.count())]
            output_directory = self._output_directory.text()
            network_location = self._network_location.text()
            # Substring network location to give true value needed
            network_location = network_location[0:network_location.rindex(".")]
            self._step2 = EvalWizardStep2Window(wav_files, output_directory, network_location)
            self._step2.show()
            self.close()
        except:
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Critical)
            msg.setText("There was an error. Double check your input files and try again.")
            msg.setWindowTitle("Error")
            msg.exec_()

    def _select_wav_files(self):
        try:
            data = QFileDialog.getOpenFileNames(None, '', str(Path.home()), '*.wav', '')
            self._filenames_list.addItems(data[0])
        except:
            None

    def _select_output_directory(self):
        try:
            data = QFileDialog.getExistingDirectory(None, '', str(Path.home()))
            self._output_directory.setText(data)
        except:
            None

    def _select_network(self):
        try:
            data = QFileDialog.getOpenFileName(None, '', str(Path.home()), '*.ckpt.meta', '')
            self._network_location.setText(data[0])
        except:
            None
Example #4
0
class ConfigDialog(QDialog):
    """Allow user to modify some persistent configuration settings."""
    
    def __init__(self, parent=None):
        super().__init__(parent)

        self.lineEditPPScannos = QLineEdit()
        self.lineEditPPScannos.setReadOnly(True)
        self.comboScannoFiles = QComboBox()
        
        labelPPScannosLoc = QLabel('PPScannos File')
        labelPPScannosLoc.setBuddy(self.lineEditPPScannos)
        labelScannoLoc = QLabel('Default Scanno File')
        labelScannoLoc.setBuddy(self.comboScannoFiles)

        self.buttonPPScannos = QPushButton('Change')
        self.buttonPPScannos.pressed.connect(self.openFileDlg)
        
        hbox = QHBoxLayout()
        hbox.addWidget(labelPPScannosLoc)
        hbox.addWidget(self.lineEditPPScannos)
        hbox.addWidget(self.buttonPPScannos)
        
        self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)

        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)

        mainLayout = QGridLayout()
        mainLayout.addLayout(hbox, 0, 0, 2, 0)
        mainLayout.addWidget(labelScannoLoc, 1, 0)
        mainLayout.addWidget(self.comboScannoFiles, 1, 1)
        mainLayout.addWidget(self.buttonBox, 5, 0, 1, 2)
        self.setLayout(mainLayout)

        self.populate()
        
        self.lineEditPPScannos.textChanged.connect(self.ppscannosChanged)

        self.setWindowTitle("Configure Gui Scannos")
        self.resize(650, 400)
        
    def populate(self):
        """Fill the dialog."""
        
        settings = QSettings(self)
        ppscannos = settings.value('ppscannos', type=str)
        if not ppscannos:
            #ppscannos = os.environ['HOME']
            ppscannos = os.path.expanduser('~')
            ppscannos = ppscannos + '/ppscannos1/ppscannos1.py'
        self.lineEditPPScannos.setText(ppscannos)
        self.ppscannosChanged()
        
        defaultScanno = settings.value('defaultScannoFile', type=str)
        if defaultScanno:
            idx = self.comboScannoFiles.findText(defaultScanno)
            self.comboScannoFiles.setCurrentIndex(idx)
        #print('settings:', settings.allKeys())
        #print('\tdefault:', settings.value('defaultScannoFile'))
        
    def ppscannosChanged(self):
        self.comboScannoFiles.clear()
        ppscannos = self.lineEditPPScannos.text()
        if not ppscannos:
            return
        scannoFiles = getRCFilesForDir(os.path.dirname(ppscannos))
        if scannoFiles:
            for f in scannoFiles:
                (base, ext) = os.path.splitext(f)
                if ext == '.rc':
                    self.comboScannoFiles.addItem(f)
        idx = self.comboScannoFiles.findText('regex.rc')
        if idx != -1:
            self.comboScannoFiles.setCurrentIndex(idx)
                    
    def openFileDlg(self):
        """Open file picker for ppscannos.py file"""

        d = self.lineEditPPScannos.text()
        if d:
            d = os.path.dirname(d)

        dlg = QFileDialog(self, "Select PPScannos File...", None, "Python Files (*.py);;All Files (*)")
        dlg.setFileMode(QFileDialog.ExistingFile)
        if dlg.exec():
            flist = dlg.selectedFiles()  # returns a list
            if len(flist):
                self.lineEditPPScannos.setText(flist[0])

    def ppscannosPath(self):
        return self.lineEditPPScannos.text()
    
    def scannoFileNames(self):
        lst = []
        for i in range(self.comboScannoFiles.count()):
            lst.append(self.comboScannoFiles.itemText(i))
        return lst
Example #5
0
class FileSelector(QWidget):
    """A FileSelector is a one-line widget for selecting a file."""
    valid = pyqtSignal()
    filenameSelected = pyqtSignal()

    def __init__(self, parent, label, filename=None, dialog_label=None, file_types=None, default_suffix=None,
                 file_mode=QFileDialog.AnyFile):
        QWidget.__init__(self, parent)
        lo = QHBoxLayout(self)
        lo.setContentsMargins(0, 0, 0, 0)
        lo.setSpacing(5)
        # label
        lab = QLabel(label, self)
        lo.addWidget(lab, 0)
        # text field
        self.wfname = QLineEdit(self)
        self.wfname.setReadOnly(True)
        self.setFilename(filename)
        lo.addWidget(self.wfname, 1)
        # selector
        wsel = QToolButton(self)
        wsel.setText("Choose...")
        wsel.clicked.connect(self._chooseFile)
        lo.addWidget(wsel, 0)
        # other init
        self._file_dialog = None
        self._dialog_label = dialog_label or label
        self._file_types = file_types or "All files (*)"
        self._file_mode = file_mode
        self._default_suffix = default_suffix
        self._dir = None

    def _chooseFile(self):
        if self._file_dialog is None:
            dialog = self._file_dialog = QFileDialog(self, self._dialog_label, ".", self._file_types)
            if self._default_suffix:
                dialog.setDefaultSuffix(self._default_suffix)
            dialog.setFileMode(self._file_mode)
            dialog.setModal(True)
            if self._dir is not None:
                dialog.setDirectory(self._dir)
            dialog.filesSelected['QStringList'].connect(self.setFilename)
        return self._file_dialog.exec_()

    def setFilename(self, filename):
        if isinstance(filename, QStringList):
            filename = filename[0]
        filename = (filename and str(filename)) or ''
        self.wfname.setText(filename)
        self.valid.emit(bool(filename))
        self.filenameSelected.emit(filename)

    def setDirectory(self, directory):
        self._dir = directory
        if self._file_dialog is not None:
            self._file_dialog.setDirectory(directory)

    def filename(self):
        return str(self.wfname.text())

    def isValid(self):
        return bool(self.filename())
class EbookScramble(QDialog):
    ''' Read an EPUB/KEPUB/AZW3 de-DRM'd ebook file and
        scramble various contents '''
    def __init__(self,
                 pathtoebook,
                 book_id=None,
                 from_calibre=False,
                 dsettings={},
                 calibre_libpaths=[],
                 parent=None):
        QDialog.__init__(self, parent=parent)
        self.gui = parent
        self.pathtoebook = pathtoebook
        self.book_id = book_id
        self.from_calibre = from_calibre
        self.calibre_libpaths = calibre_libpaths
        self.dsettings = MR_SETTINGS.copy()
        self.dsettings.update(dsettings)

        self.ebook = None
        self.eborig = None
        self.cleanup_dirs = []
        self.cleanup_files = []
        self.log = []

        self.rename_file_map = {}
        self.meta, self.errors = {}, {}
        self.is_scrambled = False
        self.dummyimg = None
        self.dummysvg = ''

        self.setWindowTitle(CAPTION)
        self.setWindowIcon(get_icons('images/plugin_icon.png'))

        # create widgets
        self.buttonBox = QDialogButtonBox(QDialogButtonBox.Save
                                          | QDialogButtonBox.Cancel)
        self.buttonBox.button(
            QDialogButtonBox.Save).setText('Save scrambled ebook && Exit')

        self.browser = QTextBrowser()
        self.browser.setText('')
        self.browser.setLineWrapMode(QTextBrowser.NoWrap)
        self.browser.setMinimumWidth(600)
        self.browser.setMinimumHeight(150)
        self.browser.setReadOnly(True)

        self.savefile = QLineEdit()
        self.savefile.setReadOnly(True)

        self.sourcefile = QLineEdit()
        self.sourcefile.setMinimumWidth(100)
        self.sourcefile.setReadOnly(True)

        self.browsesource = QPushButton('...')
        self.browsesource.setMaximumWidth(30)

        about_button = QPushButton('About', self)
        self.runButton = QPushButton('Scramble now')
        previewButton = QPushButton('Preview content')
        if Webview is None:
            previewButton.setEnabled(False)
            previewButton.setToolTip(
                'Preview not currently available for this book')

        configButton = QPushButton('Change rules *')
        configButton.setToolTip(
            'Only available in standalone version, not calibre plugin')
        metadataButton = QPushButton('View metadata *')
        metadataButton.setToolTip(
            'Only available in standalone version, not calibre plugin')
        errorsButton = QPushButton('View errors *')
        errorsButton.setToolTip(
            'Only available in standalone version, not calibre plugin')

        # layout widgets
        gpsource = QGroupBox('Source ebook:')
        laysource = QGridLayout()
        gpsource.setLayout(laysource)
        laysource.addWidget(self.sourcefile, 0, 0)
        laysource.addWidget(self.browsesource, 0, 1)

        gptarget = QGroupBox('Scrambled ebook:')
        laytarget = QGridLayout()
        gptarget.setLayout(laytarget)
        laytarget.addWidget(self.savefile, 0, 0)

        gpaction = QGroupBox('Actions:')
        layaction = QVBoxLayout()
        gpaction.setLayout(layaction)
        layaction.addWidget(self.runButton)
        layaction.addStretch()
        layaction.addWidget(previewButton)
        layaction.addStretch()

        gpextras = QGroupBox('Extras:')
        layaction2 = QVBoxLayout()
        gpextras.setLayout(layaction2)
        layaction2.addWidget(configButton)
        layaction2.addWidget(metadataButton)
        layaction2.addWidget(errorsButton)

        layaction3 = QVBoxLayout()
        layaction3.addWidget(about_button)
        layaction3.addStretch()
        layaction3.addWidget(gpextras)

        grid = QGridLayout()
        grid.addWidget(self.browser, 0, 0)
        grid.addLayout(layaction3, 0, 1)
        grid.addWidget(gpsource, 2, 0)
        grid.addWidget(gptarget, 3, 0)
        grid.addWidget(gpaction, 2, 1, 2, 1)
        grid.addWidget(self.buttonBox, 5, 0, 1, 2)
        self.setLayout(grid)

        # create connect signals/slots
        about_button.clicked.connect(self.about_button_clicked)
        self.runButton.clicked.connect(self.create_scramble_book)
        previewButton.clicked.connect(self.preview_ebook)
        configButton.clicked.connect(self.change_rules)
        metadataButton.clicked.connect(self.view_metadata)
        errorsButton.clicked.connect(self.view_errors)
        self.browsesource.clicked.connect(self.choose_source_ebook)

        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)

        if self.from_calibre:
            gpextras.setVisible(
                False)  # Extras not available in calibre plugin
            self.browsesource.setVisible(
                False)  # ebook file selection done by calibre

        self.initialise_new_file(self.pathtoebook)

    def initialise_new_file(self, pathtoebook):
        self.meta, self.errors = {}, {}
        self.rename_file_map = {}
        self.is_scrambled = False
        self.dummyimg = None
        self.dummysvg = ''
        self.runButton.setEnabled(True)
        self.buttonBox.button(QDialogButtonBox.Save).setEnabled(False)

        fileok = True
        if not os.path.isfile(pathtoebook):
            fileok = False
        else:
            try:
                self.ebook = get_container(pathtoebook)
            except:
                fileok = False
                msg = "Source ebook must be de-DRM'd and in one of these formats:" \
                    "\n- azw3\n- epub\n- kepub\n- kepub.epub.\n\nPlease select another."
                error_dialog(self,
                             CAPTION,
                             msg,
                             show=True,
                             show_copy_button=True)

        if not fileok:
            self.log.append('No ebook selected yet')
        else:
            self.cleanup_dirs.append(self.ebook.root)
            tdir = PersistentTemporaryDirectory('_scramble_clone_orig')
            self.cleanup_dirs.append(tdir)
            self.eborig = clone_container(self.ebook, tdir)

            dirn, fname, ext, is_kepub_epub = get_fileparts(
                self.ebook.path_to_ebook)
            ext = ext.lower()
            format = 'kepub' if is_kepub_epub else ext

            if self.book_id is not None:
                # calibre library book
                self.cleanup_files.append(self.ebook.path_to_ebook)
            sourcepath = self.ebook.path_to_ebook

            self.dummyimg = get_resources('images/' + format + '.png')
            self.dummysvg = get_resources('images/' + format + '.svg')

            if self.from_calibre:
                # calibre plugin
                self.dirout = ''
            else:
                # standalone version
                self.dirout = dirn
                self.log.append('\n--- New ebook: %s' % sourcepath)

            fn = fname + '_scrambled.'
            fn += 'kepub.' + ext if is_kepub_epub else ext
            self.fname_scrambled_ebook = ascii_text(fn)
            self.sourcefile.setText(sourcepath)
            self.savefile.setText(self.fname_scrambled_ebook)
            self.meta['orig'] = get_metadata(self.ebook)
            self.errors['orig'] = get_run_check_error(self.ebook)

        self.viewlog()

    def accept(self):
        # Any accept actions which need to be done before returning to caller
        savedir = self.choose_save_dir(self.dirout)
        if savedir is not None:
            self.buttonBox.button(QDialogButtonBox.Save).setText('Saving ...')
            self.buttonBox.button(QDialogButtonBox.Save).setEnabled(False)
            msg = ''
            if self.ebook.book_type.lower() == 'azw3':
                msg = '\n   ... please note, rebuilding an AZW3 may take a little longer ...'
            self.log.append('\nSaving now ... %s' % msg)
            self.viewlog()
            path_to_scrambled_ebook = os.path.join(savedir,
                                                   self.fname_scrambled_ebook)
            self.ebook.commit(path_to_scrambled_ebook)
            self.cleanup()
            QDialog.accept(self)

    def reject(self):
        self.cleanup()
        QDialog.reject(self)

    def cleanup(self):
        # delete calibre plugin temp files
        if self.book_id:
            for f in self.cleanup_files:
                try:
                    os.remove(f)
                except:
                    pass

        if self.from_calibre:
            for d in self.cleanup_dirs:
                try:
                    shutil.rmtree(d)
                except:
                    pass

    def choose_save_dir(self, default_dir):
        savedir = None
        askagain = True
        no_save_dir = False
        if default_dir:
            no_save_dir = True
        title = _('Choose destination directory for scrambled ebook')
        while askagain:
            savedir = choose_dir(window=self,
                                 name='',
                                 title=title,
                                 default_dir=default_dir,
                                 no_save_dir=no_save_dir)
            askagain = False
            if savedir is not None:
                savedir = os.path.normpath(savedir)
                if savedir.startswith(tuple(self.calibre_libpaths)):
                    askagain = True
                    msg = []
                    msg.append(
                        'You have selected a destination inside your Calibre library.'
                    )
                    msg.append(savedir)
                    msg.append('\nThis is NOT recommended. Try again.')
                    msg.append('\nPlease avoid the following:')
                    [
                        msg.append(path)
                        for path in sorted(self.calibre_libpaths)
                    ]
                    warning_dialog(self,
                                   'Calibre library chosen',
                                   '\n'.join(msg),
                                   show=True,
                                   show_copy_button=True)
        return savedir

    def choose_source_ebook(self):
        sf = self.sourcefile.text()
        seldir = get_fileparts(sf)[0] if sf else ''
        title = _('Select source ebook')
        selfiles = choose_files(self,
                                name='',
                                title=title,
                                filters=[('Ebooks', ['epub', 'kepub',
                                                     'azw3'])],
                                select_only_single_file=True,
                                default_dir=seldir)
        if selfiles:
            self.pathtoebook = os.path.normpath(selfiles[0])
            self.initialise_new_file(self.pathtoebook)

    def create_scramble_book(self):
        if self.ebook is None:
            return

        sf = self.sourcefile.text()

        self.log.append('\nScrambling %s ...' % sf)
        self.viewlog()

        scrambler = EbookScrambleAction(self.ebook, self.dsettings,
                                        self.dummyimg, self.dummysvg)
        self.rename_file_map = {
            k: v
            for (k, v) in iteritems(scrambler.file_map)
        }

        self.meta['scramb'] = get_metadata(self.ebook)
        self.errors['scramb'] = get_run_check_error(self.ebook)
        self.buttonBox.button(QDialogButtonBox.Save).setEnabled(True)
        self.runButton.setEnabled(False)
        self.is_scrambled = True

        self.log.append(scrambler.results)
        self.log.append('\n... finished')
        self.viewlog()

    def change_rules(self):
        dlg = EbookScrambleRulesDlg(self.dsettings, parent=self.gui)
        if dlg.exec_():
            self.dsettings.update(dlg.dsettings)
            self.log.append('\n--- Scrambling rules updated ---')
        self.viewlog()

    def preview_ebook(self):
        if self.ebook is None:
            return

        dlg = EbookScramblePreviewDlg(self.ebook,
                                      self.eborig,
                                      self.is_scrambled,
                                      self.rename_file_map,
                                      parent=self.gui)
        dlg.exec_()
        dlg.raise_()

    def view_metadata(self):
        if self.ebook is None:
            return

        dlg = EbookScrambleMetadataDlg(self.meta, parent=self.gui)
        dlg.exec_()
        dlg.raise_()

    def view_errors(self):
        if self.ebook is None:
            return

        dlg = EbookScrambleErrorsDlg(self.errors, parent=self.gui)
        dlg.exec_()
        dlg.raise_()

    def display_settings(self):
        self.log.append('\nCurrent Scramble rules:')
        [
            self.log.append('%s: %s' % (k, v))
            for (k, v) in sorted(iteritems(self.dsettings))
        ]

    def viewlog(self):
        self.browser.setText('\n'.join(self.log))
        self.browser.moveCursor(QTextCursor.End)
        QApplication.instance().processEvents()

    def about_button_clicked(self):
        # Get the about text from a file inside the plugin zip file
        # The get_resources function is a builtin function defined for all your
        # plugin code. It loads files from the plugin zip file. It returns
        # the bytes from the specified file.
        #
        # Note that if you are loading more than one file, for performance, you
        # should pass a list of names to get_resources. In this case,
        # get_resources will return a dictionary mapping names to bytes. Names that
        # are not found in the zip file will not be in the returned dictionary.

        source = 'calibre plugin' if self.from_calibre else 'standalone'
        text = get_resources('about.txt')
        QMessageBox.about(self, 'About %s %s' % (CAPTION, source), text)
Example #7
0
    def __init__(self, parent = None):
        super(MainWidget, self).__init__(parent)

        # member variables
        self._lTheorySpd = 0
        self._rTheorySpd = 0
        self._serialSend = SerialSend()

        # mainWindow properties
        self.setObjectName('MainWidget')
        self.setWindowIcon(QIcon(':/image/default/app.icon'))
        self.setWindowTitle('%s V%s' % (
                            qApp.applicationDisplayName(),
                            qApp.applicationVersion()))
        self.resize(800, 480)

        # mainWindow layout

        # top

        self.groupBoxTop = QGroupBox(self)
        self.groupBoxTop.setObjectName('groupBoxTop')

        # command dashboard
        buttonLeftPower = JSwitchButton(parent = self.groupBoxTop)
        buttonRightPower = JSwitchButton(parent = self.groupBoxTop)
        buttonSettings = QPushButton(self.groupBoxTop)
        buttonHistory = QPushButton(self.groupBoxTop)
        buttonQuit = QPushButton(self.groupBoxTop)

        buttonLeftPower.setObjectName('buttonLeftPower')
        buttonRightPower.setObjectName('buttonRightPower')
        buttonSettings.setObjectName('buttonSettings')
        buttonHistory.setObjectName('buttonHistory')
        buttonQuit.setObjectName('buttonQuit')

        areaPortState = QWidget(self)
        areaPortState.setObjectName('areaPortState')
        areaPortState.setStyleSheet('QWidget#areaPortState{border-radius:3px;'
                                    'border:1px solid #505050;'
                                    'background-color:rgba(64,64,64,50);}')
        vertLayoutPortState = QVBoxLayout(areaPortState)
        vertLayoutPortState.setContentsMargins(50, 2, 50, 2)
        vertLayoutPortState.setSpacing(3)

        buttonPortState = JSwitchButton(pixmap = QPixmap(':/carmonitor/image/button-port-state.png'), parent = areaPortState)
        buttonPortState.setObjectName('buttonPortState')
        vertLayoutPortState.addWidget(QLabel('串口', areaPortState), 0, Qt.AlignHCenter)
        vertLayoutPortState.addWidget(buttonPortState)

        #
        horiLayoutTop = QHBoxLayout(self.groupBoxTop)
        horiLayoutTop.setContentsMargins(0, 0, 0, 0)
        horiLayoutTop.addSpacing(25)
        horiLayoutTop.addWidget(buttonSettings, 0, Qt.AlignLeft)
        horiLayoutTop.addSpacing(20)
        horiLayoutTop.addWidget(buttonHistory, 0, Qt.AlignLeft)
        horiLayoutTop.addSpacing(65)
        horiLayoutTop.addWidget(buttonLeftPower)
        horiLayoutTop.addWidget(QLabel('左电源开关', self.groupBoxTop))
        horiLayoutTop.addStretch()
        horiLayoutTop.addWidget(areaPortState, 0, Qt.AlignTop)
        horiLayoutTop.addStretch()
        horiLayoutTop.addWidget(QLabel('右电源开关', self.groupBoxTop))
        horiLayoutTop.addWidget(buttonRightPower)
        horiLayoutTop.addSpacing(150)
        horiLayoutTop.addWidget(buttonQuit, 0, Qt.AlignRight)
        horiLayoutTop.addSpacing(25)

        # middle

        # curves
        self.curveLBP = CurveWidget(title = '左刹车压力(MPa)', parent = self)
        self.curveLRP = CurveWidget(title = '左转速(r/min)', parent = self)
        self.curveRBP = CurveWidget(title = '右刹车压力(MPa)', parent = self)
        self.curveRRP = CurveWidget(title = '右转速(r/min)', parent = self)

        self.curveLBP.setObjectName('curveLBP')
        self.curveLRP.setObjectName('curveLRP')
        self.curveRBP.setObjectName('curveRBP')
        self.curveRRP.setObjectName('curveRRP')

        # self.curveLBP.setAxisScale(QwtPlot.yLeft, 0, 30, 5)

        # areaMiddle
        self.areaMiddle = QWidget(self)
        self.areaMiddle.setObjectName('areaMiddle')
        self.areaMiddle.setFixedWidth(280)

        #
        groupBoxStatus = QGroupBox(self)
        groupBoxStatus.setObjectName('groupBoxStatus')

        # status-view
        gridLayoutStatus = QGridLayout(groupBoxStatus)
        gridLayoutStatus.setContentsMargins(5, 5, 5, 5)
        gridLayoutStatus.setHorizontalSpacing(8)
        gridLayoutStatus.setVerticalSpacing(3)

        # Brake-Command
        editLeftBrakeCmd = QLineEdit(groupBoxStatus)
        editRightBrakeCmd = QLineEdit(groupBoxStatus)
        editLeftBrakeCmd.setObjectName('editLeftBrakeCmd')
        editRightBrakeCmd.setObjectName('editRightBrakeCmd')
        editLeftBrakeCmd.setReadOnly(True)
        editRightBrakeCmd.setReadOnly(True)
        gridLayoutStatus.addWidget(QLabel('刹车指令:', groupBoxStatus),
                                   0, 0, 1, 2, Qt.AlignCenter)
        gridLayoutStatus.addWidget(editLeftBrakeCmd, 1, 0, 1, 1)
        gridLayoutStatus.addWidget(editRightBrakeCmd, 1, 1, 1, 1)

        # Major Brake Pressure
        self.editMLeftBrakeP = QLineEdit(groupBoxStatus)
        self.editMRightBrakeP = QLineEdit(groupBoxStatus)
        self.editMLeftBrakeP.setObjectName('editMLeftBrakeP')
        self.editMRightBrakeP.setObjectName('editMRightBrakeP')
        self.editMLeftBrakeP.setReadOnly(True)
        self.editMRightBrakeP.setReadOnly(True)
        gridLayoutStatus.addWidget(QLabel('主刹车压力:', groupBoxStatus),
                                   2, 0, 1, 2, Qt.AlignCenter)
        gridLayoutStatus.addWidget(self.editMLeftBrakeP, 3, 0, 1, 1)
        gridLayoutStatus.addWidget(self.editMRightBrakeP, 3, 1, 1, 1)

        # Assistant Brake Pressure
        self.editALeftBrakeP = QLineEdit(groupBoxStatus)
        self.editARightBrakeP = QLineEdit(groupBoxStatus)
        self.editALeftBrakeP.setObjectName('editALeftBrakeP')
        self.editARightBrakeP.setObjectName('editARightBrakeP')
        self.editALeftBrakeP.setReadOnly(True)
        self.editARightBrakeP.setReadOnly(True)
        gridLayoutStatus.addWidget(QLabel('副刹车压力:', groupBoxStatus),
                                   4, 0, 1, 2, Qt.AlignCenter)
        gridLayoutStatus.addWidget(self.editALeftBrakeP, 5, 0, 1, 1)
        gridLayoutStatus.addWidget(self.editARightBrakeP, 5, 1, 1, 1)

        # Rotation Rate
        self.editLeftRotateRate = QLineEdit(groupBoxStatus)
        self.editRightRotateRate = QLineEdit(groupBoxStatus)
        self.editLeftRotateRate.setObjectName('editLeftRotateRate')
        self.editRightRotateRate.setObjectName('editRightRotateRate')
        gridLayoutStatus.addWidget(QLabel('实际转速:', groupBoxStatus),
                                   6, 0, 1, 2, Qt.AlignCenter)
        gridLayoutStatus.addWidget(self.editLeftRotateRate, 7, 0, 1, 1)
        gridLayoutStatus.addWidget(self.editRightRotateRate, 7, 1, 1, 1)

        # Theory Rotation Rate
        self.editTheoryLeftRotateRate = QLineEdit(groupBoxStatus)
        self.editTheoryRightRotateRate = QLineEdit(groupBoxStatus)
        self.editTheoryLeftRotateRate.setObjectName('editTheoryLeftRotateRate')
        self.editTheoryRightRotateRate.setObjectName('editTheoryRightRotateRate')
        gridLayoutStatus.addWidget(QLabel('理论转速:', groupBoxStatus),
                                   8, 0, 1, 2, Qt.AlignCenter)
        gridLayoutStatus.addWidget(self.editTheoryLeftRotateRate, 9, 0, 1, 1)
        gridLayoutStatus.addWidget(self.editTheoryRightRotateRate, 9, 1, 1, 1)

        #
        groupBoxCtrl = QGroupBox(self)
        groupBoxCtrl.setObjectName('groupBoxCtrl')

        # status-view
        gridLayoutCtrl = QGridLayout(groupBoxCtrl)
        gridLayoutCtrl.setContentsMargins(5, 5, 5, 5)
        gridLayoutCtrl.setSpacing(20)

        # left-button
        buttonLeftDashboard = JDashButton('左指令旋钮', groupBoxCtrl)
        buttonLeftSpeedGain = JDashButton('左转速增益', groupBoxCtrl)
        buttonLeftSpeedKnob = JDashButton('左转速增益', groupBoxCtrl)
        buttonLeftTracksip = JTracksipButton(parent = groupBoxCtrl)
        buttonLeftDashboard.setObjectName('buttonLeftDashboard')
        buttonLeftSpeedGain.setObjectName('buttonLeftSpeedGain')
        buttonLeftSpeedKnob.setObjectName('buttonLeftSpeedKnob')
        buttonLeftTracksip.setObjectName('buttonLeftTracksip')
        buttonLeftTracksip.setFixedSize(110, 45)

        # right-button
        buttonRightDashboard = JDashButton('右指令旋钮', groupBoxCtrl)
        buttonRightSpeedGain = JDashButton('右转速增益', groupBoxCtrl)
        buttonRightSpeedKnob = JDashButton('右转速增益', groupBoxCtrl)
        buttonRightTracksip = JTracksipButton(parent = groupBoxCtrl)
        buttonRightDashboard.setObjectName('buttonRightDashboard')
        buttonRightSpeedGain.setObjectName('buttonRightSpeedGain')
        buttonRightSpeedKnob.setObjectName('buttonRightSpeedKnob')
        buttonRightTracksip.setObjectName('buttonRightTracksip')
        buttonRightTracksip.setFixedSize(110, 45)

        horiLayoutTracksip = QHBoxLayout()
        horiLayoutTracksip.setContentsMargins(0, 0, 0, 0)
        horiLayoutTracksip.setSpacing(5)
        horiLayoutTracksip.addWidget(buttonLeftTracksip)
        horiLayoutTracksip.addWidget(QLabel('打滑', self), 0, Qt.AlignHCenter)
        horiLayoutTracksip.addWidget(buttonRightTracksip)
        gridLayoutCtrl.addLayout(horiLayoutTracksip, 0, 0, 1, 2)

        horiLayoutDashboard = QHBoxLayout()
        horiLayoutDashboard.setContentsMargins(0, 0, 0, 0)
        horiLayoutDashboard.setSpacing(5)
        horiLayoutDashboard.addWidget(buttonLeftDashboard)
        horiLayoutDashboard.addWidget(QLabel('    ', self), 0, Qt.AlignHCenter)
        horiLayoutDashboard.addWidget(buttonRightDashboard)
        gridLayoutCtrl.addLayout(horiLayoutDashboard, 1, 0, 1, 2)

        horiLayoutSpeedGain = QHBoxLayout()
        horiLayoutSpeedGain.setContentsMargins(0, 0, 0, 0)
        horiLayoutSpeedGain.setSpacing(5)
        horiLayoutSpeedGain.addWidget(buttonLeftSpeedGain)
        horiLayoutSpeedGain.addWidget(QLabel('(粗调)', self), 0, Qt.AlignHCenter)
        horiLayoutSpeedGain.addWidget(buttonRightSpeedGain)
        gridLayoutCtrl.addLayout(horiLayoutSpeedGain, 2, 0, 1, 2)


        horiLayoutSpeedKnob = QHBoxLayout()
        horiLayoutSpeedKnob.setContentsMargins(0, 0, 0, 0)
        horiLayoutSpeedKnob.setSpacing(5)
        horiLayoutSpeedKnob.addWidget(buttonLeftSpeedKnob)
        horiLayoutSpeedKnob.addWidget(QLabel('(细调)', self), 0, Qt.AlignHCenter)
        horiLayoutSpeedKnob.addWidget(buttonRightSpeedKnob)
        gridLayoutCtrl.addLayout(horiLayoutSpeedKnob, 3, 0, 1, 2)

        #
        vertLayoutMid = QVBoxLayout(self.areaMiddle)
        vertLayoutMid.setContentsMargins(0, 0, 0, 0)
        vertLayoutMid.setSpacing(0)
        vertLayoutMid.addWidget(groupBoxStatus)
        vertLayoutMid.addWidget(groupBoxCtrl)
        vertLayoutMid.addSpacing(20)

        #
        gridLayoutBottom = QGridLayout()
        gridLayoutBottom.setContentsMargins(0, 0, 0, 0)
        gridLayoutBottom.setSpacing(1)
        gridLayoutBottom.addWidget(self.curveLBP, 0, 0, 1, 1)
        gridLayoutBottom.addWidget(self.curveLRP, 1, 0, 1, 1)
        gridLayoutBottom.addWidget(self.areaMiddle, 0, 1, 2, 1)
        gridLayoutBottom.addWidget(self.curveRBP, 0, 2, 1, 1)
        gridLayoutBottom.addWidget(self.curveRRP, 1, 2, 1, 1)

        # main-layout
        vertLayoutMain = QVBoxLayout(self)
        vertLayoutMain.setContentsMargins(5, 5, 5, 5)
        vertLayoutMain.addWidget(self.groupBoxTop)
        vertLayoutMain.addLayout(gridLayoutBottom)

        # global properties
        qApp.setProperty('MainWidget', self)
        self._serialProxy = SerialPortProxy(self)
        self._serialProxy._serialSimulate = SerialSimulate(self._serialProxy)  #
        qApp.setProperty('SerialProxy', self._serialProxy)

        #
        buttonSettings.clicked.connect(self.onButtonSettingsClicked)
        buttonHistory.clicked.connect(self.onButtonHistoryClicked)
        buttonPortState.clicked.connect(self.onButtonPortStateClicked)
        buttonQuit.clicked.connect(self.onButtonQuitClicked)

        # curves
        self.curveLBP.doubleClicked.connect(self.onCurveDoubleClicked)
        self.curveLRP.doubleClicked.connect(self.onCurveDoubleClicked)
        self.curveRBP.doubleClicked.connect(self.onCurveDoubleClicked)
        self.curveRRP.doubleClicked.connect(self.onCurveDoubleClicked)

        # switch-power
        buttonLeftPower.stateChanged.connect(self.onButtonLeftPowerStateChanged)
        buttonRightPower.stateChanged.connect(self.onButtonRightPowerStateChanged)

        # switch-tracksip
        buttonLeftTracksip.stateChanged.connect(self.onButtonLeftTracksipStateChanged)
        buttonRightTracksip.stateChanged.connect(self.onButtonRightTracksipStateChanged)

        self._serialProxy.stateChanged.connect(self.onSerialStateChanged)
        self._serialProxy.serialPortError.connect(self.onSerialPortError)
        self._serialProxy.displayRespond.connect(self.onSerialDisplayRespond)

        #
        buttonLeftSpeedGain.clicked.connect(self.execSliderWidget)
        buttonLeftSpeedKnob.clicked.connect(self.execSliderWidget)
        buttonRightSpeedGain.clicked.connect(self.execSliderWidget)
        buttonRightSpeedKnob.clicked.connect(self.execSliderWidget)

        # final initialization

        self.editMLeftBrakeP.setText('0 MPa')
        self.editMRightBrakeP.setText('0 MPa')
        self.editALeftBrakeP.setText('0 MPa')
        self.editARightBrakeP.setText('0 MPa')

        self.editLeftRotateRate.setText('0 r/min')
        self.editRightRotateRate.setText('0 r/min')
        self.editTheoryLeftRotateRate.setText('0 r/min')
        self.editTheoryRightRotateRate.setText('0 r/min')

        #
        c_memset(self._serialSend, 0, ctypes.sizeof(self._serialSend))

        # SQL
        sqlName = applicationDirPath() \
            + '/../data/cm-' \
            + QDateTime.currentDateTime().toLocalTime().toString('yyyy-MM-dd-HH-mm-ss') \
            + '.db'
        if not DatabaseMgr().create(sqlName):
            assert(False)

        # start serialport
        self._serialProxy.start()

        #
        buttonLeftTracksip.setState(self._serialSend.ctrlWord.lTracksip)
        buttonRightTracksip.setState(self._serialSend.ctrlWord.lTracksip)
Example #8
0
class MainWidget(QWidget):
    '''
    class MainWidget
    '''
    def __init__(self, parent = None):
        super(MainWidget, self).__init__(parent)

        # member variables
        self._lTheorySpd = 0
        self._rTheorySpd = 0
        self._serialSend = SerialSend()

        # mainWindow properties
        self.setObjectName('MainWidget')
        self.setWindowIcon(QIcon(':/image/default/app.icon'))
        self.setWindowTitle('%s V%s' % (
                            qApp.applicationDisplayName(),
                            qApp.applicationVersion()))
        self.resize(800, 480)

        # mainWindow layout

        # top

        self.groupBoxTop = QGroupBox(self)
        self.groupBoxTop.setObjectName('groupBoxTop')

        # command dashboard
        buttonLeftPower = JSwitchButton(parent = self.groupBoxTop)
        buttonRightPower = JSwitchButton(parent = self.groupBoxTop)
        buttonSettings = QPushButton(self.groupBoxTop)
        buttonHistory = QPushButton(self.groupBoxTop)
        buttonQuit = QPushButton(self.groupBoxTop)

        buttonLeftPower.setObjectName('buttonLeftPower')
        buttonRightPower.setObjectName('buttonRightPower')
        buttonSettings.setObjectName('buttonSettings')
        buttonHistory.setObjectName('buttonHistory')
        buttonQuit.setObjectName('buttonQuit')

        areaPortState = QWidget(self)
        areaPortState.setObjectName('areaPortState')
        areaPortState.setStyleSheet('QWidget#areaPortState{border-radius:3px;'
                                    'border:1px solid #505050;'
                                    'background-color:rgba(64,64,64,50);}')
        vertLayoutPortState = QVBoxLayout(areaPortState)
        vertLayoutPortState.setContentsMargins(50, 2, 50, 2)
        vertLayoutPortState.setSpacing(3)

        buttonPortState = JSwitchButton(pixmap = QPixmap(':/carmonitor/image/button-port-state.png'), parent = areaPortState)
        buttonPortState.setObjectName('buttonPortState')
        vertLayoutPortState.addWidget(QLabel('串口', areaPortState), 0, Qt.AlignHCenter)
        vertLayoutPortState.addWidget(buttonPortState)

        #
        horiLayoutTop = QHBoxLayout(self.groupBoxTop)
        horiLayoutTop.setContentsMargins(0, 0, 0, 0)
        horiLayoutTop.addSpacing(25)
        horiLayoutTop.addWidget(buttonSettings, 0, Qt.AlignLeft)
        horiLayoutTop.addSpacing(20)
        horiLayoutTop.addWidget(buttonHistory, 0, Qt.AlignLeft)
        horiLayoutTop.addSpacing(65)
        horiLayoutTop.addWidget(buttonLeftPower)
        horiLayoutTop.addWidget(QLabel('左电源开关', self.groupBoxTop))
        horiLayoutTop.addStretch()
        horiLayoutTop.addWidget(areaPortState, 0, Qt.AlignTop)
        horiLayoutTop.addStretch()
        horiLayoutTop.addWidget(QLabel('右电源开关', self.groupBoxTop))
        horiLayoutTop.addWidget(buttonRightPower)
        horiLayoutTop.addSpacing(150)
        horiLayoutTop.addWidget(buttonQuit, 0, Qt.AlignRight)
        horiLayoutTop.addSpacing(25)

        # middle

        # curves
        self.curveLBP = CurveWidget(title = '左刹车压力(MPa)', parent = self)
        self.curveLRP = CurveWidget(title = '左转速(r/min)', parent = self)
        self.curveRBP = CurveWidget(title = '右刹车压力(MPa)', parent = self)
        self.curveRRP = CurveWidget(title = '右转速(r/min)', parent = self)

        self.curveLBP.setObjectName('curveLBP')
        self.curveLRP.setObjectName('curveLRP')
        self.curveRBP.setObjectName('curveRBP')
        self.curveRRP.setObjectName('curveRRP')

        # self.curveLBP.setAxisScale(QwtPlot.yLeft, 0, 30, 5)

        # areaMiddle
        self.areaMiddle = QWidget(self)
        self.areaMiddle.setObjectName('areaMiddle')
        self.areaMiddle.setFixedWidth(280)

        #
        groupBoxStatus = QGroupBox(self)
        groupBoxStatus.setObjectName('groupBoxStatus')

        # status-view
        gridLayoutStatus = QGridLayout(groupBoxStatus)
        gridLayoutStatus.setContentsMargins(5, 5, 5, 5)
        gridLayoutStatus.setHorizontalSpacing(8)
        gridLayoutStatus.setVerticalSpacing(3)

        # Brake-Command
        editLeftBrakeCmd = QLineEdit(groupBoxStatus)
        editRightBrakeCmd = QLineEdit(groupBoxStatus)
        editLeftBrakeCmd.setObjectName('editLeftBrakeCmd')
        editRightBrakeCmd.setObjectName('editRightBrakeCmd')
        editLeftBrakeCmd.setReadOnly(True)
        editRightBrakeCmd.setReadOnly(True)
        gridLayoutStatus.addWidget(QLabel('刹车指令:', groupBoxStatus),
                                   0, 0, 1, 2, Qt.AlignCenter)
        gridLayoutStatus.addWidget(editLeftBrakeCmd, 1, 0, 1, 1)
        gridLayoutStatus.addWidget(editRightBrakeCmd, 1, 1, 1, 1)

        # Major Brake Pressure
        self.editMLeftBrakeP = QLineEdit(groupBoxStatus)
        self.editMRightBrakeP = QLineEdit(groupBoxStatus)
        self.editMLeftBrakeP.setObjectName('editMLeftBrakeP')
        self.editMRightBrakeP.setObjectName('editMRightBrakeP')
        self.editMLeftBrakeP.setReadOnly(True)
        self.editMRightBrakeP.setReadOnly(True)
        gridLayoutStatus.addWidget(QLabel('主刹车压力:', groupBoxStatus),
                                   2, 0, 1, 2, Qt.AlignCenter)
        gridLayoutStatus.addWidget(self.editMLeftBrakeP, 3, 0, 1, 1)
        gridLayoutStatus.addWidget(self.editMRightBrakeP, 3, 1, 1, 1)

        # Assistant Brake Pressure
        self.editALeftBrakeP = QLineEdit(groupBoxStatus)
        self.editARightBrakeP = QLineEdit(groupBoxStatus)
        self.editALeftBrakeP.setObjectName('editALeftBrakeP')
        self.editARightBrakeP.setObjectName('editARightBrakeP')
        self.editALeftBrakeP.setReadOnly(True)
        self.editARightBrakeP.setReadOnly(True)
        gridLayoutStatus.addWidget(QLabel('副刹车压力:', groupBoxStatus),
                                   4, 0, 1, 2, Qt.AlignCenter)
        gridLayoutStatus.addWidget(self.editALeftBrakeP, 5, 0, 1, 1)
        gridLayoutStatus.addWidget(self.editARightBrakeP, 5, 1, 1, 1)

        # Rotation Rate
        self.editLeftRotateRate = QLineEdit(groupBoxStatus)
        self.editRightRotateRate = QLineEdit(groupBoxStatus)
        self.editLeftRotateRate.setObjectName('editLeftRotateRate')
        self.editRightRotateRate.setObjectName('editRightRotateRate')
        gridLayoutStatus.addWidget(QLabel('实际转速:', groupBoxStatus),
                                   6, 0, 1, 2, Qt.AlignCenter)
        gridLayoutStatus.addWidget(self.editLeftRotateRate, 7, 0, 1, 1)
        gridLayoutStatus.addWidget(self.editRightRotateRate, 7, 1, 1, 1)

        # Theory Rotation Rate
        self.editTheoryLeftRotateRate = QLineEdit(groupBoxStatus)
        self.editTheoryRightRotateRate = QLineEdit(groupBoxStatus)
        self.editTheoryLeftRotateRate.setObjectName('editTheoryLeftRotateRate')
        self.editTheoryRightRotateRate.setObjectName('editTheoryRightRotateRate')
        gridLayoutStatus.addWidget(QLabel('理论转速:', groupBoxStatus),
                                   8, 0, 1, 2, Qt.AlignCenter)
        gridLayoutStatus.addWidget(self.editTheoryLeftRotateRate, 9, 0, 1, 1)
        gridLayoutStatus.addWidget(self.editTheoryRightRotateRate, 9, 1, 1, 1)

        #
        groupBoxCtrl = QGroupBox(self)
        groupBoxCtrl.setObjectName('groupBoxCtrl')

        # status-view
        gridLayoutCtrl = QGridLayout(groupBoxCtrl)
        gridLayoutCtrl.setContentsMargins(5, 5, 5, 5)
        gridLayoutCtrl.setSpacing(20)

        # left-button
        buttonLeftDashboard = JDashButton('左指令旋钮', groupBoxCtrl)
        buttonLeftSpeedGain = JDashButton('左转速增益', groupBoxCtrl)
        buttonLeftSpeedKnob = JDashButton('左转速增益', groupBoxCtrl)
        buttonLeftTracksip = JTracksipButton(parent = groupBoxCtrl)
        buttonLeftDashboard.setObjectName('buttonLeftDashboard')
        buttonLeftSpeedGain.setObjectName('buttonLeftSpeedGain')
        buttonLeftSpeedKnob.setObjectName('buttonLeftSpeedKnob')
        buttonLeftTracksip.setObjectName('buttonLeftTracksip')
        buttonLeftTracksip.setFixedSize(110, 45)

        # right-button
        buttonRightDashboard = JDashButton('右指令旋钮', groupBoxCtrl)
        buttonRightSpeedGain = JDashButton('右转速增益', groupBoxCtrl)
        buttonRightSpeedKnob = JDashButton('右转速增益', groupBoxCtrl)
        buttonRightTracksip = JTracksipButton(parent = groupBoxCtrl)
        buttonRightDashboard.setObjectName('buttonRightDashboard')
        buttonRightSpeedGain.setObjectName('buttonRightSpeedGain')
        buttonRightSpeedKnob.setObjectName('buttonRightSpeedKnob')
        buttonRightTracksip.setObjectName('buttonRightTracksip')
        buttonRightTracksip.setFixedSize(110, 45)

        horiLayoutTracksip = QHBoxLayout()
        horiLayoutTracksip.setContentsMargins(0, 0, 0, 0)
        horiLayoutTracksip.setSpacing(5)
        horiLayoutTracksip.addWidget(buttonLeftTracksip)
        horiLayoutTracksip.addWidget(QLabel('打滑', self), 0, Qt.AlignHCenter)
        horiLayoutTracksip.addWidget(buttonRightTracksip)
        gridLayoutCtrl.addLayout(horiLayoutTracksip, 0, 0, 1, 2)

        horiLayoutDashboard = QHBoxLayout()
        horiLayoutDashboard.setContentsMargins(0, 0, 0, 0)
        horiLayoutDashboard.setSpacing(5)
        horiLayoutDashboard.addWidget(buttonLeftDashboard)
        horiLayoutDashboard.addWidget(QLabel('    ', self), 0, Qt.AlignHCenter)
        horiLayoutDashboard.addWidget(buttonRightDashboard)
        gridLayoutCtrl.addLayout(horiLayoutDashboard, 1, 0, 1, 2)

        horiLayoutSpeedGain = QHBoxLayout()
        horiLayoutSpeedGain.setContentsMargins(0, 0, 0, 0)
        horiLayoutSpeedGain.setSpacing(5)
        horiLayoutSpeedGain.addWidget(buttonLeftSpeedGain)
        horiLayoutSpeedGain.addWidget(QLabel('(粗调)', self), 0, Qt.AlignHCenter)
        horiLayoutSpeedGain.addWidget(buttonRightSpeedGain)
        gridLayoutCtrl.addLayout(horiLayoutSpeedGain, 2, 0, 1, 2)


        horiLayoutSpeedKnob = QHBoxLayout()
        horiLayoutSpeedKnob.setContentsMargins(0, 0, 0, 0)
        horiLayoutSpeedKnob.setSpacing(5)
        horiLayoutSpeedKnob.addWidget(buttonLeftSpeedKnob)
        horiLayoutSpeedKnob.addWidget(QLabel('(细调)', self), 0, Qt.AlignHCenter)
        horiLayoutSpeedKnob.addWidget(buttonRightSpeedKnob)
        gridLayoutCtrl.addLayout(horiLayoutSpeedKnob, 3, 0, 1, 2)

        #
        vertLayoutMid = QVBoxLayout(self.areaMiddle)
        vertLayoutMid.setContentsMargins(0, 0, 0, 0)
        vertLayoutMid.setSpacing(0)
        vertLayoutMid.addWidget(groupBoxStatus)
        vertLayoutMid.addWidget(groupBoxCtrl)
        vertLayoutMid.addSpacing(20)

        #
        gridLayoutBottom = QGridLayout()
        gridLayoutBottom.setContentsMargins(0, 0, 0, 0)
        gridLayoutBottom.setSpacing(1)
        gridLayoutBottom.addWidget(self.curveLBP, 0, 0, 1, 1)
        gridLayoutBottom.addWidget(self.curveLRP, 1, 0, 1, 1)
        gridLayoutBottom.addWidget(self.areaMiddle, 0, 1, 2, 1)
        gridLayoutBottom.addWidget(self.curveRBP, 0, 2, 1, 1)
        gridLayoutBottom.addWidget(self.curveRRP, 1, 2, 1, 1)

        # main-layout
        vertLayoutMain = QVBoxLayout(self)
        vertLayoutMain.setContentsMargins(5, 5, 5, 5)
        vertLayoutMain.addWidget(self.groupBoxTop)
        vertLayoutMain.addLayout(gridLayoutBottom)

        # global properties
        qApp.setProperty('MainWidget', self)
        self._serialProxy = SerialPortProxy(self)
        self._serialProxy._serialSimulate = SerialSimulate(self._serialProxy)  #
        qApp.setProperty('SerialProxy', self._serialProxy)

        #
        buttonSettings.clicked.connect(self.onButtonSettingsClicked)
        buttonHistory.clicked.connect(self.onButtonHistoryClicked)
        buttonPortState.clicked.connect(self.onButtonPortStateClicked)
        buttonQuit.clicked.connect(self.onButtonQuitClicked)

        # curves
        self.curveLBP.doubleClicked.connect(self.onCurveDoubleClicked)
        self.curveLRP.doubleClicked.connect(self.onCurveDoubleClicked)
        self.curveRBP.doubleClicked.connect(self.onCurveDoubleClicked)
        self.curveRRP.doubleClicked.connect(self.onCurveDoubleClicked)

        # switch-power
        buttonLeftPower.stateChanged.connect(self.onButtonLeftPowerStateChanged)
        buttonRightPower.stateChanged.connect(self.onButtonRightPowerStateChanged)

        # switch-tracksip
        buttonLeftTracksip.stateChanged.connect(self.onButtonLeftTracksipStateChanged)
        buttonRightTracksip.stateChanged.connect(self.onButtonRightTracksipStateChanged)

        self._serialProxy.stateChanged.connect(self.onSerialStateChanged)
        self._serialProxy.serialPortError.connect(self.onSerialPortError)
        self._serialProxy.displayRespond.connect(self.onSerialDisplayRespond)

        #
        buttonLeftSpeedGain.clicked.connect(self.execSliderWidget)
        buttonLeftSpeedKnob.clicked.connect(self.execSliderWidget)
        buttonRightSpeedGain.clicked.connect(self.execSliderWidget)
        buttonRightSpeedKnob.clicked.connect(self.execSliderWidget)

        # final initialization

        self.editMLeftBrakeP.setText('0 MPa')
        self.editMRightBrakeP.setText('0 MPa')
        self.editALeftBrakeP.setText('0 MPa')
        self.editARightBrakeP.setText('0 MPa')

        self.editLeftRotateRate.setText('0 r/min')
        self.editRightRotateRate.setText('0 r/min')
        self.editTheoryLeftRotateRate.setText('0 r/min')
        self.editTheoryRightRotateRate.setText('0 r/min')

        #
        c_memset(self._serialSend, 0, ctypes.sizeof(self._serialSend))

        # SQL
        sqlName = applicationDirPath() \
            + '/../data/cm-' \
            + QDateTime.currentDateTime().toLocalTime().toString('yyyy-MM-dd-HH-mm-ss') \
            + '.db'
        if not DatabaseMgr().create(sqlName):
            assert(False)

        # start serialport
        self._serialProxy.start()

        #
        buttonLeftTracksip.setState(self._serialSend.ctrlWord.lTracksip)
        buttonRightTracksip.setState(self._serialSend.ctrlWord.lTracksip)

    def onButtonSettingsClicked(self):
        self._serialProxy.save()
        #
        settingsWidget = SettingsWidget(self)
        settingsWidget.exec_()

        self._serialProxy.restore()

    def onButtonHistoryClicked(self):
        self._serialProxy.save()
        DatabaseMgr().save()
        #
        historyWidget = HistoryWidget(self)
        historyWidget.showMaximized()
        historyWidget.exec_()

        DatabaseMgr().restore()
        self._serialProxy.restore()

    def onButtonPortStateClicked(self, checked):
        if checked:
            self._serialProxy.start()
        else:
            self._serialProxy.stop()

    def onButtonQuitClicked(self):
        if QMessageBox.warning(self, '警告', '你确定要退出软件吗?',
                               QMessageBox.Ok | QMessageBox.No) == QMessageBox.Ok:
            self.close()

    def onCurveDoubleClicked(self, checked):
        objectName = self.sender().objectName()
        if objectName == 'curveLBP':
            self.groupBoxTop.setVisible(checked)
            self.areaMiddle.setVisible(checked)
            self.curveLRP.setVisible(checked)
            self.curveRBP.setVisible(checked)
            self.curveRRP.setVisible(checked)
        elif objectName == 'curveLRP':
            self.groupBoxTop.setVisible(checked)
            self.areaMiddle.setVisible(checked)
            self.curveLBP.setVisible(checked)
            self.curveRBP.setVisible(checked)
            self.curveRRP.setVisible(checked)
        elif objectName == 'curveRBP':
            self.groupBoxTop.setVisible(checked)
            self.areaMiddle.setVisible(checked)
            self.curveLBP.setVisible(checked)
            self.curveLRP.setVisible(checked)
            self.curveRRP.setVisible(checked)
        elif objectName == 'curveRRP':
            self.groupBoxTop.setVisible(checked)
            self.areaMiddle.setVisible(checked)
            self.curveLBP.setVisible(checked)
            self.curveLRP.setVisible(checked)
            self.curveRBP.setVisible(checked)

    def onButtonLeftPowerStateChanged(self, checked):
        self._serialSend.ctrlWord.lPowerSw = checked
        self._serialSend.sum = SerialPortProxy.serialPortSendSum(self._serialSend)
        self._serialProxy.writeData(self._serialSend)

    def onButtonRightPowerStateChanged(self, checked):
        self._serialSend.ctrlWord.rPowerSw = checked
        self._serialSend.sum = SerialPortProxy.serialPortSendSum(self._serialSend)
        self._serialProxy.writeData(self._serialSend)

    def onButtonLeftTracksipStateChanged(self, checked):
        self._serialSend.ctrlWord.lTracksip = checked
        self._serialSend.sum = SerialPortProxy.serialPortSendSum(self._serialSend)
        self._serialProxy.writeData(self._serialSend)

    def onButtonRightTracksipStateChanged(self, checked):
        self._serialSend.ctrlWord.rTracksip = checked
        self._serialSend.sum = SerialPortProxy.serialPortSendSum(self._serialSend)
        self._serialProxy.writeData(self._serialSend)

    def onSerialStateChanged(self, info):
        text = '串口: [%s] %s' % (self._serialProxy.config().__str__(), info)
        print(text)

    def onSerialDisplayRespond(self, data, dateTime):
        # Major Brake Pressure
        suffix = self.editMLeftBrakeP.text().split(' ')[1]
        self.editMLeftBrakeP.setText('%.2f %s' % (data.lMBrakeP * 1.0, suffix))
        suffix = self.editMRightBrakeP.text().split(' ')[1]
        self.editMRightBrakeP.setText('%.2f %s' % (data.rMBrakeP * 1.0, suffix))
        # Minor Brake Pressure
        suffix = self.editALeftBrakeP.text().split(' ')[1]
        self.editALeftBrakeP.setText('%.2f %s' % (data.lABrakeP * 1.0, suffix))
        suffix = self.editARightBrakeP.text().split(' ')[1]
        self.editARightBrakeP.setText('%.2f %s' % (data.rABrakeP * 1.0, suffix))
        # Rotation Rate
        suffix = self.editLeftRotateRate.text().split(' ')[1]
        self.editLeftRotateRate.setText('%d %s' % (data.lWheelSpd * 1.0, suffix))
        suffix = self.editRightRotateRate.text().split(' ')[1]
        self.editRightRotateRate.setText('%d %s' % (data.rWheelSpd * 1.0, suffix))

        # curves
        timeT = dateTime.toMSecsSinceEpoch()

        # curve - LBP
        self.curveLBP.curve(0).sheft(QPoint(timeT, data.lMBrakeP))
        self.curveLBP.curve(1).sheft(QPoint(timeT, data.lABrakeP))
        # curve - LRP
        self.curveLRP.curve(0).sheft(QPoint(timeT, data.lWheelSpd))
        self.curveLRP.curve(1).sheft(QPoint(timeT, self._lTheorySpd))
        # curve - RBP
        self.curveRBP.curve(0).sheft(QPoint(timeT, data.rMBrakeP))
        self.curveRBP.curve(1).sheft(QPoint(timeT, data.rABrakeP))
        # curve - RRP
        self.curveRRP.curve(0).sheft(QPoint(timeT, data.rWheelSpd))
        self.curveRRP.curve(1).sheft(QPoint(timeT, self._rTheorySpd))

        if not DatabaseMgr().write(data, self._lTheorySpd, self._rTheorySpd, timeT):
            assert(False)

    def onSerialPortError(self, error, info):
        buttonPortState = self.findChild(JSwitchButton, 'buttonPortState')
        if not buttonPortState:
            return
        if error == QSerialPort.NoError:
            buttonPortState.setState(True)
        else:
            buttonPortState.setState(False)
        text = '串口: [%s] %s' % (self._serialProxy.config().__str__(), info)
        print(text)

    def execSliderWidget(self):
        sliderWidget = SliderWidget(self.sender().text(), self)
        objName = self.sender().objectName()
        if objName == 'buttonLeftSpeedGain':
            lineEdit = self.findChild(QLineEdit, 'editTheoryLeftRotateRate')
            text = lineEdit.text().split(' ')
            suffix = ' ' + text[1]
            curValue = float(text[0])
            sliderWidget.setRange(0, 3000)
            # sliderWidget.setDecimals(2)
            # sliderWidget.setSingleStep(0.01)
            sliderWidget.setSuffix(suffix)
            sliderWidget.setValue(curValue)

            def valueChanged(value):
                self._lTheorySpd = value
                buttonLeftSpeedSwitch = self.findChild(QPushButton, 'buttonLeftSpeedSwitch')
                if buttonLeftSpeedSwitch:
                    buttonLeftSpeedSwitch.setText('左转速关' if value == 0.0 else '左转速开');
                lineEdit.setText(('%.2f' % value) + suffix)

                # send
                self._serialSend.index += 1
                self._serialSend.lWheelSpd = int(value * 42.94967296)
                self._serialSend.sum = SerialPortProxy.serialPortSendSum(self._serialSend)
                self._serialProxy.writeData(self._serialSend)

            sliderWidget.valueChanged.connect(valueChanged)

        elif objName == 'buttonRightSpeedGain':
            lineEdit = self.findChild(QLineEdit, 'editTheoryRightRotateRate')
            text = lineEdit.text().split(' ')
            suffix = ' ' + text[1]
            curValue = float(text[0])
            sliderWidget.setRange(0, 3000)
            # sliderWidget.setDecimals(2)
            # sliderWidget.setSingleStep(0.01)
            sliderWidget.setSuffix(suffix)
            sliderWidget.setValue(curValue)

            def valueChanged(value):
                self._rTheorySpd = value
                buttonRightSpeedSwitch = self.findChild(QPushButton, 'buttonRightSpeedSwitch')
                if buttonRightSpeedSwitch:
                    buttonRightSpeedSwitch.setText('右转速关' if value == 0.0 else '右转速开')
                lineEdit.setText(('%.2f' % value) + suffix)

                # send
                self._serialSend.index += 1
                self._serialSend.rWheelSpd = int(value * 42.94967296)
                self._serialSend.sum = SerialPortProxy.serialPortSendSum(self._serialSend)
                self._serialProxy.writeData(self._serialSend)

            sliderWidget.valueChanged.connect(valueChanged)

        elif objName == 'buttonLeftSpeedKnob':
            lineEdit = self.findChild(QLineEdit, 'editTheoryLeftRotateRate')
            text = lineEdit.text().split(' ')
            suffix = ' ' + text[1]
            curValue = float(text[0])
            minValue = max(0, curValue - 50)
            maxValue = min(3000, curValue + 50)
            if maxValue < 100:
                maxValue = minValue + 100
            if minValue > 3000 - 100:
                minValue = maxValue - 100
            sliderWidget.setRange(minValue, maxValue)
            # sliderWidget.setDecimals(2)
            # sliderWidget.setSingleStep(0.01)
            sliderWidget.setSuffix(suffix)
            sliderWidget.setValue(curValue)

            def valueChanged(value):
                self._lTheorySpd = value
                buttonLeftSpeedSwitch = self.findChild(QPushButton, 'buttonLeftSpeedSwitch')
                if buttonLeftSpeedSwitch:
                    buttonLeftSpeedSwitch.setText('左转速关' if value == 0.0 else '左转速开')
                lineEdit.setText(('%.2f' % value) + suffix)

                # send
                self._serialSend.index += 1
                self._serialSend.lWheelSpd = int(value * 42.94967296)
                self._serialSend.sum = SerialPortProxy.serialPortSendSum(self._serialSend)
                self._serialProxy.writeData(self._serialSend)

            sliderWidget.valueChanged.connect(valueChanged)

        elif objName == 'buttonRightSpeedKnob':
            lineEdit = self.findChild(QLineEdit, 'editTheoryRightRotateRate')
            text = lineEdit.text().split(' ')
            suffix = ' ' + text[1]
            curValue = float(text[0])
            minValue = max(0, curValue - 50)
            maxValue = min(3000, curValue + 50)
            if maxValue < 100:
                maxValue = minValue + 100
            if minValue > 3000 - 100:
                minValue = maxValue - 100
            sliderWidget.setRange(minValue, maxValue)
            # sliderWidget.setDecimals(2)
            # sliderWidget.setSingleStep(0.01)
            sliderWidget.setSuffix(suffix)
            sliderWidget.setValue(curValue)

            def valueChanged(value):
                self._rTheorySpd = value
                buttonRightSpeedSwitch = self.findChild(QPushButton, 'buttonRightSpeedSwitch')
                if buttonRightSpeedSwitch:
                    buttonRightSpeedSwitch.setText('右转速关' if value == 0.0 else '右转速开');
                lineEdit.setText(('%.2f' % value) + suffix)

                # send
                self._serialSend.index += 1
                self._serialSend.rWheelSpd = int(value * 42.94967296)
                self._serialSend.sum = SerialPortProxy.serialPortSendSum(self._serialSend)
                self._serialProxy.writeData(self._serialSend)

            sliderWidget.valueChanged.connect(valueChanged)

        else:
            pass

        sliderWidget.exec_()