def __init__(self, metadata, parent=None): QDialog.__init__(self, parent=parent) self.setWindowFlags(Qt.Window) buttonBox = QDialogButtonBox(QDialogButtonBox.Close) origbrowser = QTextBrowser() origbrowser.setText('') origbrowser.setReadOnly(True) browser = QTextBrowser() browser.setText('') browser.setReadOnly(True) gpbox2 = QGroupBox('Metadata: Original') lay2 = QHBoxLayout() gpbox2.setLayout(lay2) lay2.addWidget(origbrowser) gpbox4 = QGroupBox('Metadata: After scrambling') lay4 = QHBoxLayout() gpbox4.setLayout(lay4) lay4.addWidget(browser) splitter = QSplitter(Qt.Horizontal) splitter.addWidget(gpbox2) splitter.addWidget(gpbox4) splitter.setMinimumHeight(500) splitter.setMinimumWidth(1000) lay = QVBoxLayout() self.setLayout(lay) lay.addWidget(splitter) lay.addWidget(buttonBox) # create connect signals/slots buttonBox.rejected.connect(self.reject) metaorig = metadata.get('orig', '') metaorig = re.sub(r'\n\s*', r'\n ', metaorig) origbrowser.setText(metaorig) browser.setText(metadata.get('scramb', '')) self.setWindowTitle('%s: Metadata' % CAPTION) if not 'scramb' in metadata: gpbox4.setVisible(False)
class UnpackBook(QDialog): def __init__(self, parent, book_id, fmts, db): QDialog.__init__(self, parent) self.setWindowIcon(QIcon(I('unpack-book.png'))) self.book_id, self.fmts, self.db_ref = book_id, fmts, weakref.ref(db) self._exploded = None self._cleanup_dirs = [] self._cleanup_files = [] self.setup_ui() self.setWindowTitle(_('Unpack Book') + ' - ' + db.title(book_id, index_is_id=True)) button = self.fmt_choice_buttons[0] button_map = {unicode(x.text()):x for x in self.fmt_choice_buttons} of = prefs['output_format'].upper() df = tweaks.get('default_tweak_format', None) lf = gprefs.get('last_tweak_format', None) if df and df.lower() == 'remember' and lf in button_map: button = button_map[lf] elif df and df.upper() in button_map: button = button_map[df.upper()] elif of in button_map: button = button_map[of] button.setChecked(True) self.init_state() for button in self.fmt_choice_buttons: button.toggled.connect(self.init_state) def init_state(self, *args): self._exploded = None self.preview_button.setEnabled(False) self.rebuild_button.setEnabled(False) self.explode_button.setEnabled(True) def setup_ui(self): # {{{ self._g = g = QHBoxLayout(self) self.setLayout(g) self._l = l = QVBoxLayout() g.addLayout(l) fmts = sorted(x.upper() for x in self.fmts) self.fmt_choice_box = QGroupBox(_('Choose the format to unpack:'), self) self._fl = fl = QHBoxLayout() self.fmt_choice_box.setLayout(self._fl) self.fmt_choice_buttons = [QRadioButton(y, self) for y in fmts] for x in self.fmt_choice_buttons: fl.addWidget(x, stretch=10 if x is self.fmt_choice_buttons[-1] else 0) l.addWidget(self.fmt_choice_box) self.fmt_choice_box.setVisible(len(fmts) > 1) self.help_label = QLabel(_('''\ <h2>About Unpack Book</h2> <p>Unpack Book allows you to fine tune the appearance of an ebook by making small changes to its internals. In order to use Unpack Book, you need to know a little bit about HTML and CSS, technologies that are used in ebooks. Follow the steps:</p> <br> <ol> <li>Click "Explode Book": This will "explode" the book into its individual internal components.<br></li> <li>Right click on any individual file and select "Open with..." to edit it in your favorite text editor.<br></li> <li>When you are done: <b>close the file browser window and the editor windows you used to make your tweaks</b>. Then click the "Rebuild Book" button, to update the book in your calibre library.</li> </ol>''')) self.help_label.setWordWrap(True) self._fr = QFrame() self._fr.setFrameShape(QFrame.VLine) g.addWidget(self._fr) g.addWidget(self.help_label) self._b = b = QGridLayout() left, top, right, bottom = b.getContentsMargins() top += top b.setContentsMargins(left, top, right, bottom) l.addLayout(b, stretch=10) self.explode_button = QPushButton(QIcon(I('wizard.png')), _('&Explode Book')) self.preview_button = QPushButton(QIcon(I('view.png')), _('&Preview Book')) self.cancel_button = QPushButton(QIcon(I('window-close.png')), _('&Cancel')) self.rebuild_button = QPushButton(QIcon(I('exec.png')), _('&Rebuild Book')) self.explode_button.setToolTip( _('Explode the book to edit its components')) self.preview_button.setToolTip( _('Preview the result of your changes')) self.cancel_button.setToolTip( _('Abort without saving any changes')) self.rebuild_button.setToolTip( _('Save your changes and update the book in the calibre library')) a = b.addWidget a(self.explode_button, 0, 0, 1, 1) a(self.preview_button, 0, 1, 1, 1) a(self.cancel_button, 1, 0, 1, 1) a(self.rebuild_button, 1, 1, 1, 1) for x in ('explode', 'preview', 'cancel', 'rebuild'): getattr(self, x+'_button').clicked.connect(getattr(self, x)) self.msg = QLabel('dummy', self) self.msg.setVisible(False) self.msg.setStyleSheet(''' QLabel { text-align: center; background-color: white; color: black; border-width: 1px; border-style: solid; border-radius: 20px; font-size: x-large; font-weight: bold; } ''') self.resize(self.sizeHint() + QSize(40, 10)) # }}} def show_msg(self, msg): self.msg.setText(msg) self.msg.resize(self.size() - QSize(50, 25)) self.msg.move((self.width() - self.msg.width())//2, (self.height() - self.msg.height())//2) self.msg.setVisible(True) def hide_msg(self): self.msg.setVisible(False) def explode(self): self.show_msg(_('Exploding, please wait...')) if len(self.fmt_choice_buttons) > 1: gprefs.set('last_tweak_format', self.current_format.upper()) QTimer.singleShot(5, self.do_explode) def ask_question(self, msg): return question_dialog(self, _('Are you sure?'), msg) def do_explode(self): from calibre.ebooks.tweak import get_tools, Error, WorkerError tdir = PersistentTemporaryDirectory('_tweak_explode') self._cleanup_dirs.append(tdir) det_msg = None try: src = self.db.format(self.book_id, self.current_format, index_is_id=True, as_path=True) self._cleanup_files.append(src) exploder = get_tools(self.current_format)[0] opf = exploder(src, tdir, question=self.ask_question) except WorkerError as e: det_msg = e.orig_tb except Error as e: return error_dialog(self, _('Failed to unpack'), (_('Could not explode the %s file.')%self.current_format) + ' ' + as_unicode(e), show=True) except: import traceback det_msg = traceback.format_exc() finally: self.hide_msg() if det_msg is not None: return error_dialog(self, _('Failed to unpack'), _('Could not explode the %s file. Click "Show Details" for ' 'more information.')%self.current_format, det_msg=det_msg, show=True) if opf is None: # The question was answered with No return self._exploded = tdir self.explode_button.setEnabled(False) self.preview_button.setEnabled(True) self.rebuild_button.setEnabled(True) open_local_file(tdir) def rebuild_it(self): from calibre.ebooks.tweak import get_tools, WorkerError src_dir = self._exploded det_msg = None of = PersistentTemporaryFile('_tweak_rebuild.'+self.current_format.lower()) of.close() of = of.name self._cleanup_files.append(of) try: rebuilder = get_tools(self.current_format)[1] rebuilder(src_dir, of) except WorkerError as e: det_msg = e.orig_tb except: import traceback det_msg = traceback.format_exc() finally: self.hide_msg() if det_msg is not None: error_dialog(self, _('Failed to rebuild file'), _('Failed to rebuild %s. For more information, click ' '"Show details".')%self.current_format, det_msg=det_msg, show=True) return None return of def preview(self): self.show_msg(_('Rebuilding, please wait...')) QTimer.singleShot(5, self.do_preview) def do_preview(self): rebuilt = self.rebuild_it() if rebuilt is not None: self.parent().iactions['View']._view_file(rebuilt) def rebuild(self): self.show_msg(_('Rebuilding, please wait...')) QTimer.singleShot(5, self.do_rebuild) def do_rebuild(self): rebuilt = self.rebuild_it() if rebuilt is not None: fmt = os.path.splitext(rebuilt)[1][1:].upper() with open(rebuilt, 'rb') as f: self.db.add_format(self.book_id, fmt, f, index_is_id=True) self.accept() def cancel(self): self.reject() def cleanup(self): if isosx and self._exploded: try: import appscript self.finder = appscript.app('Finder') self.finder.Finder_windows[os.path.basename(self._exploded)].close() except: pass for f in self._cleanup_files: try: os.remove(f) except: pass for d in self._cleanup_dirs: try: shutil.rmtree(d) except: pass @property def db(self): return self.db_ref() @property def current_format(self): for b in self.fmt_choice_buttons: if b.isChecked(): return unicode(b.text())
class UnpackBook(QDialog): def __init__(self, parent, book_id, fmts, db): QDialog.__init__(self, parent) self.setWindowIcon(QIcon(I('unpack-book.png'))) self.book_id, self.fmts, self.db_ref = book_id, fmts, weakref.ref(db) self._exploded = None self._cleanup_dirs = [] self._cleanup_files = [] self.setup_ui() self.setWindowTitle( _('Unpack book') + ' - ' + db.title(book_id, index_is_id=True)) button = self.fmt_choice_buttons[0] button_map = { unicode_type(x.text()): x for x in self.fmt_choice_buttons } of = prefs['output_format'].upper() df = tweaks.get('default_tweak_format', None) lf = gprefs.get('last_tweak_format', None) if df and df.lower() == 'remember' and lf in button_map: button = button_map[lf] elif df and df.upper() in button_map: button = button_map[df.upper()] elif of in button_map: button = button_map[of] button.setChecked(True) self.init_state() for button in self.fmt_choice_buttons: button.toggled.connect(self.init_state) def init_state(self, *args): self._exploded = None self.preview_button.setEnabled(False) self.rebuild_button.setEnabled(False) self.explode_button.setEnabled(True) def setup_ui(self): # {{{ self._g = g = QHBoxLayout(self) self.setLayout(g) self._l = l = QVBoxLayout() g.addLayout(l) fmts = sorted(x.upper() for x in self.fmts) self.fmt_choice_box = QGroupBox(_('Choose the format to unpack:'), self) self._fl = fl = QHBoxLayout() self.fmt_choice_box.setLayout(self._fl) self.fmt_choice_buttons = [QRadioButton(y, self) for y in fmts] for x in self.fmt_choice_buttons: fl.addWidget(x, stretch=10 if x is self.fmt_choice_buttons[-1] else 0) l.addWidget(self.fmt_choice_box) self.fmt_choice_box.setVisible(len(fmts) > 1) self.help_label = QLabel( _('''\ <h2>About Unpack book</h2> <p>Unpack book allows you to fine tune the appearance of an e-book by making small changes to its internals. In order to use Unpack book, you need to know a little bit about HTML and CSS, technologies that are used in e-books. Follow the steps:</p> <br> <ol> <li>Click "Explode book": This will "explode" the book into its individual internal components.<br></li> <li>Right click on any individual file and select "Open with..." to edit it in your favorite text editor.<br></li> <li>When you are done: <b>close the file browser window and the editor windows you used to make your tweaks</b>. Then click the "Rebuild book" button, to update the book in your calibre library.</li> </ol>''')) self.help_label.setWordWrap(True) self._fr = QFrame() self._fr.setFrameShape(QFrame.VLine) g.addWidget(self._fr) g.addWidget(self.help_label) self._b = b = QGridLayout() left, top, right, bottom = b.getContentsMargins() top += top b.setContentsMargins(left, top, right, bottom) l.addLayout(b, stretch=10) self.explode_button = QPushButton(QIcon(I('wizard.png')), _('&Explode book')) self.preview_button = QPushButton(QIcon(I('view.png')), _('&Preview book')) self.cancel_button = QPushButton(QIcon(I('window-close.png')), _('&Cancel')) self.rebuild_button = QPushButton(QIcon(I('exec.png')), _('&Rebuild book')) self.explode_button.setToolTip( _('Explode the book to edit its components')) self.preview_button.setToolTip(_('Preview the result of your changes')) self.cancel_button.setToolTip(_('Abort without saving any changes')) self.rebuild_button.setToolTip( _('Save your changes and update the book in the calibre library')) a = b.addWidget a(self.explode_button, 0, 0, 1, 1) a(self.preview_button, 0, 1, 1, 1) a(self.cancel_button, 1, 0, 1, 1) a(self.rebuild_button, 1, 1, 1, 1) for x in ('explode', 'preview', 'cancel', 'rebuild'): getattr(self, x + '_button').clicked.connect(getattr(self, x)) self.msg = QLabel('dummy', self) self.msg.setVisible(False) self.msg.setStyleSheet(''' QLabel { text-align: center; background-color: white; color: black; border-width: 1px; border-style: solid; border-radius: 20px; font-size: x-large; font-weight: bold; } ''') self.resize(self.sizeHint() + QSize(40, 10)) # }}} def show_msg(self, msg): self.msg.setText(msg) self.msg.resize(self.size() - QSize(50, 25)) self.msg.move((self.width() - self.msg.width()) // 2, (self.height() - self.msg.height()) // 2) self.msg.setVisible(True) def hide_msg(self): self.msg.setVisible(False) def explode(self): self.show_msg(_('Exploding, please wait...')) if len(self.fmt_choice_buttons) > 1: gprefs.set('last_tweak_format', self.current_format.upper()) QTimer.singleShot(5, self.do_explode) def ask_question(self, msg): return question_dialog(self, _('Are you sure?'), msg) def do_explode(self): from calibre.ebooks.tweak import get_tools, Error, WorkerError tdir = PersistentTemporaryDirectory('_tweak_explode') self._cleanup_dirs.append(tdir) det_msg = None try: src = self.db.format(self.book_id, self.current_format, index_is_id=True, as_path=True) self._cleanup_files.append(src) exploder = get_tools(self.current_format)[0] opf = exploder(src, tdir, question=self.ask_question) except WorkerError as e: det_msg = e.orig_tb except Error as e: return error_dialog( self, _('Failed to unpack'), (_('Could not explode the %s file.') % self.current_format) + ' ' + as_unicode(e), show=True) except: import traceback det_msg = traceback.format_exc() finally: self.hide_msg() if det_msg is not None: return error_dialog( self, _('Failed to unpack'), _('Could not explode the %s file. Click "Show Details" for ' 'more information.') % self.current_format, det_msg=det_msg, show=True) if opf is None: # The question was answered with No return self._exploded = tdir self.explode_button.setEnabled(False) self.preview_button.setEnabled(True) self.rebuild_button.setEnabled(True) open_local_file(tdir) def rebuild_it(self): from calibre.ebooks.tweak import get_tools, WorkerError src_dir = self._exploded det_msg = None of = PersistentTemporaryFile('_tweak_rebuild.' + self.current_format.lower()) of.close() of = of.name self._cleanup_files.append(of) try: rebuilder = get_tools(self.current_format)[1] rebuilder(src_dir, of) except WorkerError as e: det_msg = e.orig_tb except: import traceback det_msg = traceback.format_exc() finally: self.hide_msg() if det_msg is not None: error_dialog(self, _('Failed to rebuild file'), _('Failed to rebuild %s. For more information, click ' '"Show details".') % self.current_format, det_msg=det_msg, show=True) return None return of def preview(self): self.show_msg(_('Rebuilding, please wait...')) QTimer.singleShot(5, self.do_preview) def do_preview(self): rebuilt = self.rebuild_it() if rebuilt is not None: self.parent().iactions['View']._view_file(rebuilt) def rebuild(self): self.show_msg(_('Rebuilding, please wait...')) QTimer.singleShot(5, self.do_rebuild) def do_rebuild(self): rebuilt = self.rebuild_it() if rebuilt is not None: fmt = os.path.splitext(rebuilt)[1][1:].upper() with open(rebuilt, 'rb') as f: self.db.add_format(self.book_id, fmt, f, index_is_id=True) self.accept() def cancel(self): self.reject() def cleanup(self): if isosx and self._exploded: try: import appscript self.finder = appscript.app('Finder') self.finder.Finder_windows[os.path.basename( self._exploded)].close() except: pass for f in self._cleanup_files: try: os.remove(f) except: pass for d in self._cleanup_dirs: try: shutil.rmtree(d) except: pass @property def db(self): return self.db_ref() @property def current_format(self): for b in self.fmt_choice_buttons: if b.isChecked(): return unicode_type(b.text())
def __init__(self, ebook, orig, is_scrambled, fmap, parent=None): QDialog.__init__(self, parent=parent) self.setWindowFlags(Qt.Window) self.orig = orig self.ebook = ebook self.revfmap = {v: k for (k, v) in iteritems(fmap)} # create widgets lay = QVBoxLayout() self.setLayout(lay) buttonBox = QDialogButtonBox(QDialogButtonBox.Close) self.webview_orig = Webview() self.webview_scram = Webview() settings = self.webview_orig.settings() if hasattr(settings, 'setUserStyleSheetUrl'): # QWebView from QtWebKit style = 'body {%s}' % CSSBG cssurl = 'data:text/css;charset=utf-8;base64,' cssurl += as_base64_unicode(style) self.webview_orig.settings().setUserStyleSheetUrl(QUrl(cssurl)) self.webview_scram.settings().setUserStyleSheetUrl(QUrl(cssurl)) elif hasattr(self.webview_orig, 'setStyleSheet'): # QWebEngineView from QtWebEngine # setStyleSheet doesn't seem to work at the moment self.webview_orig.setStyleSheet('Webview {%s}' % CSSBG) self.webview_scram.setStyleSheet('Webview {%s}' % CSSBG) dummytext = '<body><p>*** Text content could not be displayed ...</p></body>' self.webview_orig.setHtml(dummytext) self.webview_scram.setHtml(dummytext) self.htmlList_orig = QListWidget() self.htmlList_scram = QListWidget() self.htmlList_orig.setMinimumWidth(300) self.htmlList_scram.setMinimumWidth(300) gpbox1 = QGroupBox() lay1 = QHBoxLayout() gpbox1.setLayout(lay1) lay1.addWidget(self.htmlList_orig) gpbox3 = QGroupBox() lay3 = QHBoxLayout() gpbox3.setLayout(lay3) lay3.addWidget(self.htmlList_scram) gpbox2 = QGroupBox('Original text content:') lay2 = QHBoxLayout() gpbox2.setLayout(lay2) lay2.addWidget(self.webview_orig) gpbox4 = QGroupBox('Original text content:') lay4 = QHBoxLayout() gpbox4.setLayout(lay4) lay4.addWidget(self.webview_scram) splitter = QSplitter(Qt.Horizontal) splitter.addWidget(gpbox1) splitter.addWidget(gpbox2) splitter.addWidget(gpbox3) splitter.addWidget(gpbox4) lay.addWidget(splitter) lay.addWidget(buttonBox) # create connect signals/slots buttonBox.rejected.connect(self.reject) self.htmlList_scram.currentRowChanged.connect( self.htmlList_currentRowChanged) self.htmlList_scram.itemDoubleClicked.connect( self.htmlList_itemDoubleClicked) self.htmlList_orig.setEnabled(False) self.htmlnames_scram = get_textnames(self.ebook) self.htmlnames_orig = tuple( [self.revfmap.get(an, an) for an in self.htmlnames_scram]) gpbox1.setTitle('Original HTML files: %s' % len(self.htmlnames_orig)) gpbox3.setTitle('Original HTML files: %s' % len(self.htmlnames_scram)) self.htmlList_orig.clear() self.htmlList_orig.addItems(self.htmlnames_orig) self.htmlList_scram.clear() self.htmlList_scram.addItems(self.htmlnames_scram) if not self.revfmap: gpbox1.setVisible(False) msg = '%s Preview: Original' % CAPTION if not is_scrambled: self.setWindowTitle(msg) gpbox1.setVisible(False) gpbox2.setVisible(False) else: self.setWindowTitle(msg + ' vs. Scrambled') gpbox3.setTitle('Scrambled HTML files: %s' % len(self.htmlnames_scram)) gpbox4.setTitle('Scrambled text content:') self.htmlList_scram.setCurrentRow(0)
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)
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_()