class BlockingBusy(QDialog): def __init__(self, msg, parent=None, window_title=_('Working')): QDialog.__init__(self, parent) self._layout = QVBoxLayout() self.setLayout(self._layout) self.msg = QLabel(msg) #self.msg.setWordWrap(True) self.font = QFont() self.font.setPointSize(self.font.pointSize() + 8) self.msg.setFont(self.font) self.pi = ProgressIndicator(self) self.pi.setDisplaySize(100) self._layout.addWidget(self.pi, 0, Qt.AlignHCenter) self._layout.addSpacing(15) self._layout.addWidget(self.msg, 0, Qt.AlignHCenter) self.start() self.setWindowTitle(window_title) self.resize(self.sizeHint()) def start(self): self.pi.startAnimation() def stop(self): self.pi.stopAnimation() def accept(self): self.stop() return QDialog.accept(self) def reject(self): pass # Cannot cancel this dialog
class CursorPositionWidget(QWidget): # {{{ def __init__(self, parent): QWidget.__init__(self, parent) self.l = QHBoxLayout(self) self.setLayout(self.l) self.la = QLabel('') self.l.addWidget(self.la) self.l.setContentsMargins(0, 0, 0, 0) f = self.la.font() f.setBold(False) self.la.setFont(f) def update_position(self, line=None, col=None, character=None): if line is None: self.la.setText('') else: try: name = character_name(character) if character and tprefs['editor_show_char_under_cursor'] else None except Exception: name = None text = _('Line: {0} : {1}').format(line, col) if not name: name = {'\t':'TAB'}.get(character, None) if name and tprefs['editor_show_char_under_cursor']: text = name + ' : ' + text self.la.setText(text)
class CursorPositionWidget(QWidget): # {{{ def __init__(self, parent): QWidget.__init__(self, parent) self.l = QHBoxLayout(self) self.setLayout(self.l) self.la = QLabel('') self.l.addWidget(self.la) self.l.setContentsMargins(0, 0, 0, 0) f = self.la.font() f.setBold(False) self.la.setFont(f) def update_position(self, line=None, col=None, character=None): if line is None: self.la.setText('') else: try: name = unicodedata.name(character, None) if character else None except Exception: name = None text = _('Line: {0} : {1}').format(line, col) if name: text = name + ' : ' + text self.la.setText(text)
def __init__(self, parent, icon_name, title): QHBoxLayout.__init__(self) self.title_image_label = QLabel(parent) self.update_title_icon(icon_name) self.addWidget(self.title_image_label) title_font = QFont() title_font.setPointSize(16) shelf_label = QLabel(title, parent) shelf_label.setFont(title_font) self.addWidget(shelf_label) self.insertStretch(-1)
class StatusBar(QStatusBar): # {{{ def __init__(self, parent=None): QStatusBar.__init__(self, parent) self.default_message = __appname__ + ' ' + _('version') + ' ' + \ __version__ + ' ' + _('created by Kovid Goyal') self.device_string = '' self._font = QFont() self._font.setBold(True) self.setFont(self._font) self.w = QLabel(self.default_message) self.w.setFont(self._font) self.addWidget(self.w)
class StatusBar(QStatusBar): # {{{ def __init__(self, parent=None): QStatusBar.__init__(self, parent) self.default_message = __appname__ + ' ' + _('version') + ' ' + \ self.get_version() + ' ' + _('created by Kovid Goyal') self.device_string = '' self.update_label = UpdateLabel('') self.addPermanentWidget(self.update_label) self.update_label.setVisible(False) self._font = QFont() self._font.setBold(True) self.setFont(self._font) self.defmsg = QLabel(self.default_message) self.defmsg.setFont(self._font) self.addWidget(self.defmsg) def initialize(self, systray=None): self.systray = systray self.notifier = get_notifier(systray) def device_connected(self, devname): self.device_string = _('Connected ') + devname self.defmsg.setText(self.default_message + ' ..::.. ' + self.device_string) self.clearMessage() def device_disconnected(self): self.device_string = '' self.defmsg.setText(self.default_message) self.clearMessage() def get_version(self): return get_version() def show_message(self, msg, timeout=0): self.showMessage(msg, timeout) if self.notifier is not None and not config[ 'disable_tray_notification']: if isosx and isinstance(msg, unicode): try: msg = msg.encode(preferred_encoding) except UnicodeEncodeError: msg = msg.encode('utf-8') self.notifier(msg) def clear_message(self): self.clearMessage()
class StatusBar(QStatusBar): # {{{ def __init__(self, parent=None): QStatusBar.__init__(self, parent) self.default_message = __appname__ + ' ' + _('version') + ' ' + \ self.get_version() + ' ' + _('created by Kovid Goyal') self.device_string = '' self.update_label = UpdateLabel('') self.addPermanentWidget(self.update_label) self.update_label.setVisible(False) self._font = QFont() self._font.setBold(True) self.setFont(self._font) self.defmsg = QLabel(self.default_message) self.defmsg.setFont(self._font) self.addWidget(self.defmsg) def initialize(self, systray=None): self.systray = systray self.notifier = get_notifier(systray) def device_connected(self, devname): self.device_string = _('Connected ') + devname self.defmsg.setText(self.default_message + ' ..::.. ' + self.device_string) self.clearMessage() def device_disconnected(self): self.device_string = '' self.defmsg.setText(self.default_message) self.clearMessage() def get_version(self): return get_version() def show_message(self, msg, timeout=0): self.showMessage(msg, timeout) if self.notifier is not None and not config['disable_tray_notification']: if isosx and isinstance(msg, unicode): try: msg = msg.encode(preferred_encoding) except UnicodeEncodeError: msg = msg.encode('utf-8') self.notifier(msg) def clear_message(self): self.clearMessage()
class CursorPositionWidget(QWidget): def __init__(self, parent): QWidget.__init__(self, parent) self.l = QHBoxLayout(self) self.setLayout(self.l) self.la = QLabel('') self.l.addWidget(self.la) self.l.setContentsMargins(0, 0, 0, 0) f = self.la.font() f.setBold(False) self.la.setFont(f) def update_position(self, line=None, col=None): if line is None: self.la.setText('') else: self.la.setText(_('Line: {0} : {1}').format(line, col))
def __init__(self, parent, icon_name, title): QHBoxLayout.__init__(self) title_font = QFont() title_font.setPointSize(16) title_image_label = QLabel(parent) pixmap = get_pixmap(icon_name) if pixmap is None: error_dialog(parent, _('Restart required'), _('You must restart Calibre before using this plugin!'), show=True) else: title_image_label.setPixmap(pixmap) title_image_label.setMaximumSize(32, 32) title_image_label.setScaledContents(True) self.addWidget(title_image_label) shelf_label = QLabel(title, parent) shelf_label.setFont(title_font) self.addWidget(shelf_label) self.insertStretch(-1)
def __init__(self, parent, icon_name, title): QHBoxLayout.__init__(self) title_font = QFont() title_font.setPointSize(16) title_image_label = QLabel(parent) pixmap = QPixmap() pixmap.load(I(icon_name)) if pixmap is None: error_dialog(parent, _('Restart required'), _('You must restart Calibre before using this plugin!'), show=True) else: title_image_label.setPixmap(pixmap) title_image_label.setMaximumSize(32, 32) title_image_label.setScaledContents(True) self.addWidget(title_image_label) shelf_label = QLabel(title, parent) shelf_label.setFont(title_font) self.addWidget(shelf_label) self.insertStretch(-1)
class Category(QWidget): # {{{ plugin_activated = pyqtSignal(object) def __init__(self, name, plugins, gui_name, parent=None): QWidget.__init__(self, parent) self._layout = QVBoxLayout() self.setLayout(self._layout) self.label = QLabel(gui_name) self.sep = QFrame(self) self.bf = QFont() self.bf.setBold(True) self.label.setFont(self.bf) self.sep.setFrameShape(QFrame.HLine) self._layout.addWidget(self.label) self._layout.addWidget(self.sep) self.plugins = plugins self.bar = QToolBar(self) self.bar.setStyleSheet( 'QToolBar { border: none; background: none }') self.bar.setIconSize(QSize(32, 32)) self.bar.setMovable(False) self.bar.setFloatable(False) self.bar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) self._layout.addWidget(self.bar) self.actions = [] for p in plugins: target = partial(self.triggered, p) ac = self.bar.addAction(QIcon(p.icon), p.gui_name, target) ac.setToolTip(textwrap.fill(p.description)) ac.setWhatsThis(textwrap.fill(p.description)) ac.setStatusTip(p.description) self.actions.append(ac) w = self.bar.widgetForAction(ac) w.setCursor(Qt.PointingHandCursor) w.setAutoRaise(True) w.setMinimumWidth(100) def triggered(self, plugin, *args): self.plugin_activated.emit(plugin)
class parameter_dialog_or_frame: """ use as a pre-mixin before QDialog or QFrame """ ####@@@@ def __init__(self, parent = None, desc = None, name = None, modal = 0, fl = 0, env = None, type = "QDialog"): if env is None: import foundation.env as env # this is a little weird... probably it'll be ok, and logically it seems correct. self.desc = desc self.typ = type if type == "QDialog": QDialog.__init__(self,parent,name,modal,fl) elif type == "QTextEdit": QTextEdit.__init__(self, parent, name) elif type == "QFrame": QFrame.__init__(self,parent,name) else: print "don't know about type == %r" % (type,) self.image1 = QPixmap() self.image1.loadFromData(image1_data,"PNG") # should be: title_icon #### self.image3 = QPixmap() self.image3.loadFromData(image3_data,"PNG") self.image4 = QPixmap() self.image4.loadFromData(image4_data,"PNG") self.image5 = QPixmap() self.image5.loadFromData(image5_data,"PNG") self.image6 = QPixmap() self.image6.loadFromData(image6_data,"PNG") self.image7 = QPixmap() self.image7.loadFromData(image7_data,"PNG") self.image0 = QPixmap(image0_data) # should be: border_icon #### self.image2 = QPixmap(image2_data) # should be: sponsor_pixmap #### try: ####@@@@ title_icon_name = self.desc.options.get('title_icon') border_icon_name = self.desc.options.get('border_icon') if title_icon_name: self.image1 = imagename_to_pixmap(title_icon_name) ###@@@ pass icon_path ###@@@ import imagename_to_pixmap or use env function # or let that func itself be an arg, or have an env arg for it ###e rename it icon_name_to_pixmap, or find_icon? (the latter only if it's ok if it returns an iconset) ###e use iconset instead? if border_icon_name: self.image0 = imagename_to_pixmap(border_icon_name) except: print_compact_traceback("bug in icon-setting code, using fallback icons: ") pass if not name: self.setName("parameter_dialog_or_frame") ### ###k guess this will need: if type == 'QDialog' self.setIcon(self.image0) # should be: border_icon #### nanotube_dialogLayout = QVBoxLayout(self,0,0,"nanotube_dialogLayout") self.heading_frame = QFrame(self,"heading_frame") self.heading_frame.setPaletteBackgroundColor(QColor(122,122,122)) self.heading_frame.setFrameShape(QFrame.NoFrame) self.heading_frame.setFrameShadow(QFrame.Plain) heading_frameLayout = QHBoxLayout(self.heading_frame,0,3,"heading_frameLayout") self.heading_pixmap = QLabel(self.heading_frame,"heading_pixmap") self.heading_pixmap.setSizePolicy(QSizePolicy(QSizePolicy.Fixed,QSizePolicy.Fixed,0,0,self.heading_pixmap.sizePolicy().hasHeightForWidth())) self.heading_pixmap.setPixmap(self.image1) # should be: title_icon #### self.heading_pixmap.setScaledContents(1) heading_frameLayout.addWidget(self.heading_pixmap) self.heading_label = QLabel(self.heading_frame,"heading_label") self.heading_label.setPaletteForegroundColor(QColor(255,255,255)) heading_label_font = QFont(self.heading_label.font()) heading_label_font.setPointSize(12) heading_label_font.setBold(1) self.heading_label.setFont(heading_label_font) heading_frameLayout.addWidget(self.heading_label) nanotube_dialogLayout.addWidget(self.heading_frame) self.body_frame = QFrame(self,"body_frame") self.body_frame.setFrameShape(QFrame.StyledPanel) self.body_frame.setFrameShadow(QFrame.Raised) body_frameLayout = QVBoxLayout(self.body_frame,3,3,"body_frameLayout") self.sponsor_frame = QFrame(self.body_frame,"sponsor_frame") self.sponsor_frame.setPaletteBackgroundColor(QColor(255,255,255)) self.sponsor_frame.setFrameShape(QFrame.StyledPanel) self.sponsor_frame.setFrameShadow(QFrame.Raised) sponsor_frameLayout = QHBoxLayout(self.sponsor_frame,0,0,"sponsor_frameLayout") self.sponsor_btn = QPushButton(self.sponsor_frame,"sponsor_btn") self.sponsor_btn.setAutoDefault(0) #bruce 060703 bugfix self.sponsor_btn.setSizePolicy(QSizePolicy(QSizePolicy.Preferred,QSizePolicy.Preferred,0,0,self.sponsor_btn.sizePolicy().hasHeightForWidth())) self.sponsor_btn.setPaletteBackgroundColor(QColor(255,255,255)) self.sponsor_btn.setPixmap(self.image2) # should be: sponsor_pixmap #### [also we'll need to support >1 sponsor] self.sponsor_btn.setFlat(1) sponsor_frameLayout.addWidget(self.sponsor_btn) body_frameLayout.addWidget(self.sponsor_frame) layout59 = QHBoxLayout(None,0,6,"layout59") left_spacer = QSpacerItem(20,20,QSizePolicy.Expanding,QSizePolicy.Minimum) layout59.addItem(left_spacer) self.done_btn = QToolButton(self.body_frame,"done_btn") self.done_btn.setIcon(QIcon(self.image3)) layout59.addWidget(self.done_btn) self.abort_btn = QToolButton(self.body_frame,"abort_btn") self.abort_btn.setIcon(QIcon(self.image4)) layout59.addWidget(self.abort_btn) self.preview_btn = QToolButton(self.body_frame,"preview_btn") self.preview_btn.setIcon(QIcon(self.image5)) layout59.addWidget(self.preview_btn) self.whatsthis_btn = QToolButton(self.body_frame,"whatsthis_btn") self.whatsthis_btn.setIcon(QIcon(self.image6)) layout59.addWidget(self.whatsthis_btn) right_spacer = QSpacerItem(20,20,QSizePolicy.Expanding,QSizePolicy.Minimum) layout59.addItem(right_spacer) body_frameLayout.addLayout(layout59) self.groups = [] self.param_getters = {} # map from param name to get-function (which gets current value out of its widget or controller) for group_desc in self.desc.kids('group'): # == start parameters_grpbox ### this will differ for Windows style header_refs = [] # keep python refcounted refs to all objects we make (at least the ones pyuic stored in self attrs) self.parameters_grpbox = QGroupBox(self.body_frame,"parameters_grpbox") self.parameters_grpbox.setFrameShape(QGroupBox.StyledPanel) self.parameters_grpbox.setFrameShadow(QGroupBox.Sunken) self.parameters_grpbox.setMargin(0) self.parameters_grpbox.setColumnLayout(0,Qt.Vertical) self.parameters_grpbox.layout().setSpacing(1) self.parameters_grpbox.layout().setMargin(4) parameters_grpboxLayout = QVBoxLayout(self.parameters_grpbox.layout()) parameters_grpboxLayout.setAlignment(Qt.AlignTop) layout20 = QHBoxLayout(None,0,6,"layout20") self.nt_parameters_grpbtn = QPushButton(self.parameters_grpbox,"nt_parameters_grpbtn") self.nt_parameters_grpbtn.setSizePolicy(QSizePolicy(QSizePolicy.Minimum,QSizePolicy.Fixed,0,0,self.nt_parameters_grpbtn.sizePolicy().hasHeightForWidth())) self.nt_parameters_grpbtn.setMaximumSize(QSize(16,16)) self.nt_parameters_grpbtn.setAutoDefault(0) self.nt_parameters_grpbtn.setIcon(QIcon(self.image7)) ### not always right, but doesn't matter self.nt_parameters_grpbtn.setFlat(1) layout20.addWidget(self.nt_parameters_grpbtn) self.parameters_grpbox_label = QLabel(self.parameters_grpbox,"parameters_grpbox_label") self.parameters_grpbox_label.setSizePolicy(QSizePolicy(QSizePolicy.Preferred,QSizePolicy.Minimum,0,0,self.parameters_grpbox_label.sizePolicy().hasHeightForWidth())) self.parameters_grpbox_label.setAlignment(QLabel.AlignVCenter) layout20.addWidget(self.parameters_grpbox_label) gbx_spacer1 = QSpacerItem(67,16,QSizePolicy.Expanding,QSizePolicy.Minimum) layout20.addItem(gbx_spacer1) parameters_grpboxLayout.addLayout(layout20) nt_parameters_body_layout = QGridLayout(None,1,1,0,6,"nt_parameters_body_layout") ### what is 6 -- is it related to number of items??? # is it 6 in all the ones we got, but that could be a designer error so i better look it up sometime. # == start its kids # will use from above: self.parameters_grpbox, nt_parameters_body_layout nextrow = 0 # which row of the QGridLayout to start filling next (loop variable) hidethese = [] # set of objects to hide or show, when this group is closed or opened for param in group_desc.kids('parameter'): # param (a group subobj desc) is always a parameter, but we already plan to extend this beyond that, # so we redundantly test for this here. getter = None paramname = None # set these for use by uniform code at the end (e.g. for tooltips) editfield = None label = None if param.isa('parameter'): label = QLabel(self.parameters_grpbox,"members_label") label.setAlignment(QLabel.AlignVCenter | QLabel.AlignRight) nt_parameters_body_layout.addWidget(label,nextrow,0) hidethese.append(label) thisrow = nextrow nextrow += 1 #e following should be known in a place that knows the input language, not here paramname = param.options.get('name') or (param.args and param.args[0]) or "?" paramlabel = param.options.get('label') or paramname ##e wrong, label "" or none ought to be possible # QtGui.QApplication.translate(self.__class__.__name__, "xyz") label.setText(QtGui.QApplication.translate(self.__class__.__name__, paramlabel)) if param.isa('parameter', widget = 'combobox', type = ('str',None)): self.members_combox = QComboBox(0,self.parameters_grpbox,"members_combox") ###k what's 0? editfield = self.members_combox #### it probably needs a handler class, and then that could do this setup self.members_combox.clear() default = param.options.get('default', None) # None is not equal to any string thewidgetkid = param.kids('widget')[-1] # kluge; need to think what the desc method for this should be for item in thewidgetkid.kids('item'): itemval = item.args[0] itemtext = itemval self.members_combox.insertItem(QtGui.QApplication.translate(self.__class__.__name__, itemtext)) #k __tr ok?? if itemval == default: #k or itemtext? pass ##k i find no setItem in our py code, so not sure yet what to do for this. nt_parameters_body_layout.addWidget(self.members_combox,thisrow,1) hidethese.append(self.members_combox) getter = (lambda combobox = self.members_combox: str(combobox.currentText())) ##e due to __tr or non-str values, it might be better to use currentIndex and look it up in a table # (though whether __tr is good here might depend on what it's used for) elif param.isa('parameter', widget = ('lineedit', None), type = ('str',None)): # this covers explicit str|lineedit, and 3 default cases str, lineedit, neither. # (i.e. if you say parameter and nothing else, it's str lineedit by default.) self.length_linedit = QLineEdit(self.parameters_grpbox,"length_linedit") editfield = self.length_linedit nt_parameters_body_layout.addWidget(self.length_linedit,thisrow,1) hidethese.append(self.length_linedit) default = str(param.options.get('default', "")) self.length_linedit.setText(QtGui.QApplication.translate(self.__class__.__name__, default)) # __tr ok? getter = (lambda lineedit = self.length_linedit: str(lineedit.text())) elif param.isa('parameter', widget = ('lineedit', None), type = 'float'): self.length_linedit = QLineEdit(self.parameters_grpbox,"length_linedit") editfield = self.length_linedit nt_parameters_body_layout.addWidget(self.length_linedit,thisrow,1) hidethese.append(self.length_linedit) controller = FloatLineeditController_Qt(self, param, self.length_linedit) header_refs.append(controller) getter = controller.get_value elif param.isa('parameter', widget = ('spinbox', None), type = 'int') or \ param.isa('parameter', widget = ('spinbox'), type = None): self.chirality_N_spinbox = QSpinBox(self.parameters_grpbox,"chirality_N_spinbox") # was chirality_m_spinbox, now chirality_N_spinbox editfield = self.chirality_N_spinbox ### seems like Qt defaults for min and max are 0,100 -- way too small a range! if param.options.has_key('min') or 1: self.chirality_N_spinbox.setMinimum(param.options.get('min', -999999999)) # was 0 if param.options.has_key('max') or 1: self.chirality_N_spinbox.setMaximum(param.options.get('max', +999999999)) # wasn't in egcode, but needed self.chirality_N_spinbox.setValue(param.options.get('default', 0)) # was 5 ##e note: i suspect this default 0 should come from something that knows this desc grammar. suffix = param.options.get('suffix', '') if suffix: self.chirality_N_spinbox.setSuffix(QtGui.QApplication.translate(self.__class__.__name__, suffix)) else: self.chirality_N_spinbox.setSuffix(QString.null) # probably not needed nt_parameters_body_layout.addWidget(self.chirality_N_spinbox,thisrow,1) hidethese.append(self.chirality_N_spinbox) getter = self.chirality_N_spinbox.value # note: it also has .text, which includes suffix else: print "didn't match:",param ###e improve this # things done the same way for all kinds of param-editing widgets if 1: #bruce 060703 moved this down here, as bugfix # set tooltip (same one for editfield and label) tooltip = param.options.get('tooltip', '') ###e do it for more kinds of params; share the code somehow; do it in controller, or setup-aid? ###k QToolTip appropriateness; tooltip option might be entirely untested if tooltip and label: QToolTip.add(label, QtGui.QApplication.translate(self.__class__.__name__, tooltip)) if tooltip and editfield: QToolTip.add(editfield, QtGui.QApplication.translate(self.__class__.__name__, tooltip)) ##k ok?? review once not all params have same-row labels. if getter and paramname and paramname != '?': self.param_getters[paramname] = getter ### also bind these params to actions... continue # next param header_refs.extend( [self.parameters_grpbox, self.nt_parameters_grpbtn, self.parameters_grpbox_label] ) # now create the logic/control object for the group group = CollapsibleGroupController_Qt(self, group_desc, header_refs, hidethese, self.nt_parameters_grpbtn) ### maybe ask env for the class to use for this? self.groups.append(group) ### needed?? only for scanning the params, AFAIK -- oh, and to maintain a python refcount. # from languageChange: if 1: # i don't know if these are needed: self.parameters_grpbox.setTitle(QString.null) self.nt_parameters_grpbtn.setText(QString.null) self.parameters_grpbox_label.setText(QtGui.QApplication.translate(self.__class__.__name__, group_desc.args[0])) # was "Nanotube Parameters" ##e note that it's questionable in the syntax design for this property of a group (overall group label) # to be in that position (desc arg 0). # == end its kids parameters_grpboxLayout.addLayout(nt_parameters_body_layout) body_frameLayout.addWidget(self.parameters_grpbox) # == end parameters groupbox continue # next group nanotube_dialogLayout.addWidget(self.body_frame) spacer14 = QSpacerItem(20,20,QSizePolicy.Minimum,QSizePolicy.Expanding) nanotube_dialogLayout.addItem(spacer14) layout42 = QHBoxLayout(None,4,6,"layout42") btm_spacer = QSpacerItem(59,20,QSizePolicy.Expanding,QSizePolicy.Minimum) layout42.addItem(btm_spacer) self.cancel_btn = QPushButton(self,"cancel_btn") self.cancel_btn.setAutoDefault(0) #bruce 060703 bugfix layout42.addWidget(self.cancel_btn) self.ok_btn = QPushButton(self,"ok_btn") self.ok_btn.setAutoDefault(0) #bruce 060703 bugfix layout42.addWidget(self.ok_btn) nanotube_dialogLayout.addLayout(layout42) self.languageChange() self.resize(QSize(246,618).expandedTo(self.minimumSizeHint())) ### this size will need to be adjusted (guess -- it's only place overall size is set) qt4todo('self.clearWState(Qt.WState_Polished)') ## self.connect(self.nt_parameters_grpbtn,SIGNAL("clicked()"),self.toggle_nt_parameters_grpbtn) #### # new: for button, methodname in ((self.sponsor_btn, 'do_sponsor_btn'), #e generalize to more than one sponsor button (self.done_btn, 'do_done_btn'), (self.abort_btn, 'do_abort_btn'), (self.preview_btn, 'do_preview_btn'), (self.whatsthis_btn, 'do_whatsthis_btn'), (self.cancel_btn, 'do_cancel_btn'), (self.ok_btn, 'do_ok_btn')): if hasattr(self, methodname): self.connect(button, SIGNAL("clicked()"), getattr(self, methodname)) return def languageChange(self): opts = self.desc.option_attrs self.setCaption(QtGui.QApplication.translate(self.__class__.__name__, opts.caption)) # was "Nanotube" self.heading_label.setText(QtGui.QApplication.translate(self.__class__.__name__, opts.title)) # was "Nanotube" self.sponsor_btn.setText(QString.null) self.done_btn.setText(QString.null) QToolTip.add(self.done_btn,QtGui.QApplication.translate(self.__class__.__name__, "Done")) self.abort_btn.setText(QString.null) QToolTip.add(self.abort_btn,QtGui.QApplication.translate(self.__class__.__name__, "Cancel")) self.preview_btn.setText(QString.null) QToolTip.add(self.preview_btn,QtGui.QApplication.translate(self.__class__.__name__, "Preview")) self.whatsthis_btn.setText(QString.null) QToolTip.add(self.whatsthis_btn,QtGui.QApplication.translate(self.__class__.__name__, "What's This Help")) ### move these up: ## if 0: ## self.parameters_grpbox.setTitle(QString.null) ## self.nt_parameters_grpbtn.setText(QString.null) ## self.parameters_grpbox_label.setText(QtGui.QApplication.translate(self.__class__.__name__, "Nanotube Parameters")) ## if 0: ## self.members_label.setText(QtGui.QApplication.translate(self.__class__.__name__, "Members :")) ## self.length_label.setText(QtGui.QApplication.translate(self.__class__.__name__, "Length :")) ## self.chirality_n_label.setText(QtGui.QApplication.translate(self.__class__.__name__, "Chirality (n) :")) ## self.members_combox.clear() ## self.members_combox.insertItem(QtGui.QApplication.translate(self.__class__.__name__, "C - C")) ## self.members_combox.insertItem(QtGui.QApplication.translate(self.__class__.__name__, "B - N")) ## self.length_linedit.setText(QtGui.QApplication.translate(self.__class__.__name__, "20.0 A")) ## self.chirality_N_spinbox.setSuffix(QString.null) self.cancel_btn.setText(QtGui.QApplication.translate(self.__class__.__name__, "Cancel")) self.ok_btn.setText(QtGui.QApplication.translate(self.__class__.__name__, "OK")) return pass # end of class parameter_dialog_or_frame -- maybe it should be renamed
class PM_Dialog( QDialog, SponsorableMixin ): """ The PM_Dialog class is the base class for Property Manager dialogs. [To make a PM class from this superclass, subclass it to customize the widget set and add behavior. You must also provide certain methods that used to be provided by GeneratorBaseClass, including ok_btn_clicked and several others, including at least some defined by SponsorableMixin (open_sponsor_homepage, setSponsor). This set of requirements may be cleaned up.] """ headerTitleText = "" # The header title text. _widgetList = [] # A list of all group boxes in this PM dialog, # including the message group box # (but not header, sponsor button, etc.) _groupBoxCount = 0 # Number of PM_GroupBoxes in this PM dialog _lastGroupBox = None # The last PM_GroupBox in this PM dialog # (i.e. the most recent PM_GroupBox added) def __init__(self, name, iconPath = "", title = "" ): """ Property Manager constructor. @param name: the name to assign the property manager dialog object. @type name: str @param iconPath: the relative path for the icon (PNG image) that appears in the header. @type iconPath: str @param title: the title that appears in the header. @type title: str """ QDialog.__init__(self) self.setObjectName(name) self._widgetList = [] # Main pallete for PropMgr. self.setPalette(QPalette(pmColor)) # Main vertical layout for PropMgr. self.vBoxLayout = QVBoxLayout(self) self.vBoxLayout.setMargin(PM_MAINVBOXLAYOUT_MARGIN) self.vBoxLayout.setSpacing(PM_MAINVBOXLAYOUT_SPACING) # Add PropMgr's header, sponsor button, top row buttons and (hidden) # message group box. self._createHeader(iconPath, title) self._createSponsorButton() self._createTopRowBtns() # Create top buttons row self.MessageGroupBox = PM_MessageGroupBox(self) # Keep the line below around; it might be useful. # I may want to use it now that I understand it. # Mark 2007-05-17. #QMetaObject.connectSlotsByName(self) self._addGroupBoxes() try: self._addWhatsThisText() except: print_compact_traceback("Error loading whatsthis text for this " "property manager: ") try: self._addToolTipText() except: print_compact_traceback("Error loading tool tip text for this " "property manager: ") #The following attr is used for comparison in method #'_update_UI_wanted_as_something_changed' self._previous_all_change_indicators = None def update_UI(self): """ Update whatever is shown in this PM based on current state of the rest of the system, especially the state of self.command and of the model it shows. This is part of the PM API required by baseCommand, since it's called by baseCommand.command_update_UI. @note: Overridden in Command_PropertyManager, but should not be overridden in its subclasses. See that method's docstring for details. """ #bruce 081125 defined this here, to fix bugs in example commands return def keyPressEvent(self, event): """ Handles keyPress event. @note: Subclasses should carefully override this. Note that the default implementation doesn't permit ESC key as a way to close the PM_dialog. (This is typically desirable for Property Managers.) If any subclass needs to implement the key press, they should first call this method (i.e. superclass.keyPressEvent) and then implement specific code that closes the dialog when ESC key is pressed. """ key = event.key() # Don't use ESC key to close the PM dialog. Fixes bug 2596 if key == Qt.Key_Escape: pass else: QDialog.keyPressEvent(self, event) return def _addGroupBoxes(self): """ Add various group boxes to this PM. Subclasses should override this method. """ pass def _addWhatsThisText(self): """ Add what's this text. Subclasses should override this method. """ pass def _addToolTipText(self): """ Add Tool tip text. Subclasses should override this method. """ pass def show(self): """ Shows the Property Manager. """ self.setSponsor() # Show or hide the sponsor logo based on whether the user gave # permission to download sponsor logos. if env.prefs[sponsor_download_permission_prefs_key]: self.sponsorButtonContainer.show() else: self.sponsorButtonContainer.hide() if not self.pw or self: self.pw = self.win.activePartWindow() self.pw.updatePropertyManagerTab(self) self.pw.pwProjectTabWidget.setCurrentIndex( self.pw.pwProjectTabWidget.indexOf(self)) # Show the default message whenever we open the Property Manager. self.MessageGroupBox.MessageTextEdit.restoreDefault() def open(self, pm): """ Closes the current property manager (if any) and opens the property manager I{pm}. @param pm: The property manager to open. @type pm: L{PM_Dialog} or QDialog (of legacy PMs) @attention: This method is a temporary workaround for "Insert > Plane". The current command should always be responsible for (re)opening its own PM via self.show(). @see: L{show()} """ if 1: commandSequencer = self.win.commandSequencer #bruce 071008 commandName = commandSequencer.currentCommand.commandName # that's an internal name, but this is just for a debug print print "PM_Dialog.open(): Reopening the PM for command:", commandName # The following line of code is buggy when you, for instance, exit a PM # and reopen the previous one. It sends the disconnect signal twice to # the PM that is just closed.So disabling this line -- Ninad 2007-12-04 ##self.close() # Just in case there is another PM open. self.pw = self.win.activePartWindow() self.pw.updatePropertyManagerTab(pm) try: pm.setSponsor() except: print """PM_Dialog.open(): pm has no attribute 'setSponsor()' ignoring.""" self.pw.pwProjectTabWidget.setCurrentIndex( self.pw.pwProjectTabWidget.indexOf(pm)) def close(self): """ Closes the Property Manager. """ if not self.pw: self.pw = self.win.activePartWindow() self.pw.pwProjectTabWidget.setCurrentIndex(0) ## try: [bruce 071018 moved this lower, since errmsg only covers attr] pmWidget = self.pw.propertyManagerScrollArea.widget() if debug_flags.atom_debug: #bruce 071018 "atom_debug fyi: %r is closing %r (can they differ?)" % \ (self, pmWidget) try: pmWidget.update_props_if_needed_before_closing except AttributeError: if 1 or debug_flags.atom_debug: msg1 = "Last PropMgr %r doesn't have method" % pmWidget msg2 = " update_props_if_needed_before_closing. That's" msg3 = " OK (for now, only implemented for Plane PM). " msg4 = "Ignoring Exception: " print_compact_traceback(msg1 + msg2 + msg3 + msg4) #bruce 071018: I'll define that method in PM_Dialog # so this message should become rare or nonexistent, # so I'll make it happen whether or not atom_debug. else: pmWidget.update_props_if_needed_before_closing() self.pw.pwProjectTabWidget.removeTab( self.pw.pwProjectTabWidget.indexOf( self.pw.propertyManagerScrollArea)) if self.pw.propertyManagerTab: self.pw.propertyManagerTab = None def update_props_if_needed_before_closing(self): # bruce 071018 default implem """ Subclasses can override this to update some cosmetic properties of their associated model objects before closing self (the Property Manager). """ pass def updateMessage(self, msg = ''): """ Updates the message box with an informative message @param msg: Message to be displayed in the Message groupbox of the property manager @type msg: string """ self.MessageGroupBox.insertHtmlMessage(msg, setAsDefault = False, minLines = 5) def _createHeader(self, iconPath, title): """ Creates the Property Manager header, which contains an icon (a QLabel with a pixmap) and white text (a QLabel with text). @param iconPath: The relative path for the icon (PNG image) that appears in the header. @type iconPath: str @param title: The title that appears in the header. @type title: str """ # Heading frame (dark gray), which contains # a pixmap and (white) heading text. self.headerFrame = QFrame(self) self.headerFrame.setFrameShape(QFrame.NoFrame) self.headerFrame.setFrameShadow(QFrame.Plain) self.headerFrame.setPalette(QPalette(pmHeaderFrameColor)) self.headerFrame.setAutoFillBackground(True) # HBox layout for heading frame, containing the pixmap # and label (title). HeaderFrameHLayout = QHBoxLayout(self.headerFrame) # 2 pixels around edges -- HeaderFrameHLayout.setMargin(PM_HEADER_FRAME_MARGIN) # 5 pixel between pixmap and label. -- HeaderFrameHLayout.setSpacing(PM_HEADER_FRAME_SPACING) # PropMgr icon. Set image by calling setHeaderIcon(). self.headerIcon = QLabel(self.headerFrame) self.headerIcon.setSizePolicy( QSizePolicy(QSizePolicy.Policy(QSizePolicy.Fixed), QSizePolicy.Policy(QSizePolicy.Fixed))) self.headerIcon.setScaledContents(True) HeaderFrameHLayout.addWidget(self.headerIcon) # PropMgr header title text (a QLabel). self.headerTitle = QLabel(self.headerFrame) headerTitlePalette = self._getHeaderTitlePalette() self.headerTitle.setPalette(headerTitlePalette) self.headerTitle.setAlignment(PM_LABEL_LEFT_ALIGNMENT) # Assign header title font. self.headerTitle.setFont(self._getHeaderFont()) HeaderFrameHLayout.addWidget(self.headerTitle) self.vBoxLayout.addWidget(self.headerFrame) # Set header icon and title text. self.setHeaderIcon(iconPath) self.setHeaderTitle(title) def _getHeaderFont(self): """ Returns the font used for the header. @return: the header font @rtype: QFont """ font = QFont() font.setFamily(PM_HEADER_FONT) font.setPointSize(PM_HEADER_FONT_POINT_SIZE) font.setBold(PM_HEADER_FONT_BOLD) return font def setHeaderTitle(self, title): """ Set the Property Manager header title to string <title>. @param title: the title to insert in the header. @type title: str """ self.headerTitleText = title self.headerTitle.setText(title) def setHeaderIcon(self, iconPath): """ Set the Property Manager header icon. @param iconPath: the relative path to the PNG file containing the icon image. @type iconPath: str """ if not iconPath: return self.headerIcon.setPixmap(getpixmap(iconPath)) def _createSponsorButton(self): """ Creates the Property Manager sponsor button, which contains a QPushButton inside of a QGridLayout inside of a QFrame. The sponsor logo image is not loaded here. """ # Sponsor button (inside a frame) self.sponsorButtonContainer = QWidget(self) SponsorFrameGrid = QGridLayout(self.sponsorButtonContainer) SponsorFrameGrid.setMargin(PM_SPONSOR_FRAME_MARGIN) SponsorFrameGrid.setSpacing(PM_SPONSOR_FRAME_SPACING) # Has no effect. self.sponsor_btn = QToolButton(self.sponsorButtonContainer) self.sponsor_btn.setAutoRaise(True) self.connect(self.sponsor_btn, SIGNAL("clicked()"), self.open_sponsor_homepage) SponsorFrameGrid.addWidget(self.sponsor_btn, 0, 0, 1, 1) self.vBoxLayout.addWidget(self.sponsorButtonContainer) button_whatsthis_widget = self.sponsor_btn #bruce 070615 bugfix -- put tooltip & whatsthis on self.sponsor_btn, # not self. # [self.sponsorButtonContainer might be another possible place to put them.] button_whatsthis_widget.setWhatsThis("""<b>Sponsor Button</b> <p>When clicked, this sponsor logo will display a short description about a NanoEngineer-1 sponsor. This can be an official sponsor or credit given to a contributor that has helped code part or all of this command. A link is provided in the description to learn more about this sponsor.</p>""") button_whatsthis_widget.setToolTip("NanoEngineer-1 Sponsor Button") return def _createTopRowBtns(self): """ Creates the Done, Cancel, Preview, Restore Defaults and What's This buttons row at the top of the Property Manager. """ topBtnSize = QSize(22, 22) # button images should be 16 x 16, though. # Main "button group" widget (but it is not a QButtonGroup). self.pmTopRowBtns = QHBoxLayout() # This QHBoxLayout is (probably) not necessary. Try using just the frame # for the foundation. I think it should work. Mark 2007-05-30 # Horizontal spacer horizontalSpacer = QSpacerItem(1, 1, QSizePolicy.Expanding, QSizePolicy.Minimum) # Widget containing all the buttons. self.topRowBtnsContainer = QWidget() # Create Hbox layout for main frame. topRowBtnsHLayout = QHBoxLayout(self.topRowBtnsContainer) topRowBtnsHLayout.setMargin(PM_TOPROWBUTTONS_MARGIN) topRowBtnsHLayout.setSpacing(PM_TOPROWBUTTONS_SPACING) # Set to True to center align the buttons in the PM if False: # Left aligns the buttons. topRowBtnsHLayout.addItem(horizontalSpacer) # Done (OK) button. self.done_btn = QToolButton(self.topRowBtnsContainer) self.done_btn.setIcon( geticon("ui/actions/Properties Manager/Done_16x16.png")) self.done_btn.setIconSize(topBtnSize) self.done_btn.setAutoRaise(True) self.connect(self.done_btn, SIGNAL("clicked()"), self.doneButtonClicked) self.done_btn.setToolTip("Done") topRowBtnsHLayout.addWidget(self.done_btn) # Cancel (Abort) button. self.cancel_btn = QToolButton(self.topRowBtnsContainer) self.cancel_btn.setIcon( geticon("ui/actions/Properties Manager/Abort_16x16.png")) self.cancel_btn.setIconSize(topBtnSize) self.cancel_btn.setAutoRaise(True) self.connect(self.cancel_btn, SIGNAL("clicked()"), self.cancelButtonClicked) self.cancel_btn.setToolTip("Cancel") topRowBtnsHLayout.addWidget(self.cancel_btn) #@ abort_btn deprecated. We still need it because modes use it. self.abort_btn = self.cancel_btn # Restore Defaults button. self.restore_defaults_btn = QToolButton(self.topRowBtnsContainer) self.restore_defaults_btn.setIcon( geticon("ui/actions/Properties Manager/Restore_16x16.png")) self.restore_defaults_btn.setIconSize(topBtnSize) self.restore_defaults_btn.setAutoRaise(True) self.connect(self.restore_defaults_btn, SIGNAL("clicked()"), self.restoreDefaultsButtonClicked) self.restore_defaults_btn.setToolTip("Restore Defaults") topRowBtnsHLayout.addWidget(self.restore_defaults_btn) # Preview (glasses) button. self.preview_btn = QToolButton(self.topRowBtnsContainer) self.preview_btn.setIcon( geticon("ui/actions/Properties Manager/Preview_16x16.png")) self.preview_btn.setIconSize(topBtnSize) self.preview_btn.setAutoRaise(True) self.connect(self.preview_btn, SIGNAL("clicked()"), self.previewButtonClicked) self.preview_btn.setToolTip("Preview") topRowBtnsHLayout.addWidget(self.preview_btn) # What's This (?) button. self.whatsthis_btn = QToolButton(self.topRowBtnsContainer) self.whatsthis_btn.setIcon( geticon("ui/actions/Properties Manager/WhatsThis_16x16.png")) self.whatsthis_btn.setIconSize(topBtnSize) self.whatsthis_btn.setAutoRaise(True) self.connect(self.whatsthis_btn, SIGNAL("clicked()"), self.whatsThisButtonClicked) self.whatsthis_btn.setToolTip("Enter \"What's This\" help mode") topRowBtnsHLayout.addWidget(self.whatsthis_btn) topRowBtnsHLayout.addItem(horizontalSpacer) # Create Button Row self.pmTopRowBtns.addWidget(self.topRowBtnsContainer) self.vBoxLayout.addLayout(self.pmTopRowBtns) # Add What's This for buttons. self.done_btn.setWhatsThis("""<b>Done</b> <p> <img source=\"ui/actions/Properties Manager/Done_16x16.png\"><br> Completes and/or exits the current command.</p>""") self.cancel_btn.setWhatsThis("""<b>Cancel</b> <p> <img source=\"ui/actions/Properties Manager/Abort_16x16.png\"><br> Cancels the current command.</p>""") self.restore_defaults_btn.setWhatsThis("""<b>Restore Defaults</b> <p><img source=\"ui/actions/Properties Manager/Restore_16x16.png\"><br> Restores the defaut values of the Property Manager.</p>""") self.preview_btn.setWhatsThis("""<b>Preview</b> <p> <img source=\"ui/actions/Properties Manager/Preview_16x16.png\"><br> Preview the structure based on current Property Manager settings. </p>""") self.whatsthis_btn.setWhatsThis("""<b>What's This</b> <p> <img source=\"ui/actions/Properties Manager/WhatsThis_16x16.png\"><br> This invokes \"What's This?\" help mode which is part of NanoEngineer-1's online help system, and provides users with information about the functionality and usage of a particular command button or widget. </p>""") return def hideTopRowButtons(self, pmButtonFlags = None): """ Hides one or more top row buttons using <pmButtonFlags>. Button flags not set will cause the button to be shown if currently hidden. @param pmButtonFlags: This enumerator describes the which buttons to hide, where: - PM_DONE_BUTTON = 1 - PM_CANCEL_BUTTON = 2 - PM_RESTORE_DEFAULTS_BUTTON = 4 - PM_PREVIEW_BUTTON = 8 - PM_WHATS_THIS_BUTTON = 16 - PM_ALL_BUTTONS = 31 @type pmButtonFlags: int """ if pmButtonFlags & PM_DONE_BUTTON: self.done_btn.hide() else: self.done_btn.show() if pmButtonFlags & PM_CANCEL_BUTTON: self.cancel_btn.hide() else: self.cancel_btn.show() if pmButtonFlags & PM_RESTORE_DEFAULTS_BUTTON: self.restore_defaults_btn.hide() else: self.restore_defaults_btn.show() if pmButtonFlags & PM_PREVIEW_BUTTON: self.preview_btn.hide() else: self.preview_btn.show() if pmButtonFlags & PM_WHATS_THIS_BUTTON: self.whatsthis_btn.hide() else: self.whatsthis_btn.show() def showTopRowButtons(self, pmButtonFlags = PM_ALL_BUTTONS): """ Shows one or more top row buttons using <pmButtonFlags>. Button flags not set will cause the button to be hidden if currently displayed. @param pmButtonFlags: this enumerator describes which buttons to display, where: - PM_DONE_BUTTON = 1 - PM_CANCEL_BUTTON = 2 - PM_RESTORE_DEFAULTS_BUTTON = 4 - PM_PREVIEW_BUTTON = 8 - PM_WHATS_THIS_BUTTON = 16 - PM_ALL_BUTTONS = 31 @type pmButtonFlags: int """ self.hideTopRowButtons(pmButtonFlags ^ PM_ALL_BUTTONS) def _getHeaderTitlePalette(self): """ Return a palette for header title (text) label. """ palette = QPalette() palette.setColor(QPalette.WindowText, pmHeaderTitleColor) return palette def doneButtonClicked(self): # note: never overridden, as of 080815 """ Slot for the Done button. """ self.ok_btn_clicked() def cancelButtonClicked(self): # note: never overridden, as of 080815 """ Slot for the Cancel button. """ self.cancel_btn_clicked() def restoreDefaultsButtonClicked(self): """ Slot for "Restore Defaults" button in the Property Manager. It is called each time the button is clicked. """ for widget in self._widgetList: if isinstance(widget, PM_GroupBox): widget.restoreDefault() def previewButtonClicked(self): """ Slot for the Preview button. """ self.preview_btn_clicked() def whatsThisButtonClicked(self): """ Slot for the What's This button. """ QWhatsThis.enterWhatsThisMode() # default implementations for subclasses # [bruce 080815 pulled these in from subclasses] def ok_btn_clicked(self): """ Implements Done button. Called by its slot method in PM_Dialog. [subclasses can override as needed] """ self.win.toolsDone() def cancel_btn_clicked(self): """ Implements Cancel button. Called by its slot method in PM_Dialog. [subclasses can override as needed] """ # Note: many subclasses override this to call self.w.toolsDone # (rather than toolsCancel). This should be cleaned up # so those overrides are not needed. (Maybe they are already # not needed.) [bruce 080815 comment] self.win.toolsCancel() pass
class DiagnosticGui(Plugin): last_suppress_time = Time() last_twist_time = Time() gui_update_timer = QTimer() # Raw joystick data joystick_data = [] joystick_table_vals = [] joystick_channel_text = ['CHAN_ENABLE: ', 'CHAN_ROTATE: ', 'CHAN_FORWARD: ', 'CHAN_LATERAL: ', 'CHAN_MODE: ', 'CHAN_EXTRA: '] joystick_bind_status = False joystick_bind_dot_counter = 0 # Mode current_mode = -1 # Topic pub timeouts JOYSTICK_SUPPRESS_PERIOD = 0.2 # 5 Hz CMD_VEL_TIMEOUT_PERIOD = 0.2 # 5 Hz joystick_suppressed = False command_received = False current_cmd = Twist() battery_percent = 0 battery_voltage = 0 # Checklist icons bad_icon = QPixmap() good_icon = QPixmap() none_icon = QPixmap() # Checklist status GOOD = 0 BAD = 1 NONE = 2 # Checklist variables checklist_status = [] BATT_MAN = 0 ESTOP_MAN = 1 DISABLE_MAN = 2 JOYSTICK_MAN = 3 SUPPRESS_MAN = 4 BATT_COMP = 5 ESTOP_COMP = 6 DISABLE_COMP = 7 JOYSTICK_COMP = 8 SUPPRESS_COMP = 9 CMD_COMP = 10 # Bumpers bumper_front_left = 0 bumper_front_right = 0 bumper_rear_left = 0 bumper_rear_right = 0 # Gyro cal gyro_cal_status = False gyro_x = 0.0 gyro_y = 0.0 gyro_z = 0.0 cal_enabled = True cal_time = rospy.Time(0) # Max speed config max_speed_known = False max_speed_dirty = True max_linear_actual = 0.0 max_angular_actual = 0.0 max_linear_setting = 0.0 max_angular_setting = 0.0 # Wake time current_wake_time = rospy.Time(0) rel_wake_days = 0 rel_wake_hours = 0 rel_wake_minutes = 0 rel_wake_secs = 0 # Switching between tabs and full GUI is_currently_tab = False widget_count = 0 current_tab_idx = -1 raw_data_tab_idx = 5 # Check connection to base base_connected = False last_joystick_time = rospy.Time(0) # Constants stick_ind_lox = 80 stick_ind_loy = 136 stick_ind_rox = 286 stick_ind_roy = 135 stick_ind_range_pix = 88.0 stick_ind_range_max = JoystickRaw.MAX stick_ind_range_min = JoystickRaw.MIN stick_ind_range_mid = JoystickRaw.CENTER stick_ind_range_factor = stick_ind_range_pix / (stick_ind_range_max - stick_ind_range_min) stick_ind_radius = 7 mode_ind_x1 = 52 mode_ind_y1 = 37 mode_ind_x2 = 44 mode_ind_y2 = 13 power_ind_x1 = 160 power_ind_x2 = 206 power_ind_y = 213 bumper_fl_x = 70 bumper_fl_y = 60 bumper_fr_x = 293 bumper_fr_y = 60 bumper_rl_x = 70 bumper_rl_y = 282 bumper_rr_x = 293 bumper_rr_y = 282 bumper_dx = 62 bumper_dy = 54 joystick_table_left_edge = 440 joystick_table_top_edge = 525 twist_table_left_edge = 700 twist_table_top_edge = 580 battery_table_left_edge = 700 battery_table_top_edge = 730 def __init__(self, context): # Qt setup self.context_ = context self.initGui('full') # ROS setup topic_timeout_timer = rospy.Timer(rospy.Duration(0.02), self.topicTimeoutCallback) self.subscribeTopics() self.advertiseTopics() def initGui(self, gui_type): if gui_type == 'full': self.spawnFullGui() self.initTables(self._widget, self.joystick_table_left_edge, self.joystick_table_top_edge) else: self.spawnTabGui() self.initTables(self._widget.gui_tabs.widget(self.raw_data_tab_idx), 20, 20) self._widget.gui_tabs.setCurrentIndex(self.current_tab_idx) self.resetGuiTimer() self.initJoystickGraphics() self.initBumperGraphics() self.initChecklists() self.bindCallbacks() self.refreshMaxSpeed() # Initialize absolute wake time setter to current time datetime_now = QDateTime(QDate.currentDate(), QTime.currentTime()) self._widget.absolute_wake_time_obj.setDateTime(datetime_now) temp_time = self._widget.absolute_wake_time_obj.time() temp_time = QTime(temp_time.hour(), temp_time.minute()) self._widget.absolute_wake_time_obj.setTime(temp_time) # Set connection label text if self.base_connected: self._widget.disconnected_lbl.setVisible(False) else: self._widget.disconnected_lbl.setVisible(True) self._widget.disconnected_lbl.setText('<font color=#FF0000>NOT CONNECTED</font>') def topicTimeoutCallback(self, event): # Joystick suppression if (event.current_real - self.last_suppress_time).to_sec() < self.JOYSTICK_SUPPRESS_PERIOD and self.suppress_dt.to_sec() <= 1.0/9.0: self.joystick_suppressed = True else: self.joystick_suppressed = False # Command message if (event.current_real - self.last_twist_time).to_sec() < self.CMD_VEL_TIMEOUT_PERIOD and self.twist_dt.to_sec() <= 1.0/6.0: self.command_received = True else: self.command_received = False def initChecklists(self): self.bad_icon.load(os.path.join(rospkg.RosPack().get_path('mobility_base_tools'), 'images', 'bad.png')) self.good_icon.load(os.path.join(rospkg.RosPack().get_path('mobility_base_tools'), 'images', 'good.png')) self.none_icon.load(os.path.join(rospkg.RosPack().get_path('mobility_base_tools'), 'images', 'none.png')) self.checklist_status=[0 for i in range(self.CMD_COMP + 1)] self.checklist_status[self.BATT_MAN] = self.NONE self.checklist_status[self.ESTOP_MAN] = self.NONE self.checklist_status[self.DISABLE_MAN] = self.NONE self.checklist_status[self.JOYSTICK_MAN] = self.NONE self.checklist_status[self.SUPPRESS_MAN] = self.NONE self.checklist_status[self.BATT_COMP] = self.NONE self.checklist_status[self.ESTOP_COMP] = self.NONE self.checklist_status[self.DISABLE_COMP] = self.NONE self.checklist_status[self.JOYSTICK_COMP] = self.NONE self.checklist_status[self.SUPPRESS_COMP] = self.NONE self.checklist_status[self.CMD_COMP] = self.NONE def initTabTables(self): self.joystick_table_vals = [QLabel(self._widget.gui_tabs.widget(self.raw_data_tab_idx)) for i in range(ChannelIndex.CHAN_EXTRA+1)] self.joystick_table_labels = [QLabel(self._widget.gui_tabs.widget(self.raw_data_tab_idx)) for i in range(ChannelIndex.CHAN_EXTRA+1)] self.joystick_table_heading = QLabel(self._widget.gui_tabs.widget(self.raw_data_tab_idx)) def initTables(self, widget, left, top): # Joystick data table self.joystick_data = [0 for i in range(ChannelIndex.CHAN_EXTRA+1)] self.joystick_table_vals = [QLabel(widget) for i in range(ChannelIndex.CHAN_EXTRA+1)] self.joystick_table_labels = [QLabel(widget) for i in range(ChannelIndex.CHAN_EXTRA+1)] self.joystick_table_heading = QLabel(widget) self.joystick_table_heading.setText('Raw Joystick Data') self.joystick_table_heading.setFont(QFont('Ubuntu', 11, QFont.Bold)) self.joystick_table_heading.move(left, top) for i in range(len(self.joystick_table_vals)): self.joystick_table_vals[i].move(left + 150, top + 30 * (i+1)) self.joystick_table_vals[i].setText('0000') self.joystick_table_vals[i].setFixedWidth(200) self.joystick_table_labels[i].move(left, top + 30 * (i+1)) self.joystick_table_labels[i].setText(self.joystick_channel_text[i]) # Twist data table self.twist_table_heading = QLabel(widget) self.twist_table_heading.setText('Current Twist Command') self.twist_table_heading.setFont(QFont('Ubuntu', 11, QFont.Bold)) self.twist_table_heading.move(left + 260, top) self.twist_table_labels = [QLabel(widget) for i in range(0, 3)] self.twist_table_vals = [QLabel(widget) for i in range(0, 3)] for i in range(len(self.twist_table_vals)): self.twist_table_vals[i].move(left + 260 + 150, top + 30 * (i+1)) self.twist_table_vals[i].setText('Not Published') self.twist_table_vals[i].setFixedWidth(200) self.twist_table_labels[i].move(left + 260, top + 30 * (i+1)) self.twist_table_labels[0].setText('Forward (m/s):') self.twist_table_labels[1].setText('Lateral (m/s):') self.twist_table_labels[2].setText('Rotation (rad/s):') # Battery percentage self.battery_heading = QLabel(widget) self.battery_heading.setText('Current Battery State') self.battery_heading.setFont(QFont('Ubuntu', 11, QFont.Bold)) self.battery_heading.move(left + 260, top + 150) self.battery_label = QLabel(widget) self.battery_label.move(left + 260, top + 150 +30) self.battery_label.setText('000 %') self.battery_voltage_label = QLabel(widget) self.battery_voltage_label.move(left + 260, top + 150 +60) self.battery_voltage_label.setText('00.00 V') self.battery_voltage_label.setFixedWidth(200) # Mode self.mode_heading = QLabel(widget) self.mode_heading.setFont(QFont('Ubuntu', 11, QFont.Bold)) self.mode_heading.move(left, top + 225) self.mode_heading.setText('Current Mode') self.mode_label = QLabel(widget) self.mode_label.move(left + 120, top + 225) self.mode_label.setText('XXXXXXXXXXXXXXXXXXXXXX') def bindCallbacks(self): self._widget.start_bind_btn.clicked.connect(self.startBind) self._widget.stop_bind_btn.clicked.connect(self.stopBind) self._widget.gyro_cal_btn.clicked.connect(self.calGyro) self._widget.clear_cal_btn.clicked.connect(self.clearCal) self._widget.max_linear_txt.editingFinished.connect(self.maxLinearChanged) self._widget.max_angular_txt.editingFinished.connect(self.maxAngularChanged) self._widget.set_speed_btn.clicked.connect(self.setMaxSpeed) self._widget.clear_speed_btn.clicked.connect(self.clearMaxSpeed) self._widget.wake_time_days_txt.editingFinished.connect(self.wakeDaysChanged) self._widget.wake_time_hours_txt.editingFinished.connect(self.wakeHoursChanged) self._widget.wake_time_minutes_txt.editingFinished.connect(self.wakeMinutesChanged) self._widget.wake_time_secs_txt.editingFinished.connect(self.wakeSecsChanged) self._widget.set_relative_wake_time_btn.clicked.connect(self.setRelativeWakeTime) self._widget.set_absolute_wake_time_btn.clicked.connect(self.setAbsoluteWakeTime) self._widget.clear_wake_time_btn.clicked.connect(self.clearWakeTime) if self.is_currently_tab: self._widget.gui_tabs.currentChanged.connect(self.setCurrentTab) def setCurrentTab(self, idx): self.current_tab_idx = self._widget.gui_tabs.currentIndex() def startBind(self): self.pub_start_bind.publish(std_msgs.msg.Empty()) def stopBind(self): self.pub_stop_bind.publish(std_msgs.msg.Empty()) def calGyro(self): gyro_cal_srv = rospy.ServiceProxy('/mobility_base/imu/calibrate', std_srvs.srv.Empty) try: gyro_cal_srv() self.cal_enabled = False self.cal_time = rospy.Time.now() except: pass def clearCal(self): clear_cal_srv = rospy.ServiceProxy('/mobility_base/imu/clear_cal', std_srvs.srv.Empty) try: clear_cal_srv() except: pass def maxLinearChanged(self): try: float_val = float(self._widget.max_linear_txt.text()) self.max_linear_setting = float_val; except ValueError: if self.max_linear_actual <= 0 or not isfinite(self.max_linear_actual): self.max_linear_setting = 0.0 else: self.max_linear_setting = self.max_linear_actual self.max_speed_dirty = True def maxAngularChanged(self): try: float_val = float(self._widget.max_angular_txt.text()) self.max_angular_setting = float_val; except ValueError: if self.max_angular_actual <= 0 or not isfinite(self.max_angular_actual): self.max_angular_setting = 0.0 else: self.max_angular_setting = self.max_angular_actual self.max_speed_dirty = True def setMaxSpeed(self): set_max_speed_srv = rospy.ServiceProxy('/mobility_base/set_max_speed', SetMaxSpeed) req = SetMaxSpeedRequest() req.linear = self.max_linear_setting req.angular = self.max_angular_setting try: set_max_speed_srv(req) self.max_speed_known = False except: pass def clearMaxSpeed(self): set_max_speed_srv = rospy.ServiceProxy('/mobility_base/set_max_speed', SetMaxSpeed) req = SetMaxSpeedRequest() req.linear = float('nan') req.angular = float('nan') try: set_max_speed_srv(req) self.max_speed_known = False except: pass def wakeDaysChanged(self): try: self.rel_wake_days = float(self._widget.wake_time_days_txt.text()) except: self._widget.wake_time_days_txt.setText(str(self.rel_wake_days)) def wakeHoursChanged(self): try: self.rel_wake_hours = float(self._widget.wake_time_hours_txt.text()) except: self._widget.wake_time_hours_txt.setText(str(self.rel_wake_hours)) def wakeMinutesChanged(self): try: self.rel_wake_minutes = float(self._widget.wake_time_minutes_txt.text()) except: self._widget.wake_time_minutes_txt.setText(str(self.rel_wake_minutes)) def wakeSecsChanged(self): try: self.rel_wake_secs = float(self._widget.wake_time_secs_txt.text()) except: self._widget.wake_time_secs_txt.setText(str(self.rel_wake_secs)) def setRelativeWakeTime(self): new_wake_time = std_msgs.msg.Time() rel_wake_time = 86400 * self.rel_wake_days + 3600 * self.rel_wake_hours + 60 * self.rel_wake_minutes + self.rel_wake_secs new_wake_time.data = rospy.Time.now() + rospy.Duration(rel_wake_time) self.pub_set_wake_time.publish(new_wake_time) def setAbsoluteWakeTime(self): self.pub_set_wake_time.publish(rospy.Time(self._widget.absolute_wake_time_obj.dateTime().toTime_t())) def clearWakeTime(self): self.pub_set_wake_time.publish(rospy.Time(0)) def refreshMaxSpeed(self): self.max_speed_dirty = True self.max_speed_known = False def updateGuiCallback(self): # Switch between tabs and full GUI if self.is_currently_tab: if self._widget.height() > 830 and self._widget.width() > 1205: self.is_currently_tab = False self.context_.remove_widget(self._widget) self.initGui('full') else: if self._widget.height() < 810 or self._widget.width() < 1185: self.is_currently_tab = True self.context_.remove_widget(self._widget) self.initGui('tab') # Check connection to base if self.base_connected and (rospy.Time.now() - self.last_joystick_time).to_sec() > 1.0: self.base_connected = False self._widget.disconnected_lbl.setText('<font color=#FF0000>NOT CONNECTED</font>') self._widget.disconnected_lbl.setVisible(True) if not self.base_connected and (rospy.Time.now() - self.last_joystick_time).to_sec() < 1.0: self.base_connected = True # self._widget.disconnected_lbl.setText('') self._widget.disconnected_lbl.setVisible(False) # Update checklists self.updateChecklist(); # Manage 5 second disable of gyro calibration button if not self.cal_enabled: if (rospy.Time.now() - self.cal_time).to_sec() > 5.0: self._widget.gyro_cal_btn.setEnabled(True) self._widget.gyro_cal_btn.setText('Calibrate') self.cal_enabled = True else: self._widget.gyro_cal_btn.setEnabled(False) self._widget.gyro_cal_btn.setText(str(5 - 0.1*floor(10*(rospy.Time.now() - self.cal_time).to_sec()))) # Update joystick graphics if not self.checkJoystickValid(): self.updateCheckStatus(self._widget.joystick_bind_chk, self.NONE) if not self.joystick_bind_status: self._widget.joystick_bind_lbl.setText('') for l in self.joystick_power_ind: l.setVisible(True) self.updateRightStickIndicator(self.stick_ind_range_mid, self.stick_ind_range_mid) self.updateLeftStickIndicator(self.stick_ind_range_mid, self.stick_ind_range_mid) else: self.updateCheckStatus(self._widget.joystick_bind_chk, self.GOOD) self._widget.joystick_bind_lbl.setText('Joystick bound') for l in self.joystick_power_ind: l.setVisible(False) self.updateRightStickIndicator(self.joystick_data[ChannelIndex.CHAN_LATERAL], self.joystick_data[ChannelIndex.CHAN_FORWARD]) self.updateLeftStickIndicator(self.joystick_data[ChannelIndex.CHAN_ROTATE], self.joystick_data[ChannelIndex.CHAN_ENABLE]) if self.joystick_data[ChannelIndex.CHAN_MODE] < self.stick_ind_range_mid: self.mode_ind.setPen(self.cyan_pen) self._widget.modeLabel.setText("0 (Computer)") else: self.mode_ind.setPen(self.magenta_pen) self._widget.modeLabel.setText("1 (Manual)") # Update joystick data table for i in range(len(self.joystick_table_vals)): self.joystick_table_vals[i].setText(str(self.joystick_data[i])) # Update twist data table if self.command_received: self.twist_table_vals[0].setText(str(0.01 * floor(100 * self.current_cmd.linear.x))) self.twist_table_vals[1].setText(str(0.01 * floor(100 * self.current_cmd.linear.y))) self.twist_table_vals[2].setText(str(0.01 * floor(100 * self.current_cmd.angular.z))) else: self.twist_table_vals[0].setText('Not Published') self.twist_table_vals[1].setText('Not Published') self.twist_table_vals[2].setText('Not Published') # Update battery percentage self.battery_label.setText(str(self.battery_percent) + ' %') self.battery_voltage_label.setText(str(0.01 * floor(100 * self.battery_voltage)) + ' V') # Update mode self.mode_label.setText(self.getModeString(self.current_mode)) # Update bumper graphics self.bumperVisibleSwitch(BumperIndex.BUMPER_1F, self.bumper_front_left) self.bumperVisibleSwitch(BumperIndex.BUMPER_2F, self.bumper_front_right) self.bumperVisibleSwitch(BumperIndex.BUMPER_3F, self.bumper_rear_left) self.bumperVisibleSwitch(BumperIndex.BUMPER_4F, self.bumper_rear_right) self.bumper_state_labels[0].setPlainText(str(self.bumper_front_left)) self.bumper_state_labels[1].setPlainText(str(self.bumper_front_right)) self.bumper_state_labels[2].setPlainText(str(self.bumper_rear_left)) self.bumper_state_labels[3].setPlainText(str(self.bumper_rear_right)) # Update gyro cal graphics if self.gyro_cal_status: self.updateCheckStatus(self._widget.gyro_cal_chk, self.GOOD) self._widget.gyro_cal_lbl.setText('Gyro calibrated') else: self.updateCheckStatus(self._widget.gyro_cal_chk, self.BAD) self._widget.gyro_cal_lbl.setText('Gyro NOT calibrated') self._widget.gyro_x_lbl.setText('x: ' + str(1e-5*floor(1e5*self.gyro_x))) self._widget.gyro_y_lbl.setText('y: ' + str(1e-5*floor(1e5*self.gyro_y))) self._widget.gyro_z_lbl.setText('z: ' + str(1e-5*floor(1e5*self.gyro_z))) # Update max speed configuration if not self.max_speed_known: service_name = '/mobility_base/get_max_speed' get_max_speed_srv = rospy.ServiceProxy(service_name, GetMaxSpeed) try: resp = get_max_speed_srv() self.max_speed_known = True self.max_linear_actual = resp.linear self.max_angular_actual = resp.angular if self.max_linear_actual <= 0 or not isfinite(self.max_linear_actual): self._widget.max_linear_lbl.setText('Unlimited') else: self._widget.max_linear_lbl.setText(str(1e-2*round(1e2*self.max_linear_actual))) if self.max_angular_actual <= 0 or not isfinite(self.max_angular_actual): self._widget.max_angular_lbl.setText('Unlimited') else: self._widget.max_angular_lbl.setText(str(1e-2*round(1e2*self.max_angular_actual))) except: pass # print service_name + " doesn't exist" if self.max_speed_dirty: self._widget.max_linear_txt.setText(str(self.max_linear_setting)) self._widget.max_angular_txt.setText(str(self.max_angular_setting)) self.max_speed_dirty = False # Wake time if self.current_wake_time == rospy.Time(0): self._widget.wake_time_lbl.setText('Not Set') else: self._widget.wake_time_lbl.setText(time.strftime('%m/%d/%Y, %H:%M:%S', time.localtime(self.current_wake_time.to_sec()))) def checkJoystickValid(self): return self.joystick_data[ChannelIndex.CHAN_FORWARD] > 0 or self.joystick_data[ChannelIndex.CHAN_LATERAL] > 0 or self.joystick_data[ChannelIndex.CHAN_ROTATE] > 0 or self.joystick_data[ChannelIndex.CHAN_MODE] > 0 def getModeString(self, mode_num): if mode_num == Mode.MODE_ESTOP: return 'MODE_ESTOP' elif mode_num == Mode.MODE_DISABLED: return 'MODE_DISABLED' elif mode_num == Mode.MODE_BATTERY_LIMP_HOME: return 'MODE_BATTERY_LIMP_HOME' elif mode_num == Mode.MODE_BATTERY_CRITICAL: return 'MODE_BATTERY_CRITICAL' elif mode_num == Mode.MODE_WIRELESS: return 'MODE_WIRELESS' elif mode_num == Mode.MODE_TIMEOUT: return 'MODE_TIMEOUT' elif mode_num == Mode.MODE_VELOCITY: return 'MODE_VELOCITY' elif mode_num == Mode.MODE_VELOCITY_RAW: return 'MODE_VELOCITY_RAW' else: return '' def updateChecklist(self): if self.current_mode >= Mode.MODE_TIMEOUT: self.checklist_status[self.BATT_MAN] = self.GOOD self.checklist_status[self.ESTOP_MAN] = self.GOOD self.checklist_status[self.DISABLE_MAN] = self.GOOD self.checklist_status[self.JOYSTICK_MAN] = self.BAD self.checklist_status[self.BATT_COMP] = self.GOOD self.checklist_status[self.ESTOP_COMP] = self.GOOD self.checklist_status[self.DISABLE_COMP] = self.GOOD self.checklist_status[self.JOYSTICK_COMP] = self.GOOD elif self.current_mode == Mode.MODE_WIRELESS: self.checklist_status[self.BATT_MAN] = self.GOOD self.checklist_status[self.ESTOP_MAN] = self.GOOD self.checklist_status[self.DISABLE_MAN] = self.GOOD self.checklist_status[self.JOYSTICK_MAN] = self.GOOD self.checklist_status[self.BATT_COMP] = self.GOOD self.checklist_status[self.ESTOP_COMP] = self.GOOD self.checklist_status[self.DISABLE_COMP] = self.GOOD self.checklist_status[self.JOYSTICK_COMP] = self.BAD elif self.current_mode == Mode.MODE_DISABLED: self.checklist_status[self.BATT_MAN] = self.NONE self.checklist_status[self.ESTOP_MAN] = self.GOOD self.checklist_status[self.DISABLE_MAN] = self.BAD self.checklist_status[self.JOYSTICK_MAN] = self.NONE self.checklist_status[self.BATT_COMP] = self.NONE self.checklist_status[self.ESTOP_COMP] = self.GOOD self.checklist_status[self.DISABLE_COMP] = self.BAD self.checklist_status[self.JOYSTICK_COMP] = self.NONE elif self.current_mode == Mode.MODE_ESTOP: self.checklist_status[self.BATT_MAN] = self.NONE self.checklist_status[self.ESTOP_MAN] = self.BAD self.checklist_status[self.DISABLE_MAN] = self.NONE self.checklist_status[self.JOYSTICK_MAN] = self.NONE self.checklist_status[self.BATT_COMP] = self.NONE self.checklist_status[self.ESTOP_COMP] = self.BAD self.checklist_status[self.DISABLE_COMP] = self.NONE self.checklist_status[self.JOYSTICK_COMP] = self.NONE elif self.current_mode == Mode.MODE_BATTERY_CRITICAL: self.checklist_status[self.BATT_MAN] = self.BAD self.checklist_status[self.ESTOP_MAN] = self.GOOD self.checklist_status[self.DISABLE_MAN] = self.GOOD self.checklist_status[self.JOYSTICK_MAN] = self.NONE self.checklist_status[self.BATT_COMP] = self.BAD self.checklist_status[self.ESTOP_COMP] = self.GOOD self.checklist_status[self.DISABLE_COMP] = self.GOOD self.checklist_status[self.JOYSTICK_COMP] = self.NONE elif self.current_mode == Mode.MODE_BATTERY_LIMP_HOME: self.checklist_status[self.BATT_MAN] = self.GOOD self.checklist_status[self.ESTOP_MAN] = self.GOOD self.checklist_status[self.DISABLE_MAN] = self.GOOD self.checklist_status[self.JOYSTICK_MAN] = self.NONE self.checklist_status[self.BATT_COMP] = self.BAD self.checklist_status[self.ESTOP_COMP] = self.GOOD self.checklist_status[self.DISABLE_COMP] = self.GOOD self.checklist_status[self.JOYSTICK_COMP] = self.NONE # Check if joystick is suppressed by topic if self.joystick_suppressed: self.checklist_status[self.SUPPRESS_COMP] = self.GOOD self.checklist_status[self.DISABLE_COMP] = self.NONE self.checklist_status[self.JOYSTICK_COMP] = self.NONE else: self.checklist_status[self.SUPPRESS_COMP] = self.NONE if (rospy.Time.now() - self.last_suppress_time).to_sec() > self.JOYSTICK_SUPPRESS_PERIOD: self.checklist_status[self.SUPPRESS_MAN] = self.GOOD else: self.checklist_status[self.SUPPRESS_MAN] = self.BAD # Command message received if self.command_received: self.checklist_status[self.CMD_COMP] = self.GOOD else: self.checklist_status[self.CMD_COMP] = self.BAD # Override twist checkbox if mode is in TIMEOUT if self.current_mode == Mode.MODE_TIMEOUT: self.checklist_status[self.CMD_COMP] = self.BAD # Update checklist graphics self.updateCheckStatus(self._widget.batt_man_chk, self.checklist_status[self.BATT_MAN]) self.updateCheckStatus(self._widget.estop_man_chk, self.checklist_status[self.ESTOP_MAN]) self.updateCheckStatus(self._widget.disable_man_chk, self.checklist_status[self.DISABLE_MAN]) self.updateCheckStatus(self._widget.joystick_man_chk, self.checklist_status[self.JOYSTICK_MAN]) self.updateCheckStatus(self._widget.suppress_man_chk, self.checklist_status[self.SUPPRESS_MAN]) self.updateCheckStatus(self._widget.batt_comp_chk, self.checklist_status[self.BATT_COMP]) self.updateCheckStatus(self._widget.estop_comp_chk, self.checklist_status[self.ESTOP_COMP]) self.updateCheckStatus(self._widget.disable_comp_chk, self.checklist_status[self.DISABLE_COMP]) self.updateCheckStatus(self._widget.joystick_comp_chk, self.checklist_status[self.JOYSTICK_COMP]) self.updateCheckStatus(self._widget.suppress_comp_chk, self.checklist_status[self.SUPPRESS_COMP]) self.updateCheckStatus(self._widget.cmd_comp_chk, self.checklist_status[self.CMD_COMP]) self.updateCheckStatus(self._widget.joystick_bind_chk, self.NONE) def updateCheckStatus(self, obj, icon_type): if icon_type == self.GOOD: obj.setPixmap(self.good_icon) elif icon_type == self.BAD: obj.setPixmap(self.bad_icon) else: obj.setPixmap(self.none_icon) def updateTable(self): for i in range(0, len(self.joystick_table_vals)): self.joystick_table_vals[i].setText(55) def recvMode(self, mode_msg): self.current_mode = mode_msg.mode def recvSuppress(self, suppress_msg): self.suppress_dt = rospy.Time.now() - self.last_suppress_time self.last_suppress_time = rospy.Time.now() def recvTwist(self, twist_msg): self.twist_dt = rospy.Time.now() - self.last_twist_time self.last_twist_time = rospy.Time.now() self.current_cmd = twist_msg def recvJoystick(self, joystick_msg): self.joystick_data = joystick_msg.channels; self.last_joystick_time = rospy.Time.now() def recvBumpers(self, bumper_msg): self.bumper_front_left = bumper_msg.front_left self.bumper_front_right = bumper_msg.front_right self.bumper_rear_left = bumper_msg.rear_left self.bumper_rear_right = bumper_msg.rear_right def recvBattery(self, battery_msg): self.battery_percent = battery_msg.percent self.battery_voltage = battery_msg.voltage def recvBindStatus(self, bind_msg): self.joystick_bind_status = bind_msg.data if bind_msg.data: if self.joystick_bind_dot_counter == 0: self._widget.joystick_bind_lbl.setText('Binding.') elif self.joystick_bind_dot_counter == 1: self._widget.joystick_bind_lbl.setText('Binding..') elif self.joystick_bind_dot_counter == 2: self._widget.joystick_bind_lbl.setText('Binding...') self.joystick_bind_dot_counter = (self.joystick_bind_dot_counter + 1) % 3 def recvGyroCalibrated(self, cal_msg): self.gyro_cal_status = cal_msg.data def recvImu(self, imu_msg): self.gyro_x = imu_msg.angular_velocity.x self.gyro_y = imu_msg.angular_velocity.y self.gyro_z = imu_msg.angular_velocity.z def recvWakeTime(self, time_msg): self.current_wake_time = time_msg.data def subscribeTopics(self): sub_joystick = rospy.Subscriber('/mobility_base/joystick_raw', JoystickRaw, self.recvJoystick) sub_suppress = rospy.Subscriber('/mobility_base/suppress_wireless', std_msgs.msg.Empty, self.recvSuppress) sub_twist = rospy.Subscriber('/mobility_base/cmd_vel', Twist, self.recvTwist) sub_mode = rospy.Subscriber('/mobility_base/mode', Mode, self.recvMode) sub_bumpers = rospy.Subscriber('/mobility_base/bumper_states', BumperState, self.recvBumpers) sub_battery = rospy.Subscriber('/mobility_base/battery', BatteryState, self.recvBattery) sub_bind = rospy.Subscriber('/mobility_base/bind_status', std_msgs.msg.Bool, self.recvBindStatus) sub_gyro_calibrated = rospy.Subscriber('/mobility_base/imu/is_calibrated', std_msgs.msg.Bool, self.recvGyroCalibrated) sub_imu = rospy.Subscriber('/mobility_base/imu/data_raw', Imu, self.recvImu) sub_wake_time = rospy.Subscriber('/mobility_base/wake_time', std_msgs.msg.Time, self.recvWakeTime) def advertiseTopics(self): self.pub_start_bind = rospy.Publisher('/mobility_base/bind_start', std_msgs.msg.Empty, queue_size=1) self.pub_stop_bind = rospy.Publisher('/mobility_base/bind_stop', std_msgs.msg.Empty, queue_size=1) self.pub_set_wake_time = rospy.Publisher('/mobility_base/set_wake_time', std_msgs.msg.Time, queue_size=1) def initJoystickGraphics(self): # Pens self.cyan_pen = QPen(QColor(0, 255, 255)) self.magenta_pen = QPen(QColor(255, 0, 255)) self.red_pen = QPen(QColor(255, 0, 0)) self.cyan_pen.setWidth(3) self.magenta_pen.setWidth(3) self.red_pen.setWidth(3) self.stick_ind_l = QGraphicsEllipseItem() self.stick_ind_r = QGraphicsEllipseItem() self.stick_line_l = QGraphicsLineItem() self.stick_line_r = QGraphicsLineItem() self.mode_ind = QGraphicsLineItem() # Left joystick indicator circle px_l = self.stick_ind_lox - self.stick_ind_radius py_l = self.stick_ind_loy - self.stick_ind_radius self.stick_ind_l.setRect(px_l, py_l, 2 * self.stick_ind_radius, 2 * self.stick_ind_radius) self.stick_ind_l.setBrush(QBrush(QColor(255, 0, 0))) self.stick_ind_l.setPen(QPen(QColor(0, 0, 0))) # Right joystick indicator circle px_r = self.stick_ind_rox - self.stick_ind_radius py_r = self.stick_ind_roy - self.stick_ind_radius self.stick_ind_r.setRect(px_r, py_r, 2 * self.stick_ind_radius, 2 * self.stick_ind_radius) self.stick_ind_r.setBrush(QBrush(QColor(255, 0, 0))) self.stick_ind_r.setPen(QPen(QColor(0, 0, 0))) # Left joystick indicator line line_pen = QPen(QColor(255,0,0)) line_pen.setWidth(4) self.stick_line_l.setLine(self.stick_ind_lox, self.stick_ind_loy, self.stick_ind_lox, self.stick_ind_loy) self.stick_line_l.setPen(line_pen) # Right joystick indicator line self.stick_line_r.setLine(self.stick_ind_rox, self.stick_ind_roy, self.stick_ind_rox, self.stick_ind_roy) self.stick_line_r.setPen(line_pen) # Mode indicator line self.mode_ind.setLine(self.mode_ind_x1, self.mode_ind_y1, self.mode_ind_x2, self.mode_ind_y2) self.mode_ind.setPen(self.cyan_pen) # Joystick power indicator self.joystick_power_ind = [] self.joystick_power_ind.append(QGraphicsLineItem(self.power_ind_x1, self.power_ind_y + 20, self.power_ind_x1, self.power_ind_y - 20)) self.joystick_power_ind.append(QGraphicsLineItem(self.power_ind_x1, self.power_ind_y - 20, self.power_ind_x1 + 50, self.power_ind_y - 20)) self.joystick_power_ind.append(QGraphicsLineItem(self.power_ind_x1+50, self.power_ind_y - 20, self.power_ind_x1+50, self.power_ind_y + 20)) self.joystick_power_ind.append(QGraphicsLineItem(self.power_ind_x1+50, self.power_ind_y + 20, self.power_ind_x1, self.power_ind_y + 20)) # Populate scene graphics_scene = QGraphicsScene() graphics_scene.addItem(self.stick_ind_l) graphics_scene.addItem(self.stick_ind_r) graphics_scene.addItem(self.stick_line_l) graphics_scene.addItem(self.stick_line_r) graphics_scene.addItem(self.mode_ind) for l in self.joystick_power_ind: l.setPen(self.red_pen) graphics_scene.addItem(l) graphics_scene.setSceneRect(0, 0, self._widget.joystickGraphicsView.width() - 4, self._widget.joystickGraphicsView.height() - 4) self._widget.joystickGraphicsView.setScene(graphics_scene) self._widget.joystickGraphicsView.setBackgroundBrush(QBrush(QImage(os.path.join(rospkg.RosPack().get_path('mobility_base_tools'), 'images', 'dx6ilabels.jpg')))) self._widget.joystickGraphicsView.show() def initBumperGraphics(self): # Pens self.blue_pen = QPen(QColor(0,0,255)) self.blue_pen.setWidth(10) self.bumper_lines = [] # Text state labels self.bumper_state_labels = [QGraphicsTextItem() for i in range(0,4)] for i in range(len(self.bumper_state_labels)): self.bumper_state_labels[i].setFont(QFont('Ubuntu', 14, QFont.Bold)) self.bumper_state_labels[i].setPlainText('00') self.bumper_state_labels[0].setPos(self.bumper_fl_x-10, self.bumper_fl_y + 55) self.bumper_state_labels[1].setPos(self.bumper_fr_x-10, self.bumper_fr_y + 55) self.bumper_state_labels[2].setPos(self.bumper_rl_x-10, self.bumper_rl_y - 80) self.bumper_state_labels[3].setPos(self.bumper_rr_x-10, self.bumper_rr_y - 80) # Bumper indicator lines self.bumperLine(self.bumper_fl_x - 20, self.bumper_fl_y - self.bumper_dy, True) self.bumperLine(self.bumper_fl_x - self.bumper_dx, self.bumper_fl_y - 20, False) self.bumperLine(self.bumper_fl_x + self.bumper_dx, self.bumper_fl_y - 20, False) self.bumperLine(self.bumper_fl_x - 20, self.bumper_fl_y + self.bumper_dy, True) self.bumperLine(self.bumper_fr_x - 20, self.bumper_fr_y - self.bumper_dy, True) self.bumperLine(self.bumper_fr_x - self.bumper_dx, self.bumper_fr_y - 20, False) self.bumperLine(self.bumper_fr_x + self.bumper_dx, self.bumper_fr_y - 20, False) self.bumperLine(self.bumper_fr_x - 20, self.bumper_fr_y + self.bumper_dy, True) self.bumperLine(self.bumper_rl_x - 20, self.bumper_rl_y - self.bumper_dy, True) self.bumperLine(self.bumper_rl_x - self.bumper_dx, self.bumper_rl_y - 20, False) self.bumperLine(self.bumper_rl_x + self.bumper_dx, self.bumper_rl_y - 20, False) self.bumperLine(self.bumper_rl_x - 20, self.bumper_rl_y + self.bumper_dy, True) self.bumperLine(self.bumper_rr_x - 20, self.bumper_rr_y - self.bumper_dy, True) self.bumperLine(self.bumper_rr_x - self.bumper_dx, self.bumper_rr_y - 20, False) self.bumperLine(self.bumper_rr_x + self.bumper_dx, self.bumper_rr_y - 20, False) self.bumperLine(self.bumper_rr_x - 20, self.bumper_rr_y + self.bumper_dy, True) # Populate scene graphics_scene = QGraphicsScene() for bumper in self.bumper_lines: graphics_scene.addItem(bumper) for label in self.bumper_state_labels: graphics_scene.addItem(label) graphics_scene.setSceneRect(0, 0, self._widget.bumperGraphicsView.width() - 4, self._widget.bumperGraphicsView.height() - 4) self._widget.bumperGraphicsView.setScene(graphics_scene) self._widget.bumperGraphicsView.setBackgroundBrush(QBrush(QImage(os.path.join(rospkg.RosPack().get_path('mobility_base_tools'), 'images', 'mb_top.png')))) self._widget.bumperGraphicsView.show() def bumperLine(self, x, y, front): new_line = QGraphicsLineItem() if front: new_line.setLine(x, y, x+40, y) else: new_line.setLine(x, y, x, y+40) new_line.setPen(self.blue_pen) new_line.setVisible(False) self.bumper_lines.append(new_line) def bumperVisibleSwitch(self, idx, bumper_state): if (bumper_state & BumperState.BUMPER_FRONT): self.bumper_lines[idx].setVisible(True) else: self.bumper_lines[idx].setVisible(False) if (bumper_state & BumperState.BUMPER_LEFT): self.bumper_lines[idx+1].setVisible(True) else: self.bumper_lines[idx+1].setVisible(False) if (bumper_state & BumperState.BUMPER_RIGHT): self.bumper_lines[idx+2].setVisible(True) else: self.bumper_lines[idx+2].setVisible(False) if (bumper_state & BumperState.BUMPER_REAR): self.bumper_lines[idx+3].setVisible(True) else: self.bumper_lines[idx+3].setVisible(False) def resetGuiTimer(self): # del self.gui_update_timer self.gui_update_timer = QTimer(self._widget) self.gui_update_timer.setInterval(100) self.gui_update_timer.setSingleShot(False) self.gui_update_timer.timeout.connect(lambda:self.updateGuiCallback()) self.gui_update_timer.start() def spawnFullGui(self): super(DiagnosticGui, self).__init__(self.context_) # Give QObjects reasonable names self.setObjectName('DiagnosticGui') # Create QWidget self._widget = QWidget() # Get path to UI file which should be in the "resource" folder of this package ui_file = os.path.join(rospkg.RosPack().get_path('mobility_base_tools'), 'resource', 'DiagnosticGui.ui') # Extend the widget with all attributes and children from UI file loadUi(ui_file, self._widget) # Give QObjects reasonable names self._widget.setObjectName('DiagnosticGui' + str(self.widget_count)) self.widget_count += 1 # Add widget to the user interface self.context_.add_widget(self._widget) def spawnTabGui(self): super(DiagnosticGui, self).__init__(self.context_) # Give QObjects reasonable names self.setObjectName('DiagnosticGui') # Create QWidget self._widget = QWidget() # Get path to UI file which should be in the "resource" folder of this package ui_file = os.path.join(rospkg.RosPack().get_path('mobility_base_tools'), 'resource', 'DiagnosticGuiTabs.ui') # Extend the widget with all attributes and children from UI file loadUi(ui_file, self._widget) # Give QObjects reasonable names self._widget.setObjectName('DiagnosticGui' + str(self.widget_count)) self.widget_count += 1 # Add widget to the user interface self.context_.add_widget(self._widget) def updateRightStickIndicator(self, lat_val, forward_val): horiz_val = -self.stick_ind_range_factor * (lat_val - self.stick_ind_range_mid) vert_val = -self.stick_ind_range_factor * (forward_val - self.stick_ind_range_mid) r = sqrt(horiz_val * horiz_val + vert_val * vert_val) if r > self.stick_ind_range_pix / 2: r = self.stick_ind_range_pix / 2 ang = atan2(vert_val, horiz_val) px = r * cos(ang) py = r * sin(ang) self.stick_ind_r.setPos(QPoint(px, py)) self.stick_line_r.setLine(self.stick_ind_rox, self.stick_ind_roy, self.stick_ind_rox + px, self.stick_ind_roy + py) def updateLeftStickIndicator(self, yaw_val, enable_val): horiz_val = -self.stick_ind_range_factor * (yaw_val - self.stick_ind_range_mid) vert_val = -self.stick_ind_range_factor * (enable_val - self.stick_ind_range_mid) r = sqrt(horiz_val * horiz_val + vert_val * vert_val) if r > self.stick_ind_range_pix / 2: r = self.stick_ind_range_pix / 2 ang = atan2(vert_val, horiz_val) px = r * cos(ang) py = r * sin(ang) self.stick_ind_l.setPos(QPoint(px, py)) self.stick_line_l.setLine(self.stick_ind_lox, self.stick_ind_loy, self.stick_ind_lox + px, self.stick_ind_loy + py) def shutdown_plugin(self): pass
class MyBlockingBusy(QDialog): # {{{ do_one_signal = pyqtSignal() phases = ['', _('Title/Author'), _('Standard metadata'), _('Custom metadata'), _('Search/Replace'), ] def __init__(self, msg, args, db, ids, cc_widgets, s_r_func, parent=None, window_title=_('Working')): QDialog.__init__(self, parent) self._layout = QVBoxLayout() self.setLayout(self._layout) self.msg_text = msg self.msg = QLabel(msg+' ') # Ensure dialog is wide enough #self.msg.setWordWrap(True) self.font = QFont() self.font.setPointSize(self.font.pointSize() + 8) self.msg.setFont(self.font) self.pi = ProgressIndicator(self) self.pi.setDisplaySize(100) self._layout.addWidget(self.pi, 0, Qt.AlignHCenter) self._layout.addSpacing(15) self._layout.addWidget(self.msg, 0, Qt.AlignHCenter) self.setWindowTitle(window_title) self.resize(self.sizeHint()) self.start() self.args = args self.series_start_value = None self.db = db self.ids = ids self.error = None self.cc_widgets = cc_widgets self.s_r_func = s_r_func self.do_one_signal.connect(self.do_one_safe, Qt.QueuedConnection) def start(self): self.pi.startAnimation() def stop(self): self.pi.stopAnimation() def accept(self): self.stop() return QDialog.accept(self) def exec_(self): self.current_index = 0 self.current_phase = 1 self.do_one_signal.emit() return QDialog.exec_(self) def do_one_safe(self): try: if self.current_index >= len(self.ids): self.current_phase += 1 self.current_index = 0 if self.current_phase > 4: self.db.commit() return self.accept() id = self.ids[self.current_index] percent = int((self.current_index*100)/float(len(self.ids))) self.msg.setText(self.msg_text.format(self.phases[self.current_phase], percent)) self.do_one(id) except Exception as err: import traceback try: err = unicode(err) except: err = repr(err) self.error = (err, traceback.format_exc()) return self.accept() def do_one(self, id): remove_all, remove, add, au, aus, do_aus, rating, pub, do_series, \ do_autonumber, do_remove_format, remove_format, do_swap_ta, \ do_remove_conv, do_auto_author, series, do_series_restart, \ series_start_value, do_title_case, cover_action, clear_series, \ pubdate, adddate, do_title_sort, languages, clear_languages, \ restore_original = self.args # first loop: All changes that modify the filesystem and commit # immediately. We want to # try hard to keep the DB and the file system in sync, even in the face # of exceptions or forced exits. if self.current_phase == 1: title_set = False if do_swap_ta: title = self.db.title(id, index_is_id=True) aum = self.db.authors(id, index_is_id=True) if aum: aum = [a.strip().replace('|', ',') for a in aum.split(',')] new_title = authors_to_string(aum) if do_title_case: new_title = titlecase(new_title) self.db.set_title(id, new_title, notify=False) title_set = True if title: new_authors = string_to_authors(title) self.db.set_authors(id, new_authors, notify=False) if do_title_case and not title_set: title = self.db.title(id, index_is_id=True) self.db.set_title(id, titlecase(title), notify=False) if do_title_sort: title = self.db.title(id, index_is_id=True) if languages: lang = languages[0] else: lang = self.db.languages(id, index_is_id=True) if lang: lang = lang.partition(',')[0] self.db.set_title_sort(id, title_sort(title, lang=lang), notify=False) if au: self.db.set_authors(id, string_to_authors(au), notify=False) if cover_action == 'remove': self.db.remove_cover(id) elif cover_action == 'generate': from calibre.ebooks import calibre_cover from calibre.ebooks.metadata import fmt_sidx from calibre.gui2 import config mi = self.db.get_metadata(id, index_is_id=True) series_string = None if mi.series: series_string = _('Book %(sidx)s of %(series)s')%dict( sidx=fmt_sidx(mi.series_index, use_roman=config['use_roman_numerals_for_series_number']), series=mi.series) cdata = calibre_cover(mi.title, mi.format_field('authors')[-1], series_string=series_string) self.db.set_cover(id, cdata) elif cover_action == 'fromfmt': fmts = self.db.formats(id, index_is_id=True, verify_formats=False) if fmts: covers = [] for fmt in fmts.split(','): fmtf = self.db.format(id, fmt, index_is_id=True, as_file=True) if fmtf is None: continue cdata, area = get_cover_data(fmtf, fmt) if cdata: covers.append((cdata, area)) covers.sort(key=lambda x: x[1]) if covers: self.db.set_cover(id, covers[-1][0]) covers = [] if do_remove_format: self.db.remove_format(id, remove_format, index_is_id=True, notify=False, commit=True) if restore_original: formats = self.db.formats(id, index_is_id=True) formats = formats.split(',') if formats else [] originals = [x.upper() for x in formats if x.upper().startswith('ORIGINAL_')] for ofmt in originals: fmt = ofmt.replace('ORIGINAL_', '') with SpooledTemporaryFile(SPOOL_SIZE) as stream: self.db.copy_format_to(id, ofmt, stream, index_is_id=True) stream.seek(0) self.db.add_format(id, fmt, stream, index_is_id=True, notify=False) self.db.remove_format(id, ofmt, index_is_id=True, notify=False, commit=True) elif self.current_phase == 2: # All of these just affect the DB, so we can tolerate a total rollback if do_auto_author: x = self.db.author_sort_from_book(id, index_is_id=True) if x: self.db.set_author_sort(id, x, notify=False, commit=False) if aus and do_aus: self.db.set_author_sort(id, aus, notify=False, commit=False) if rating != -1: self.db.set_rating(id, 2*rating, notify=False, commit=False) if pub: self.db.set_publisher(id, pub, notify=False, commit=False) if clear_series: self.db.set_series(id, '', notify=False, commit=False) if pubdate is not None: self.db.set_pubdate(id, pubdate, notify=False, commit=False) if adddate is not None: self.db.set_timestamp(id, adddate, notify=False, commit=False) if do_series: if do_series_restart: if self.series_start_value is None: self.series_start_value = series_start_value next = self.series_start_value self.series_start_value += 1 else: next = self.db.get_next_series_num_for(series) self.db.set_series(id, series, notify=False, commit=False) if not series: self.db.set_series_index(id, 1.0, notify=False, commit=False) elif do_autonumber: # is True if do_series_restart is True self.db.set_series_index(id, next, notify=False, commit=False) elif tweaks['series_index_auto_increment'] != 'no_change': self.db.set_series_index(id, 1.0, notify=False, commit=False) if do_remove_conv: self.db.delete_conversion_options(id, 'PIPE', commit=False) if clear_languages: self.db.set_languages(id, [], notify=False, commit=False) elif languages: self.db.set_languages(id, languages, notify=False, commit=False) elif self.current_phase == 3: # both of these are fast enough to just do them all for w in self.cc_widgets: w.commit(self.ids) if remove_all: self.db.remove_all_tags(self.ids) self.db.bulk_modify_tags(self.ids, add=add, remove=remove, notify=False) self.current_index = len(self.ids) elif self.current_phase == 4: self.s_r_func(id) # do the next one self.current_index += 1 self.do_one_signal.emit()
def set_element_name_in_row(self, row, col, name): rule_name = QLabel(" %s " % name) rule_name.setFont(self.FONT) self.setCellWidget(row, col, rule_name)
def initUI(self): # Set central widget centralWidget = QWidget() self.setCentralWidget(centralWidget) # Load LCD fonts lcdNumbersFontID = QFontDatabase().addApplicationFont("lcdmn.ttf") #fontNames = QFontDatabase().applicationFontFamilies(lcdNumbersFontID) # Change font size and use italic for strings #self.lcdNumbersFont = QFont(fontNames[0]) self.lcdNumbersFont = QFont() self.lcdNumbersFont.setPointSize(40) #self.lcdStringFont = QFont(fontNames[0]) self.lcdStringFont = QFont() self.lcdStringFont.setPointSize(35) self.lcdStringFont.setItalic(True) # self.lcdBoldFont = QFont(fontNames[0]) self.lcdBoldFont = QFont() self.lcdBoldFont.setPointSize(50) self.lcdBoldFont.setBold(True) # Labels dataLabel = QLabel("DATA") dataLabel.setStyleSheet(""" QLabel {color:red} """) energyLabel = QLabel("ENERGY") energyLabel.setStyleSheet(""" QLabel {color:red} """) powerLabel = QLabel("POWER") powerLabel.setStyleSheet(""" QLabel {color:red} """) dataLabel.setFont(self.lcdBoldFont) powerLabel.setFont(self.lcdBoldFont) energyLabel.setFont(self.lcdBoldFont) self.voltageLabel = QLabel("0.00") self.voltageLabel.setFont(self.lcdNumbersFont) self.voltageString = QLabel("V") self.voltageString.setFont(self.lcdStringFont) self.currentLabel = QLabel("0.00") self.currentLabel.setFont(self.lcdNumbersFont) self.currentString = QLabel("A") self.currentString.setFont(self.lcdStringFont) self.frequencyLabel = QLabel("0.00") self.frequencyLabel.setFont(self.lcdNumbersFont) self.frequencyString = QLabel("Hz") self.frequencyString.setFont(self.lcdStringFont) self.activeEnergyLabel = QLabel("0.00") self.activeEnergyLabel.setFont(self.lcdNumbersFont) self.activeEnergyString = QLabel("Wh") self.activeEnergyString.setFont(self.lcdStringFont) self.apparentEnergyLabel = QLabel("0.00") self.apparentEnergyLabel.setFont(self.lcdNumbersFont) self.apparentEnergyString = QLabel("VAh") self.apparentEnergyString.setFont(self.lcdStringFont) self.reactiveEnergyLabel = QLabel("0.00") self.reactiveEnergyLabel.setFont(self.lcdNumbersFont) self.reactiveEnergyString = QLabel("VARh") self.reactiveEnergyString.setFont(self.lcdStringFont) self.activePowerLabel = QLabel("0.00") self.activePowerLabel.setFont(self.lcdNumbersFont) self.activePowerString = QLabel("W") self.activePowerString.setFont(self.lcdStringFont) self.apparentPowerLabel = QLabel("0.00") self.apparentPowerLabel.setFont(self.lcdNumbersFont) self.apparentPowerString = QLabel("VA") self.apparentPowerString.setFont(self.lcdStringFont) self.reactivePowerLabel = QLabel("0.00") self.reactivePowerLabel.setFont(self.lcdNumbersFont) self.reactivePowerString = QLabel("VAR") self.reactivePowerString.setFont(self.lcdStringFont) # Horizontal lines hline1 = self.HLine() hline2 = self.HLine() hline3 = self.HLine() hline4 = self.HLine() # Vertical lines vline1 = self.VLine() vline2 = self.VLine() vline3 = self.VLine() # Central grid layout for central widget self.centralGridLayout = QGridLayout(self.centralWidget()) self.centralGridLayout.setHorizontalSpacing(20) self.centralGridLayout.setVerticalSpacing(5) # Add labels self.centralGridLayout.addWidget(dataLabel,0,0,1,2, QtCore.Qt.AlignCenter) self.centralGridLayout.addWidget(energyLabel,0,3,1,2, QtCore.Qt.AlignCenter) self.centralGridLayout.addWidget(powerLabel,0,6,1,2, QtCore.Qt.AlignCenter) self.centralGridLayout.addWidget(hline1, 1, 0, 1, -1) self.centralGridLayout.addWidget(self.voltageLabel, 2, 0, 1, 1, QtCore.Qt.AlignLeft) self.centralGridLayout.addWidget(self.voltageString, 2, 1, 1, 1, QtCore.Qt.AlignLeft) self.centralGridLayout.addWidget(hline2, 3, 0, 1, -1) self.centralGridLayout.addWidget(self.currentLabel, 4, 0, 1, 1, QtCore.Qt.AlignLeft) self.centralGridLayout.addWidget(self.currentString, 4, 1, 1, 1, QtCore.Qt.AlignLeft) self.centralGridLayout.addWidget(hline3, 5, 0, 1, -1) self.centralGridLayout.addWidget(self.frequencyLabel, 6, 0, 1, 1, QtCore.Qt.AlignLeft) self.centralGridLayout.addWidget(self.frequencyString, 6, 1, 1, 1, QtCore.Qt.AlignLeft) self.centralGridLayout.addWidget(hline4, 7, 0, 1, -1) self.centralGridLayout.addWidget(vline1, 0, 2, -1, 1) self.centralGridLayout.addWidget(self.activeEnergyLabel, 2, 3, 1, 1, QtCore.Qt.AlignLeft) self.centralGridLayout.addWidget(self.activeEnergyString, 2, 4, 1, 1, QtCore.Qt.AlignLeft) self.centralGridLayout.addWidget(self.apparentEnergyLabel, 4, 3, 1, 1, QtCore.Qt.AlignLeft) self.centralGridLayout.addWidget(self.apparentEnergyString, 4, 4, 1, 1, QtCore.Qt.AlignLeft) self.centralGridLayout.addWidget(self.reactiveEnergyLabel, 6, 3, 1, 1, QtCore.Qt.AlignLeft) self.centralGridLayout.addWidget(self.reactiveEnergyString, 6, 4, 1, 1, QtCore.Qt.AlignLeft) self.centralGridLayout.addWidget(vline2, 0, 5, -1, 1) self.centralGridLayout.addWidget(self.activePowerLabel, 2, 6, 1, 1, QtCore.Qt.AlignLeft) self.centralGridLayout.addWidget(self.activePowerString, 2, 7, 1, 1, QtCore.Qt.AlignLeft) self.centralGridLayout.addWidget(self.apparentPowerLabel, 4, 6, 1, 1, QtCore.Qt.AlignLeft) self.centralGridLayout.addWidget(self.apparentPowerString, 4, 7, 1, 1, QtCore.Qt.AlignLeft) self.centralGridLayout.addWidget(self.reactivePowerLabel, 6, 6, 1, 1, QtCore.Qt.AlignLeft) self.centralGridLayout.addWidget(self.reactivePowerString, 6, 7, 1, 1, QtCore.Qt.AlignLeft) # self.centralGridLayout.addWidget(vline3, 0, 8, -1, 1) # Buttons self.startStopButton = QPushButton("START") self.startStopButton.setFont(self.lcdStringFont) buttonPolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.startStopButton.setSizePolicy(buttonPolicy) self.startStopButton.clicked.connect(self.startStopClicked) self.resetButton = QPushButton("RESET") self.resetButton.setFont(self.lcdStringFont) self.resetButton.setSizePolicy(buttonPolicy) self.resetButton.clicked.connect(self.resetButtonClicked) self.broadcastButton = QPushButton("BROADCAST") self.broadcastButton.setFont(self.lcdStringFont) self.broadcastButton.setSizePolicy(buttonPolicy) self.broadcastButton.setCheckable(True) self.broadcastButton.toggled.connect(self.broadcastButtonClicked) self.centralGridLayout.addWidget(self.startStopButton, 8, 0, 1, 2) self.centralGridLayout.addWidget(self.resetButton, 8, 3, 1, 2) self.centralGridLayout.addWidget(self.broadcastButton, 8, 6, 1, 2) # Status bar and show window self.statusBar().showMessage('Ready') self.setWindowTitle("ADE7753 Power Meter") self.show()
class StatusBar(QStatusBar): # {{{ def __init__(self, parent=None): QStatusBar.__init__(self, parent) self.base_msg = '%s %s' % (__appname__, get_version()) self.version = get_version() self.device_string = '' self.update_label = UpdateLabel('') self.total = self.current = self.selected = self.library_total = 0 self.addPermanentWidget(self.update_label) self.update_label.setVisible(False) self._font = QFont() self._font.setBold(True) self.setFont(self._font) self.defmsg = QLabel('') self.defmsg.setFont(self._font) self.addWidget(self.defmsg) self.set_label() def initialize(self, systray=None): self.systray = systray self.notifier = get_notifier(systray) def device_connected(self, devname): self.device_string = _('Connected ') + devname self.set_label() def update_state(self, library_total, total, current, selected): self.library_total = library_total self.total, self.current, self.selected = total, current, selected self.set_label() def set_label(self): try: self._set_label() except: import traceback traceback.print_exc() def _set_label(self): msg = self.base_msg if self.device_string: msg += ' ..::.. ' + self.device_string else: msg += _(' %(created)s %(name)s') % dict(created=_('created by'), name='Kovid Goyal') if self.total != self.current: base = _('%(num)d of %(total)d books') % dict(num=self.current, total=self.total) else: base = _('%d books') % self.total if self.selected > 0: base = _('%(num)s, %(sel)d selected') % dict(num=base, sel=self.selected) if self.library_total != self.total: base = _('{0}, {1} total').format(base, self.library_total) self.defmsg.setText('%s [%s]' % (msg, base)) self.clearMessage() def device_disconnected(self): self.device_string = '' self.set_label() def show_message(self, msg, timeout=0): self.showMessage(msg, timeout) if self.notifier is not None and not config['disable_tray_notification']: if isosx and isinstance(msg, unicode): try: msg = msg.encode(preferred_encoding) except UnicodeEncodeError: msg = msg.encode('utf-8') self.notifier(msg) def clear_message(self): self.clearMessage()
class MyBlockingBusy(QDialog): NORMAL = 0 REQUESTED = 1 ACKNOWLEDGED = 2 def __init__(self, gui, msg, size=100, window_title="Marvin XD", show_cancel=False, on_top=False): flags = Qt.FramelessWindowHint if on_top: flags = Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint QDialog.__init__(self, gui, flags) self._layout = QVBoxLayout() self.setLayout(self._layout) self.cancel_status = 0 self.is_running = False # Add the spinner self.pi = ProgressIndicator(self) self.pi.setDisplaySize(size) self._layout.addSpacing(15) self._layout.addWidget(self.pi, 0, Qt.AlignHCenter) self._layout.addSpacing(15) # Fiddle with the message self.msg = QLabel(msg) # self.msg.setWordWrap(True) self.font = QFont() self.font.setPointSize(self.font.pointSize() + 2) self.msg.setFont(self.font) self._layout.addWidget(self.msg, 0, Qt.AlignHCenter) sp = QSizePolicy() sp.setHorizontalStretch(True) sp.setVerticalStretch(False) sp.setHeightForWidth(False) self.msg.setSizePolicy(sp) self.msg.setMinimumHeight(self.font.pointSize() + 8) self._layout.addSpacing(15) if show_cancel: self.bb = QDialogButtonBox() self.cancel_button = QPushButton(QIcon(I("window-close.png")), "Cancel") self.bb.addButton(self.cancel_button, self.bb.RejectRole) self.bb.clicked.connect(self.button_handler) self._layout.addWidget(self.bb) self.setWindowTitle(window_title) self.resize(self.sizeHint()) def accept(self): self.stop() return QDialog.accept(self) def button_handler(self, button): """ Only change cancel_status from NORMAL to REQUESTED """ if self.bb.buttonRole(button) == QDialogButtonBox.RejectRole: if self.cancel_status == self.NORMAL: self.cancel_status = self.REQUESTED self.cancel_button.setEnabled(False) def reject(self): """ Cannot cancel this dialog manually """ pass def set_text(self, text): self.msg.setText(text) def start(self): self.is_running = True self.pi.startAnimation() def stop(self): self.is_running = False self.pi.stopAnimation()
class PM_Dialog(QDialog, SponsorableMixin): """ The PM_Dialog class is the base class for Property Manager dialogs. [To make a PM class from this mixin-superclass, subclass it to customize the widget set and add behavior. You must also provide certain methods provided by GeneratorBaseClass (either by inheriting it -- not sure if superclass order matters for that -- or by defining them yourself), including ok_btn_clicked and several others, including at least some defined by SponsorableMixin (open_sponsor_homepage, setSponsor). This set of requirements may be cleaned up.] [Note: Technically, this is not a "base class" but a "mixin class".] """ headerTitleText = "" # The header title text. _widgetList = [] # A list of all group boxes in this PM dialog, # including the message group box. # (but not header, sponsor button, etc.) _groupBoxCount = 0 # Number of PM_GroupBoxes in this PM dialog. _lastGroupBox = None # The last PM_GroupBox in this PM dialog. # (i.e. the most recent PM_GroupBox added). def __init__(self, name, iconPath="", title=""): """ Property Manager constructor. @param name: the name to assign the property manager dialog object. @type name: str @param iconPath: the relative path for the icon (PNG image) that appears in the header. @type iconPath: str @param title: the title that appears in the header. @type title: str """ QDialog.__init__(self) self.setObjectName(name) self._widgetList = [] # Main pallete for PropMgr. self.setPalette(QPalette(pmColor)) # Main vertical layout for PropMgr. self.vBoxLayout = QVBoxLayout(self) self.vBoxLayout.setMargin(PM_MAINVBOXLAYOUT_MARGIN) self.vBoxLayout.setSpacing(PM_MAINVBOXLAYOUT_SPACING) # Add PropMgr's header, sponsor button, top row buttons and (hidden) # message group box. self._createHeader(iconPath, title) self._createSponsorButton() self._createTopRowBtns() # Create top buttons row self.MessageGroupBox = PM_MessageGroupBox(self) # Keep the line below around; it might be useful. # I may want to use it now that I understand it. # Mark 2007-05-17. #QMetaObject.connectSlotsByName(self) self._addGroupBoxes() try: self._addWhatsThisText() except: print_compact_traceback("Error loading whatsthis text for this " \ "property manager.") try: self._addToolTipText() except: print_compact_traceback("Error loading tool tip text for this " \ "property manager.") def keyPressEvent(self, event): """ Handles keyPress event. NOTE: Subclasses should carefully override this. Note that the default implementation doesn't permit ESC key as a way to close the PM_dialog. (this is typically dsesirable for Property Managers) If any subclass need to implement the key press, they should first call this method(i.e. superclass.keyPressEvent) and then implement specific code that closed the dialog when ESC key is pressed. """ key = event.key() # Don't use ESC key to close the PM dialog. Fixes bug 2596 if key == Qt.Key_Escape: pass else: QDialog.keyPressEvent(self, event) return def _addGroupBoxes(self): """ Add various group boxes to this PM. Subclasses should override this method. """ pass def _addWhatsThisText(self): """ Add what's this text. Subclasses should override this method. """ pass def _addToolTipText(self): """ Add Tool tip text. Subclasses should override this method. """ pass def show(self): """ Shows the Property Manager. """ self.setSponsor() if not self.pw or self: self.pw = self.win.activePartWindow() self.pw.updatePropertyManagerTab(self) self.pw.pwProjectTabWidget.setCurrentIndex( self.pw.pwProjectTabWidget.indexOf(self)) # Show the default message whenever we open the Property Manager. self.MessageGroupBox.MessageTextEdit.restoreDefault() def open(self, pm): """ Closes the current property manager (if any) and opens the property manager I{pm}. @param pm: The property manager to open. @type pm: L{PM_Dialog} or QDialog (of legacy PMs) @attention: This method is a temporary workaround for "Insert > Plane". The current command should always be responsible for (re)opening its own PM via self.show(). @see: L{show()} """ if 1: commandSequencer = self.win.commandSequencer #bruce 071008 commandName = commandSequencer.currentCommand.commandName # that's an internal name, but this is just for a debug print print "PM_Dialog.open(): Reopening the PM for command:", commandName # The following line of code is buggy when you, for instance, exit a PM # and reopen the previous one. It sends the disconnect signal twice to # the PM that is just closed.So disabling this line -- Ninad 2007-12-04 ##self.close() # Just in case there is another PM open. self.pw = self.win.activePartWindow() self.pw.updatePropertyManagerTab(pm) try: pm.setSponsor() except: print """PM_Dialog.open(): pm has no attribute 'setSponsor()' ignoring.""" self.pw.pwProjectTabWidget.setCurrentIndex( self.pw.pwProjectTabWidget.indexOf(pm)) def close(self): """ Closes the Property Manager. """ if not self.pw: self.pw = self.win.activePartWindow() self.pw.pwProjectTabWidget.setCurrentIndex(0) ## try: [bruce 071018 moved this lower, since errmsg only covers attr] pmWidget = self.pw.propertyManagerScrollArea.widget() if debug_flags.atom_debug: #bruce 071018 "atom_debug fyi: %r is closing %r (can they differ?)" % \ (self, pmWidget) try: pmWidget.update_props_if_needed_before_closing except AttributeError: if 1 or debug_flags.atom_debug: msg1 = "Last PropMgr %r doesn't have method" % pmWidget msg2 = " update_props_if_needed_before_closing. That's" msg3 = " OK (for now, only implemented for Plane PM). " msg4 = "Ignoring Exception: " print_compact_traceback(msg1 + msg2 + msg3 + msg4) #bruce 071018: I'll define that method in PM_Dialog # so this message should become rare or nonexistent, # so I'll make it happen whether or not atom_debug. else: pmWidget.update_props_if_needed_before_closing() self.pw.pwProjectTabWidget.removeTab( self.pw.pwProjectTabWidget.indexOf( self.pw.propertyManagerScrollArea)) if self.pw.propertyManagerTab: self.pw.propertyManagerTab = None def update_props_if_needed_before_closing(self): # bruce 071018 default implem """ Subclasses can override this to update some cosmetic properties of their associated model objects before closing self (the Property Manager). """ pass def updateMessage(self, msg=''): """ Updates the message box with an informative message @param msg: Message to be displayed in the Message groupbox of the property manager @type msg: string """ self.MessageGroupBox.insertHtmlMessage(msg, setAsDefault=False, minLines=5) def _createHeader(self, iconPath, title): """ Creates the Property Manager header, which contains an icon (a QLabel with a pixmap) and white text (a QLabel with text). @param iconPath: The relative path for the icon (PNG image) that appears in the header. @type iconPath: str @param title: The title that appears in the header. @type title: str """ # Heading frame (dark gray), which contains # a pixmap and (white) heading text. self.headerFrame = QFrame(self) self.headerFrame.setFrameShape(QFrame.NoFrame) self.headerFrame.setFrameShadow(QFrame.Plain) self.headerFrame.setPalette(QPalette(pmHeaderFrameColor)) self.headerFrame.setAutoFillBackground(True) # HBox layout for heading frame, containing the pixmap # and label (title). HeaderFrameHLayout = QHBoxLayout(self.headerFrame) # 2 pixels around edges -- HeaderFrameHLayout.setMargin(PM_HEADER_FRAME_MARGIN) # 5 pixel between pixmap and label. -- HeaderFrameHLayout.setSpacing(PM_HEADER_FRAME_SPACING) # PropMgr icon. Set image by calling setHeaderIcon(). self.headerIcon = QLabel(self.headerFrame) self.headerIcon.setSizePolicy( QSizePolicy(QSizePolicy.Policy(QSizePolicy.Fixed), QSizePolicy.Policy(QSizePolicy.Fixed))) self.headerIcon.setScaledContents(True) HeaderFrameHLayout.addWidget(self.headerIcon) # PropMgr header title text (a QLabel). self.headerTitle = QLabel(self.headerFrame) headerTitlePalette = self._getHeaderTitlePalette() self.headerTitle.setPalette(headerTitlePalette) self.headerTitle.setAlignment(PM_LABEL_LEFT_ALIGNMENT) # Assign header title font. self.headerTitle.setFont(self._getHeaderFont()) HeaderFrameHLayout.addWidget(self.headerTitle) self.vBoxLayout.addWidget(self.headerFrame) # Set header icon and title text. self.setHeaderIcon(iconPath) self.setHeaderTitle(title) def _getHeaderFont(self): """ Returns the font used for the header. @return: the header font @rtype: QFont """ font = QFont() font.setFamily(PM_HEADER_FONT) font.setPointSize(PM_HEADER_FONT_POINT_SIZE) font.setBold(PM_HEADER_FONT_BOLD) return font def setHeaderTitle(self, title): """ Set the Property Manager header title to string <title>. @param title: the title to insert in the header. @type title: str """ self.headerTitleText = title self.headerTitle.setText(title) def setHeaderIcon(self, iconPath): """ Set the Property Manager header icon. @param iconPath: the relative path to the PNG file containing the icon image. @type iconPath: str """ if not iconPath: return self.headerIcon.setPixmap(getpixmap(iconPath)) def _createSponsorButton(self): """ Creates the Property Manager sponsor button, which contains a QPushButton inside of a QGridLayout inside of a QFrame. The sponsor logo image is not loaded here. """ # Sponsor button (inside a frame) self.sponsor_frame = QFrame(self) self.sponsor_frame.setFrameShape(QFrame.NoFrame) self.sponsor_frame.setFrameShadow(QFrame.Plain) SponsorFrameGrid = QGridLayout(self.sponsor_frame) SponsorFrameGrid.setMargin(PM_SPONSOR_FRAME_MARGIN) SponsorFrameGrid.setSpacing(PM_SPONSOR_FRAME_SPACING) # Has no effect. self.sponsor_btn = QPushButton(self.sponsor_frame) self.sponsor_btn.setAutoDefault(False) self.sponsor_btn.setFlat(True) self.connect(self.sponsor_btn, SIGNAL("clicked()"), self.open_sponsor_homepage) SponsorFrameGrid.addWidget(self.sponsor_btn, 0, 0, 1, 1) self.vBoxLayout.addWidget(self.sponsor_frame) button_whatsthis_widget = self.sponsor_btn #bruce 070615 bugfix -- put tooltip & whatsthis on self.sponsor_btn, # not self. # [self.sponsor_frame might be another possible place to put them.] button_whatsthis_widget.setWhatsThis("""<b>Sponsor Button</b> <p>When clicked, this sponsor logo will display a short description about a NanoEngineer-1 sponsor. This can be an official sponsor or credit given to a contributor that has helped code part or all of this command. A link is provided in the description to learn more about this sponsor.</p>""") button_whatsthis_widget.setToolTip("NanoEngineer-1 Sponsor Button") return def _createTopRowBtns(self): """ Creates the Done, Cancel, Preview, Restore Defaults and What's This buttons row at the top of the Property Manager. """ # Main "button group" widget (but it is not a QButtonGroup). self.pmTopRowBtns = QHBoxLayout() # This QHBoxLayout is (probably) not necessary. Try using just the frame # for the foundation. I think it should work. Mark 2007-05-30 # Horizontal spacer horizontalSpacer = QSpacerItem(1, 1, QSizePolicy.Expanding, QSizePolicy.Minimum) # Frame containing all the buttons. self.topRowBtnsFrame = QFrame() self.topRowBtnsFrame.setFrameShape(QFrame.NoFrame) self.topRowBtnsFrame.setFrameShadow(QFrame.Plain) # Create Hbox layout for main frame. topRowBtnsHLayout = QHBoxLayout(self.topRowBtnsFrame) topRowBtnsHLayout.setMargin(PM_TOPROWBUTTONS_MARGIN) topRowBtnsHLayout.setSpacing(PM_TOPROWBUTTONS_SPACING) topRowBtnsHLayout.addItem(horizontalSpacer) # Set button type. if 1: # Mark 2007-05-30 # Needs to be QToolButton for MacOS. Fine for Windows, too. buttonType = QToolButton # May want to use QToolButton.setAutoRaise(1) below. Mark 2007-05-29 else: buttonType = QPushButton # Do not use. # Done (OK) button. self.done_btn = buttonType(self.topRowBtnsFrame) self.done_btn.setIcon( geticon("ui/actions/Properties Manager/Done.png")) self.done_btn.setIconSize(QSize(22, 22)) self.connect(self.done_btn, SIGNAL("clicked()"), self.doneButtonClicked) self.done_btn.setToolTip("Done") topRowBtnsHLayout.addWidget(self.done_btn) # Cancel (Abort) button. self.cancel_btn = buttonType(self.topRowBtnsFrame) self.cancel_btn.setIcon( geticon("ui/actions/Properties Manager/Abort.png")) self.cancel_btn.setIconSize(QSize(22, 22)) self.connect(self.cancel_btn, SIGNAL("clicked()"), self.cancelButtonClicked) self.cancel_btn.setToolTip("Cancel") topRowBtnsHLayout.addWidget(self.cancel_btn) #@ abort_btn deprecated. We still need it because modes use it. self.abort_btn = self.cancel_btn # Restore Defaults button. self.restore_defaults_btn = buttonType(self.topRowBtnsFrame) self.restore_defaults_btn.setIcon( geticon("ui/actions/Properties Manager/Restore.png")) self.restore_defaults_btn.setIconSize(QSize(22, 22)) self.connect(self.restore_defaults_btn, SIGNAL("clicked()"), self.restoreDefaultsButtonClicked) self.restore_defaults_btn.setToolTip("Restore Defaults") topRowBtnsHLayout.addWidget(self.restore_defaults_btn) # Preview (glasses) button. self.preview_btn = buttonType(self.topRowBtnsFrame) self.preview_btn.setIcon( geticon("ui/actions/Properties Manager/Preview.png")) self.preview_btn.setIconSize(QSize(22, 22)) self.connect(self.preview_btn, SIGNAL("clicked()"), self.previewButtonClicked) self.preview_btn.setToolTip("Preview") topRowBtnsHLayout.addWidget(self.preview_btn) # What's This (?) button. self.whatsthis_btn = buttonType(self.topRowBtnsFrame) self.whatsthis_btn.setIcon( geticon("ui/actions/Properties Manager/WhatsThis.png")) self.whatsthis_btn.setIconSize(QSize(22, 22)) self.connect(self.whatsthis_btn, SIGNAL("clicked()"), self.whatsThisButtonClicked) self.whatsthis_btn.setToolTip("Enter \"What's This\" help mode") topRowBtnsHLayout.addWidget(self.whatsthis_btn) topRowBtnsHLayout.addItem(horizontalSpacer) # Create Button Row self.pmTopRowBtns.addWidget(self.topRowBtnsFrame) self.vBoxLayout.addLayout(self.pmTopRowBtns) # Add What's This for buttons. self.done_btn.setWhatsThis("""<b>Done</b> <p> <img source=\"ui/actions/Properties Manager/Done.png\"><br> Completes and/or exits the current command.</p>""") self.cancel_btn.setWhatsThis("""<b>Cancel</b> <p> <img source=\"ui/actions/Properties Manager/Abort.png\"><br> Cancels the current command.</p>""") self.restore_defaults_btn.setWhatsThis("""<b>Restore Defaults</b> <p><img source=\"ui/actions/Properties Manager/Restore.png\"><br> Restores the defaut values of the Property Manager.</p>""") self.preview_btn.setWhatsThis("""<b>Preview</b> <p> <img source=\"ui/actions/Properties Manager/Preview.png\"><br> Preview the structure based on current Property Manager settings. </p>""") self.whatsthis_btn.setWhatsThis("""<b>What's This</b> <p> <img source=\"ui/actions/Properties Manager/WhatsThis.png\"><br> This invokes \"What's This?\" help mode which is part of NanoEngineer-1's online help system, and provides users with information about the functionality and usage of a particular command button or widget. </p>""") return def hideTopRowButtons(self, pmButtonFlags=None): """ Hides one or more top row buttons using <pmButtonFlags>. Button flags not set will cause the button to be shown if currently hidden. @param pmButtonFlags: This enumerator describes the which buttons to hide, where: - PM_DONE_BUTTON = 1 - PM_CANCEL_BUTTON = 2 - PM_RESTORE_DEFAULTS_BUTTON = 4 - PM_PREVIEW_BUTTON = 8 - PM_WHATS_THIS_BUTTON = 16 - PM_ALL_BUTTONS = 31 @type pmButtonFlags: int """ if pmButtonFlags & PM_DONE_BUTTON: self.done_btn.hide() else: self.done_btn.show() if pmButtonFlags & PM_CANCEL_BUTTON: self.cancel_btn.hide() else: self.cancel_btn.show() if pmButtonFlags & PM_RESTORE_DEFAULTS_BUTTON: self.restore_defaults_btn.hide() else: self.restore_defaults_btn.show() if pmButtonFlags & PM_PREVIEW_BUTTON: self.preview_btn.hide() else: self.preview_btn.show() if pmButtonFlags & PM_WHATS_THIS_BUTTON: self.whatsthis_btn.hide() else: self.whatsthis_btn.show() def showTopRowButtons(self, pmButtonFlags=PM_ALL_BUTTONS): """ Shows one or more top row buttons using <pmButtonFlags>. Button flags not set will cause the button to be hidden if currently displayed. @param pmButtonFlags: this enumerator describes which buttons to display, where: - PM_DONE_BUTTON = 1 - PM_CANCEL_BUTTON = 2 - PM_RESTORE_DEFAULTS_BUTTON = 4 - PM_PREVIEW_BUTTON = 8 - PM_WHATS_THIS_BUTTON = 16 - PM_ALL_BUTTONS = 31 @type pmButtonFlags: int """ self.hideTopRowButtons(pmButtonFlags ^ PM_ALL_BUTTONS) def _getHeaderTitlePalette(self): """ Return a palette for header title (text) label. """ palette = QPalette() palette.setColor(QPalette.WindowText, pmHeaderTitleColor) return palette def doneButtonClicked(self): """ Slot for the What's This button. """ self.ok_btn_clicked() def cancelButtonClicked(self): """ Slot for the What's This button. """ self.cancel_btn_clicked() def restoreDefaultsButtonClicked(self): """ Slot for "Restore Defaults" button in the Property Manager. It is called each time the button is clicked. """ for widget in self._widgetList: if isinstance(widget, PM_GroupBox): widget.restoreDefault() def previewButtonClicked(self): """ Slot for the What's This button. """ self.preview_btn_clicked() def whatsThisButtonClicked(self): """ Slot for the What's This button. """ QWhatsThis.enterWhatsThisMode()
class IdentifyWidget(QWidget): # {{{ rejected = pyqtSignal() results_found = pyqtSignal() book_selected = pyqtSignal(object, object) def __init__(self, log, parent=None): QWidget.__init__(self, parent) self.log = log self.abort = Event() self.caches = {} self.l = l = QGridLayout() self.setLayout(l) names = ['<b>'+p.name+'</b>' for p in metadata_plugins(['identify']) if p.is_configured()] self.top = QLabel('<p>'+_('calibre is downloading metadata from: ') + ', '.join(names)) self.top.setWordWrap(True) l.addWidget(self.top, 0, 0) self.results_view = ResultsView(self) self.results_view.book_selected.connect(self.emit_book_selected) self.get_result = self.results_view.get_result l.addWidget(self.results_view, 1, 0) self.comments_view = Comments(self) l.addWidget(self.comments_view, 1, 1) self.results_view.show_details_signal.connect(self.comments_view.show_data) self.query = QLabel('download starting...') f = self.query.font() f.setPointSize(f.pointSize()-2) self.query.setFont(f) self.query.setWordWrap(True) l.addWidget(self.query, 2, 0, 1, 2) self.comments_view.show_data('<h2>'+_('Please wait')+ '<br><span id="dots">.</span></h2>'+ ''' <script type="text/javascript"> window.onload=function(){ var dotspan = document.getElementById('dots'); window.setInterval(function(){ if(dotspan.textContent == '............'){ dotspan.textContent = '.'; } else{ dotspan.textContent += '.'; } }, 400); } </script> ''') def emit_book_selected(self, book): self.book_selected.emit(book, self.caches) def start(self, title=None, authors=None, identifiers={}): self.log.clear() self.log('Starting download') parts = [] if title: parts.append('title:'+title) if authors: parts.append('authors:'+authors_to_string(authors)) if identifiers: x = ', '.join('%s:%s'%(k, v) for k, v in identifiers.iteritems()) parts.append(x) self.query.setText(_('Query: ')+'; '.join(parts)) self.log(unicode(self.query.text())) self.worker = IdentifyWorker(self.log, self.abort, title, authors, identifiers, self.caches) self.worker.start() QTimer.singleShot(50, self.update) def update(self): if self.worker.is_alive(): QTimer.singleShot(50, self.update) else: self.process_results() def process_results(self): if self.worker.error is not None: error_dialog(self, _('Download failed'), _('Failed to download metadata. Click ' 'Show Details to see details'), show=True, det_msg=self.worker.error) self.rejected.emit() return if not self.worker.results: log = ''.join(self.log.plain_text) error_dialog(self, _('No matches found'), '<p>' + _('Failed to find any books that ' 'match your search. Try making the search <b>less ' 'specific</b>. For example, use only the author\'s ' 'last name and a single distinctive word from ' 'the title.<p>To see the full log, click Show Details.'), show=True, det_msg=log) self.rejected.emit() return self.results_view.show_results(self.worker.results) self.results_found.emit() def cancel(self): self.abort.set()
class MainView(QMainWindow): # Signals startPressed = pyqtSignal(bool) resetPressed = pyqtSignal() broadcastPressed = pyqtSignal(bool) def __init__(self): super(MainView, self).__init__() self.initUI() # Private variables self._running = False # ADE7753 instance self.meter = ade.ADE7753() # Connect signals and slots self.startPressed.connect(self.meter.startStopSlot) self.resetPressed.connect(self.meter.resetSlot) self.broadcastPressed.connect(self.meter.broadcastSlot) self.meter.varData.connect(self.updateData) self.meter.varPower.connect(self.updatePower) self.meter.varEnergy.connect(self.updateEnergy) # Slots # Update Vrms, Irms and Frequency @pyqtSlot(float, float, float, float) def updateData(self, vrms, irms, frequency, period): vrms = '{:.2f}'.format(vrms) irms = '{:.3f}'.format(irms) frequency = '{:.2f}'.format(frequency) self.voltageLabel.setText(vrms) self.currentLabel.setText(irms) self.frequencyLabel.setText(frequency) # Update energy @pyqtSlot(float, float, float) def updateEnergy(self, activeEnergy, apparentEnergy, reactiveEnergy): activeEnergy = '{:.3f}'.format(activeEnergy) apparentEnergy = '{:.3f}'.format(apparentEnergy) reactiveEnergy = '{:.3f}'.format(reactiveEnergy) self.activeEnergyLabel.setText(activeEnergy) self.apparentEnergyLabel.setText(apparentEnergy) self.reactiveEnergyLabel.setText(reactiveEnergy) # Update power @pyqtSlot(float, float, float) def updatePower(self, activePower, apparentPower, reactivePower): activePower = '{:.3f}'.format(activePower) apparentPower = '{:.3f}'.format(apparentPower) reactivePower = '{:.3f}'.format(reactivePower) self.activePowerLabel.setText(activePower) self.apparentPowerLabel.setText(apparentPower) self.reactivePowerLabel.setText(reactivePower) def initUI(self): # Set central widget centralWidget = QWidget() self.setCentralWidget(centralWidget) # Load LCD fonts lcdNumbersFontID = QFontDatabase().addApplicationFont("lcdmn.ttf") #fontNames = QFontDatabase().applicationFontFamilies(lcdNumbersFontID) # Change font size and use italic for strings #self.lcdNumbersFont = QFont(fontNames[0]) self.lcdNumbersFont = QFont() self.lcdNumbersFont.setPointSize(40) #self.lcdStringFont = QFont(fontNames[0]) self.lcdStringFont = QFont() self.lcdStringFont.setPointSize(35) self.lcdStringFont.setItalic(True) # self.lcdBoldFont = QFont(fontNames[0]) self.lcdBoldFont = QFont() self.lcdBoldFont.setPointSize(50) self.lcdBoldFont.setBold(True) # Labels dataLabel = QLabel("DATA") dataLabel.setStyleSheet(""" QLabel {color:red} """) energyLabel = QLabel("ENERGY") energyLabel.setStyleSheet(""" QLabel {color:red} """) powerLabel = QLabel("POWER") powerLabel.setStyleSheet(""" QLabel {color:red} """) dataLabel.setFont(self.lcdBoldFont) powerLabel.setFont(self.lcdBoldFont) energyLabel.setFont(self.lcdBoldFont) self.voltageLabel = QLabel("0.00") self.voltageLabel.setFont(self.lcdNumbersFont) self.voltageString = QLabel("V") self.voltageString.setFont(self.lcdStringFont) self.currentLabel = QLabel("0.00") self.currentLabel.setFont(self.lcdNumbersFont) self.currentString = QLabel("A") self.currentString.setFont(self.lcdStringFont) self.frequencyLabel = QLabel("0.00") self.frequencyLabel.setFont(self.lcdNumbersFont) self.frequencyString = QLabel("Hz") self.frequencyString.setFont(self.lcdStringFont) self.activeEnergyLabel = QLabel("0.00") self.activeEnergyLabel.setFont(self.lcdNumbersFont) self.activeEnergyString = QLabel("Wh") self.activeEnergyString.setFont(self.lcdStringFont) self.apparentEnergyLabel = QLabel("0.00") self.apparentEnergyLabel.setFont(self.lcdNumbersFont) self.apparentEnergyString = QLabel("VAh") self.apparentEnergyString.setFont(self.lcdStringFont) self.reactiveEnergyLabel = QLabel("0.00") self.reactiveEnergyLabel.setFont(self.lcdNumbersFont) self.reactiveEnergyString = QLabel("VARh") self.reactiveEnergyString.setFont(self.lcdStringFont) self.activePowerLabel = QLabel("0.00") self.activePowerLabel.setFont(self.lcdNumbersFont) self.activePowerString = QLabel("W") self.activePowerString.setFont(self.lcdStringFont) self.apparentPowerLabel = QLabel("0.00") self.apparentPowerLabel.setFont(self.lcdNumbersFont) self.apparentPowerString = QLabel("VA") self.apparentPowerString.setFont(self.lcdStringFont) self.reactivePowerLabel = QLabel("0.00") self.reactivePowerLabel.setFont(self.lcdNumbersFont) self.reactivePowerString = QLabel("VAR") self.reactivePowerString.setFont(self.lcdStringFont) # Horizontal lines hline1 = self.HLine() hline2 = self.HLine() hline3 = self.HLine() hline4 = self.HLine() # Vertical lines vline1 = self.VLine() vline2 = self.VLine() vline3 = self.VLine() # Central grid layout for central widget self.centralGridLayout = QGridLayout(self.centralWidget()) self.centralGridLayout.setHorizontalSpacing(20) self.centralGridLayout.setVerticalSpacing(5) # Add labels self.centralGridLayout.addWidget(dataLabel,0,0,1,2, QtCore.Qt.AlignCenter) self.centralGridLayout.addWidget(energyLabel,0,3,1,2, QtCore.Qt.AlignCenter) self.centralGridLayout.addWidget(powerLabel,0,6,1,2, QtCore.Qt.AlignCenter) self.centralGridLayout.addWidget(hline1, 1, 0, 1, -1) self.centralGridLayout.addWidget(self.voltageLabel, 2, 0, 1, 1, QtCore.Qt.AlignLeft) self.centralGridLayout.addWidget(self.voltageString, 2, 1, 1, 1, QtCore.Qt.AlignLeft) self.centralGridLayout.addWidget(hline2, 3, 0, 1, -1) self.centralGridLayout.addWidget(self.currentLabel, 4, 0, 1, 1, QtCore.Qt.AlignLeft) self.centralGridLayout.addWidget(self.currentString, 4, 1, 1, 1, QtCore.Qt.AlignLeft) self.centralGridLayout.addWidget(hline3, 5, 0, 1, -1) self.centralGridLayout.addWidget(self.frequencyLabel, 6, 0, 1, 1, QtCore.Qt.AlignLeft) self.centralGridLayout.addWidget(self.frequencyString, 6, 1, 1, 1, QtCore.Qt.AlignLeft) self.centralGridLayout.addWidget(hline4, 7, 0, 1, -1) self.centralGridLayout.addWidget(vline1, 0, 2, -1, 1) self.centralGridLayout.addWidget(self.activeEnergyLabel, 2, 3, 1, 1, QtCore.Qt.AlignLeft) self.centralGridLayout.addWidget(self.activeEnergyString, 2, 4, 1, 1, QtCore.Qt.AlignLeft) self.centralGridLayout.addWidget(self.apparentEnergyLabel, 4, 3, 1, 1, QtCore.Qt.AlignLeft) self.centralGridLayout.addWidget(self.apparentEnergyString, 4, 4, 1, 1, QtCore.Qt.AlignLeft) self.centralGridLayout.addWidget(self.reactiveEnergyLabel, 6, 3, 1, 1, QtCore.Qt.AlignLeft) self.centralGridLayout.addWidget(self.reactiveEnergyString, 6, 4, 1, 1, QtCore.Qt.AlignLeft) self.centralGridLayout.addWidget(vline2, 0, 5, -1, 1) self.centralGridLayout.addWidget(self.activePowerLabel, 2, 6, 1, 1, QtCore.Qt.AlignLeft) self.centralGridLayout.addWidget(self.activePowerString, 2, 7, 1, 1, QtCore.Qt.AlignLeft) self.centralGridLayout.addWidget(self.apparentPowerLabel, 4, 6, 1, 1, QtCore.Qt.AlignLeft) self.centralGridLayout.addWidget(self.apparentPowerString, 4, 7, 1, 1, QtCore.Qt.AlignLeft) self.centralGridLayout.addWidget(self.reactivePowerLabel, 6, 6, 1, 1, QtCore.Qt.AlignLeft) self.centralGridLayout.addWidget(self.reactivePowerString, 6, 7, 1, 1, QtCore.Qt.AlignLeft) # self.centralGridLayout.addWidget(vline3, 0, 8, -1, 1) # Buttons self.startStopButton = QPushButton("START") self.startStopButton.setFont(self.lcdStringFont) buttonPolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.startStopButton.setSizePolicy(buttonPolicy) self.startStopButton.clicked.connect(self.startStopClicked) self.resetButton = QPushButton("RESET") self.resetButton.setFont(self.lcdStringFont) self.resetButton.setSizePolicy(buttonPolicy) self.resetButton.clicked.connect(self.resetButtonClicked) self.broadcastButton = QPushButton("BROADCAST") self.broadcastButton.setFont(self.lcdStringFont) self.broadcastButton.setSizePolicy(buttonPolicy) self.broadcastButton.setCheckable(True) self.broadcastButton.toggled.connect(self.broadcastButtonClicked) self.centralGridLayout.addWidget(self.startStopButton, 8, 0, 1, 2) self.centralGridLayout.addWidget(self.resetButton, 8, 3, 1, 2) self.centralGridLayout.addWidget(self.broadcastButton, 8, 6, 1, 2) # Status bar and show window self.statusBar().showMessage('Ready') self.setWindowTitle("ADE7753 Power Meter") self.show() # Button slots def startStopClicked(self): if(self._running): self._running = False self.startStopButton.setText("START") self.startPressed.emit(False) else: self._running = True self.startStopButton.setText("STOP") self.startPressed.emit(True) def resetButtonClicked(self): self.resetPressed.emit() def broadcastButtonClicked(self, s): self.broadcastPressed.emit(s) # Helper functions def HLine(self): line = QFrame() line.setFrameStyle(QFrame.HLine) line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) return line def VLine(self): line = QFrame() line.setFrameStyle(QFrame.VLine) line.setFrameShape(QFrame.VLine) line.setFrameShadow(QFrame.Sunken) return line
class MyBlockingBusy(QDialog): NORMAL = 0 REQUESTED = 1 ACKNOWLEDGED = 2 def __init__(self, gui, msg, size=100, window_title='Marvin XD', show_cancel=False, on_top=False): flags = Qt.FramelessWindowHint if on_top: flags = Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint QDialog.__init__(self, gui, flags) self._layout = QVBoxLayout() self.setLayout(self._layout) self.cancel_status = 0 self.is_running = False # Add the spinner self.pi = ProgressIndicator(self) self.pi.setDisplaySize(size) self._layout.addSpacing(15) self._layout.addWidget(self.pi, 0, Qt.AlignHCenter) self._layout.addSpacing(15) # Fiddle with the message self.msg = QLabel(msg) #self.msg.setWordWrap(True) self.font = QFont() self.font.setPointSize(self.font.pointSize() + 2) self.msg.setFont(self.font) self._layout.addWidget(self.msg, 0, Qt.AlignHCenter) sp = QSizePolicy() sp.setHorizontalStretch(True) sp.setVerticalStretch(False) sp.setHeightForWidth(False) self.msg.setSizePolicy(sp) self.msg.setMinimumHeight(self.font.pointSize() + 8) self._layout.addSpacing(15) if show_cancel: self.bb = QDialogButtonBox() self.cancel_button = QPushButton(QIcon(I('window-close.png')), 'Cancel') self.bb.addButton(self.cancel_button, self.bb.RejectRole) self.bb.clicked.connect(self.button_handler) self._layout.addWidget(self.bb) self.setWindowTitle(window_title) self.resize(self.sizeHint()) def accept(self): self.stop() return QDialog.accept(self) def button_handler(self, button): ''' Only change cancel_status from NORMAL to REQUESTED ''' if self.bb.buttonRole(button) == QDialogButtonBox.RejectRole: if self.cancel_status == self.NORMAL: self.cancel_status = self.REQUESTED self.cancel_button.setEnabled(False) def reject(self): ''' Cannot cancel this dialog manually ''' pass def set_text(self, text): self.msg.setText(text) def start(self): self.is_running = True self.pi.startAnimation() def stop(self): self.is_running = False self.pi.stopAnimation()
class MyBlockingBusy(QDialog): # {{{ all_done = pyqtSignal() def __init__(self, args, ids, db, refresh_books, cc_widgets, s_r_func, do_sr, sr_calls, parent=None, window_title=_('Working')): QDialog.__init__(self, parent) self._layout = l = QVBoxLayout() self.setLayout(l) self.msg = QLabel(_('Processing %d books, please wait...') % len(ids)) self.font = QFont() self.font.setPointSize(self.font.pointSize() + 8) self.msg.setFont(self.font) self.pi = ProgressIndicator(self) self.pi.setDisplaySize(100) self._layout.addWidget(self.pi, 0, Qt.AlignHCenter) self._layout.addSpacing(15) self._layout.addWidget(self.msg, 0, Qt.AlignHCenter) self.setWindowTitle(window_title + '...') self.setMinimumWidth(200) self.resize(self.sizeHint()) self.error = None self.all_done.connect(self.on_all_done, type=Qt.QueuedConnection) self.args, self.ids = args, ids self.db, self.cc_widgets = db, cc_widgets self.s_r_func = FunctionDispatcher(s_r_func) self.do_sr = do_sr self.sr_calls = sr_calls self.refresh_books = refresh_books def accept(self): pass def reject(self): pass def on_all_done(self): if not self.error: # The cc widgets can only be accessed in the GUI thread try: for w in self.cc_widgets: w.commit(self.ids) except Exception as err: import traceback self.error = (err, traceback.format_exc()) self.pi.stopAnimation() QDialog.accept(self) def exec_(self): self.thread = Thread(target=self.do_it) self.thread.start() self.pi.startAnimation() return QDialog.exec_(self) def do_it(self): try: self.do_all() except Exception as err: import traceback try: err = unicode(err) except: err = repr(err) self.error = (err, traceback.format_exc()) self.all_done.emit() def do_all(self): cache = self.db.new_api args = self.args # Title and authors if args.do_swap_ta: title_map = cache.all_field_for('title', self.ids) authors_map = cache.all_field_for('authors', self.ids) def new_title(authors): ans = authors_to_string(authors) return titlecase(ans) if args.do_title_case else ans new_title_map = {bid:new_title(authors) for bid, authors in authors_map.iteritems()} new_authors_map = {bid:string_to_authors(title) for bid, title in title_map.iteritems()} cache.set_field('authors', new_authors_map) cache.set_field('title', new_title_map) if args.do_title_case and not args.do_swap_ta: title_map = cache.all_field_for('title', self.ids) cache.set_field('title', {bid:titlecase(title) for bid, title in title_map.iteritems()}) if args.do_title_sort: lang_map = cache.all_field_for('languages', self.ids) title_map = cache.all_field_for('title', self.ids) def get_sort(book_id): if args.languages: lang = args.languages[0] else: try: lang = lang_map[book_id][0] except (KeyError, IndexError, TypeError, AttributeError): lang = 'eng' return title_sort(title_map[book_id], lang=lang) cache.set_field('sort', {bid:get_sort(bid) for bid in self.ids}) if args.au: authors = string_to_authors(args.au) cache.set_field('authors', {bid:authors for bid in self.ids}) if args.do_auto_author: aus_map = cache.author_sort_strings_for_books(self.ids) cache.set_field('author_sort', {book_id:' & '.join(aus_map[book_id]) for book_id in aus_map}) if args.aus and args.do_aus: cache.set_field('author_sort', {bid:args.aus for bid in self.ids}) # Covers if args.cover_action == 'remove': cache.set_cover({bid:None for bid in self.ids}) elif args.cover_action == 'generate': from calibre.ebooks import calibre_cover from calibre.ebooks.metadata import fmt_sidx from calibre.gui2 import config for book_id in self.ids: mi = self.db.get_metadata(book_id, index_is_id=True) series_string = None if mi.series: series_string = _('Book %(sidx)s of %(series)s')%dict( sidx=fmt_sidx(mi.series_index, use_roman=config['use_roman_numerals_for_series_number']), series=mi.series) cdata = calibre_cover(mi.title, mi.format_field('authors')[-1], series_string=series_string) cache.set_cover({book_id:cdata}) elif args.cover_action == 'fromfmt': for book_id in self.ids: fmts = cache.formats(book_id, verify_formats=False) if fmts: covers = [] for fmt in fmts: fmtf = cache.format(book_id, fmt, as_file=True) if fmtf is None: continue cdata, area = get_cover_data(fmtf, fmt) if cdata: covers.append((cdata, area)) covers.sort(key=lambda x: x[1]) if covers: cache.set_cover({book_id:covers[-1][0]}) elif args.cover_action == 'trim': from calibre.utils.magick import Image for book_id in self.ids: cdata = cache.cover(book_id) if cdata: im = Image() im.load(cdata) im.trim(tweaks['cover_trim_fuzz_value']) cdata = im.export('jpg') cache.set_cover({book_id:cdata}) elif args.cover_action == 'clone': cdata = None for book_id in self.ids: cdata = cache.cover(book_id) if cdata: break if cdata: cache.set_cover({bid:cdata for bid in self.ids if bid != book_id}) # Formats if args.do_remove_format: cache.remove_formats({bid:(args.remove_format,) for bid in self.ids}) if args.restore_original: for book_id in self.ids: formats = cache.formats(book_id) originals = tuple(x.upper() for x in formats if x.upper().startswith('ORIGINAL_')) for ofmt in originals: cache.restore_original_format(book_id, ofmt) # Various fields if args.rating != -1: cache.set_field('rating', {bid:args.rating*2 for bid in self.ids}) if args.clear_pub: cache.set_field('publisher', {bid:'' for bid in self.ids}) if args.pub: cache.set_field('publisher', {bid:args.pub for bid in self.ids}) if args.clear_series: cache.set_field('series', {bid:'' for bid in self.ids}) if args.pubdate is not None: cache.set_field('pubdate', {bid:args.pubdate for bid in self.ids}) if args.adddate is not None: cache.set_field('timestamp', {bid:args.adddate for bid in self.ids}) if args.do_series: sval = args.series_start_value if args.do_series_restart else cache.get_next_series_num_for(args.series, current_indices=True) cache.set_field('series', {bid:args.series for bid in self.ids}) if not args.series: cache.set_field('series_index', {bid:1.0 for bid in self.ids}) else: def next_series_num(bid, i): if args.do_series_restart: return sval + i next_num = _get_next_series_num_for_list(sorted(sval.itervalues()), unwrap=False) sval[bid] = next_num return next_num smap = {bid:next_series_num(bid, i) for i, bid in enumerate(self.ids)} if args.do_autonumber: cache.set_field('series_index', smap) elif tweaks['series_index_auto_increment'] != 'no_change': cache.set_field('series_index', {bid:1.0 for bid in self.ids}) if args.comments is not null: cache.set_field('comments', {bid:args.comments for bid in self.ids}) if args.do_remove_conv: cache.delete_conversion_options(self.ids) if args.clear_languages: cache.set_field('languages', {bid:() for bid in self.ids}) elif args.languages: cache.set_field('languages', {bid:args.languages for bid in self.ids}) if args.remove_all: cache.set_field('tags', {bid:() for bid in self.ids}) if args.add or args.remove: self.db.bulk_modify_tags(self.ids, add=args.add, remove=args.remove) if self.do_sr: for book_id in self.ids: self.s_r_func(book_id) if self.sr_calls: for field, book_id_val_map in self.sr_calls.iteritems(): self.refresh_books.update(self.db.new_api.set_field(field, book_id_val_map))
class parameter_dialog_or_frame: """ use as a pre-mixin before QDialog or QFrame """ ####@@@@ def __init__(self, parent=None, desc=None, name=None, modal=0, fl=0, env=None, type="QDialog"): if env is None: import foundation.env as env # this is a little weird... probably it'll be ok, and logically it seems correct. self.desc = desc self.typ = type if type == "QDialog": QDialog.__init__(self, parent, name, modal, fl) elif type == "QTextEdit": QTextEdit.__init__(self, parent, name) elif type == "QFrame": QFrame.__init__(self, parent, name) else: print "don't know about type == %r" % (type, ) self.image1 = QPixmap() self.image1.loadFromData(image1_data, "PNG") # should be: title_icon #### self.image3 = QPixmap() self.image3.loadFromData(image3_data, "PNG") self.image4 = QPixmap() self.image4.loadFromData(image4_data, "PNG") self.image5 = QPixmap() self.image5.loadFromData(image5_data, "PNG") self.image6 = QPixmap() self.image6.loadFromData(image6_data, "PNG") self.image7 = QPixmap() self.image7.loadFromData(image7_data, "PNG") self.image0 = QPixmap(image0_data) # should be: border_icon #### self.image2 = QPixmap(image2_data) # should be: sponsor_pixmap #### try: ####@@@@ title_icon_name = self.desc.options.get('title_icon') border_icon_name = self.desc.options.get('border_icon') if title_icon_name: self.image1 = imagename_to_pixmap( title_icon_name) ###@@@ pass icon_path ###@@@ import imagename_to_pixmap or use env function # or let that func itself be an arg, or have an env arg for it ###e rename it icon_name_to_pixmap, or find_icon? (the latter only if it's ok if it returns an iconset) ###e use iconset instead? if border_icon_name: self.image0 = imagename_to_pixmap(border_icon_name) except: print_compact_traceback( "bug in icon-setting code, using fallback icons: ") pass if not name: self.setName("parameter_dialog_or_frame") ### ###k guess this will need: if type == 'QDialog' self.setIcon(self.image0) # should be: border_icon #### nanotube_dialogLayout = QVBoxLayout(self, 0, 0, "nanotube_dialogLayout") self.heading_frame = QFrame(self, "heading_frame") self.heading_frame.setPaletteBackgroundColor(QColor(122, 122, 122)) self.heading_frame.setFrameShape(QFrame.NoFrame) self.heading_frame.setFrameShadow(QFrame.Plain) heading_frameLayout = QHBoxLayout(self.heading_frame, 0, 3, "heading_frameLayout") self.heading_pixmap = QLabel(self.heading_frame, "heading_pixmap") self.heading_pixmap.setSizePolicy( QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed, 0, 0, self.heading_pixmap.sizePolicy().hasHeightForWidth())) self.heading_pixmap.setPixmap( self.image1) # should be: title_icon #### self.heading_pixmap.setScaledContents(1) heading_frameLayout.addWidget(self.heading_pixmap) self.heading_label = QLabel(self.heading_frame, "heading_label") self.heading_label.setPaletteForegroundColor(QColor(255, 255, 255)) heading_label_font = QFont(self.heading_label.font()) heading_label_font.setPointSize(12) heading_label_font.setBold(1) self.heading_label.setFont(heading_label_font) heading_frameLayout.addWidget(self.heading_label) nanotube_dialogLayout.addWidget(self.heading_frame) self.body_frame = QFrame(self, "body_frame") self.body_frame.setFrameShape(QFrame.StyledPanel) self.body_frame.setFrameShadow(QFrame.Raised) body_frameLayout = QVBoxLayout(self.body_frame, 3, 3, "body_frameLayout") self.sponsor_frame = QFrame(self.body_frame, "sponsor_frame") self.sponsor_frame.setPaletteBackgroundColor(QColor(255, 255, 255)) self.sponsor_frame.setFrameShape(QFrame.StyledPanel) self.sponsor_frame.setFrameShadow(QFrame.Raised) sponsor_frameLayout = QHBoxLayout(self.sponsor_frame, 0, 0, "sponsor_frameLayout") self.sponsor_btn = QPushButton(self.sponsor_frame, "sponsor_btn") self.sponsor_btn.setAutoDefault(0) #bruce 060703 bugfix self.sponsor_btn.setSizePolicy( QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred, 0, 0, self.sponsor_btn.sizePolicy().hasHeightForWidth())) self.sponsor_btn.setPaletteBackgroundColor(QColor(255, 255, 255)) self.sponsor_btn.setPixmap( self.image2 ) # should be: sponsor_pixmap #### [also we'll need to support >1 sponsor] self.sponsor_btn.setFlat(1) sponsor_frameLayout.addWidget(self.sponsor_btn) body_frameLayout.addWidget(self.sponsor_frame) layout59 = QHBoxLayout(None, 0, 6, "layout59") left_spacer = QSpacerItem(20, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) layout59.addItem(left_spacer) self.done_btn = QToolButton(self.body_frame, "done_btn") self.done_btn.setIcon(QIcon(self.image3)) layout59.addWidget(self.done_btn) self.abort_btn = QToolButton(self.body_frame, "abort_btn") self.abort_btn.setIcon(QIcon(self.image4)) layout59.addWidget(self.abort_btn) self.preview_btn = QToolButton(self.body_frame, "preview_btn") self.preview_btn.setIcon(QIcon(self.image5)) layout59.addWidget(self.preview_btn) self.whatsthis_btn = QToolButton(self.body_frame, "whatsthis_btn") self.whatsthis_btn.setIcon(QIcon(self.image6)) layout59.addWidget(self.whatsthis_btn) right_spacer = QSpacerItem(20, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) layout59.addItem(right_spacer) body_frameLayout.addLayout(layout59) self.groups = [] self.param_getters = { } # map from param name to get-function (which gets current value out of its widget or controller) for group_desc in self.desc.kids('group'): # == start parameters_grpbox ### this will differ for Windows style header_refs = [ ] # keep python refcounted refs to all objects we make (at least the ones pyuic stored in self attrs) self.parameters_grpbox = QGroupBox(self.body_frame, "parameters_grpbox") self.parameters_grpbox.setFrameShape(QGroupBox.StyledPanel) self.parameters_grpbox.setFrameShadow(QGroupBox.Sunken) self.parameters_grpbox.setMargin(0) self.parameters_grpbox.setColumnLayout(0, Qt.Vertical) self.parameters_grpbox.layout().setSpacing(1) self.parameters_grpbox.layout().setMargin(4) parameters_grpboxLayout = QVBoxLayout( self.parameters_grpbox.layout()) parameters_grpboxLayout.setAlignment(Qt.AlignTop) layout20 = QHBoxLayout(None, 0, 6, "layout20") self.nt_parameters_grpbtn = QPushButton(self.parameters_grpbox, "nt_parameters_grpbtn") self.nt_parameters_grpbtn.setSizePolicy( QSizePolicy( QSizePolicy.Minimum, QSizePolicy.Fixed, 0, 0, self.nt_parameters_grpbtn.sizePolicy().hasHeightForWidth()) ) self.nt_parameters_grpbtn.setMaximumSize(QSize(16, 16)) self.nt_parameters_grpbtn.setAutoDefault(0) self.nt_parameters_grpbtn.setIcon(QIcon( self.image7)) ### not always right, but doesn't matter self.nt_parameters_grpbtn.setFlat(1) layout20.addWidget(self.nt_parameters_grpbtn) self.parameters_grpbox_label = QLabel(self.parameters_grpbox, "parameters_grpbox_label") self.parameters_grpbox_label.setSizePolicy( QSizePolicy( QSizePolicy.Preferred, QSizePolicy.Minimum, 0, 0, self.parameters_grpbox_label.sizePolicy(). hasHeightForWidth())) self.parameters_grpbox_label.setAlignment(QLabel.AlignVCenter) layout20.addWidget(self.parameters_grpbox_label) gbx_spacer1 = QSpacerItem(67, 16, QSizePolicy.Expanding, QSizePolicy.Minimum) layout20.addItem(gbx_spacer1) parameters_grpboxLayout.addLayout(layout20) nt_parameters_body_layout = QGridLayout( None, 1, 1, 0, 6, "nt_parameters_body_layout" ) ### what is 6 -- is it related to number of items??? # is it 6 in all the ones we got, but that could be a designer error so i better look it up sometime. # == start its kids # will use from above: self.parameters_grpbox, nt_parameters_body_layout nextrow = 0 # which row of the QGridLayout to start filling next (loop variable) hidethese = [ ] # set of objects to hide or show, when this group is closed or opened for param in group_desc.kids('parameter'): # param (a group subobj desc) is always a parameter, but we already plan to extend this beyond that, # so we redundantly test for this here. getter = None paramname = None # set these for use by uniform code at the end (e.g. for tooltips) editfield = None label = None if param.isa('parameter'): label = QLabel(self.parameters_grpbox, "members_label") label.setAlignment(QLabel.AlignVCenter | QLabel.AlignRight) nt_parameters_body_layout.addWidget(label, nextrow, 0) hidethese.append(label) thisrow = nextrow nextrow += 1 #e following should be known in a place that knows the input language, not here paramname = param.options.get('name') or ( param.args and param.args[0]) or "?" paramlabel = param.options.get( 'label' ) or paramname ##e wrong, label "" or none ought to be possible # QtGui.QApplication.translate(self.__class__.__name__, "xyz") label.setText( QtGui.QApplication.translate(self.__class__.__name__, paramlabel)) if param.isa('parameter', widget='combobox', type=('str', None)): self.members_combox = QComboBox( 0, self.parameters_grpbox, "members_combox") ###k what's 0? editfield = self.members_combox #### it probably needs a handler class, and then that could do this setup self.members_combox.clear() default = param.options.get( 'default', None) # None is not equal to any string thewidgetkid = param.kids( 'widget' )[-1] # kluge; need to think what the desc method for this should be for item in thewidgetkid.kids('item'): itemval = item.args[0] itemtext = itemval self.members_combox.insertItem( QtGui.QApplication.translate( self.__class__.__name__, itemtext)) #k __tr ok?? if itemval == default: #k or itemtext? pass ##k i find no setItem in our py code, so not sure yet what to do for this. nt_parameters_body_layout.addWidget( self.members_combox, thisrow, 1) hidethese.append(self.members_combox) getter = (lambda combobox=self.members_combox: str( combobox.currentText())) ##e due to __tr or non-str values, it might be better to use currentIndex and look it up in a table # (though whether __tr is good here might depend on what it's used for) elif param.isa('parameter', widget=('lineedit', None), type=('str', None)): # this covers explicit str|lineedit, and 3 default cases str, lineedit, neither. # (i.e. if you say parameter and nothing else, it's str lineedit by default.) self.length_linedit = QLineEdit(self.parameters_grpbox, "length_linedit") editfield = self.length_linedit nt_parameters_body_layout.addWidget( self.length_linedit, thisrow, 1) hidethese.append(self.length_linedit) default = str(param.options.get('default', "")) self.length_linedit.setText( QtGui.QApplication.translate(self.__class__.__name__, default)) # __tr ok? getter = (lambda lineedit=self.length_linedit: str( lineedit.text())) elif param.isa('parameter', widget=('lineedit', None), type='float'): self.length_linedit = QLineEdit(self.parameters_grpbox, "length_linedit") editfield = self.length_linedit nt_parameters_body_layout.addWidget( self.length_linedit, thisrow, 1) hidethese.append(self.length_linedit) controller = FloatLineeditController_Qt( self, param, self.length_linedit) header_refs.append(controller) getter = controller.get_value elif param.isa('parameter', widget = ('spinbox', None), type = 'int') or \ param.isa('parameter', widget = ('spinbox'), type = None): self.chirality_N_spinbox = QSpinBox( self.parameters_grpbox, "chirality_N_spinbox" ) # was chirality_m_spinbox, now chirality_N_spinbox editfield = self.chirality_N_spinbox ### seems like Qt defaults for min and max are 0,100 -- way too small a range! if param.options.has_key('min') or 1: self.chirality_N_spinbox.setMinimum( param.options.get('min', -999999999)) # was 0 if param.options.has_key('max') or 1: self.chirality_N_spinbox.setMaximum( param.options.get( 'max', +999999999)) # wasn't in egcode, but needed self.chirality_N_spinbox.setValue( param.options.get('default', 0)) # was 5 ##e note: i suspect this default 0 should come from something that knows this desc grammar. suffix = param.options.get('suffix', '') if suffix: self.chirality_N_spinbox.setSuffix( QtGui.QApplication.translate( self.__class__.__name__, suffix)) else: self.chirality_N_spinbox.setSuffix( QString.null) # probably not needed nt_parameters_body_layout.addWidget( self.chirality_N_spinbox, thisrow, 1) hidethese.append(self.chirality_N_spinbox) getter = self.chirality_N_spinbox.value # note: it also has .text, which includes suffix else: print "didn't match:", param ###e improve this # things done the same way for all kinds of param-editing widgets if 1: #bruce 060703 moved this down here, as bugfix # set tooltip (same one for editfield and label) tooltip = param.options.get('tooltip', '') ###e do it for more kinds of params; share the code somehow; do it in controller, or setup-aid? ###k QToolTip appropriateness; tooltip option might be entirely untested if tooltip and label: QToolTip.add( label, QtGui.QApplication.translate( self.__class__.__name__, tooltip)) if tooltip and editfield: QToolTip.add( editfield, QtGui.QApplication.translate( self.__class__.__name__, tooltip) ) ##k ok?? review once not all params have same-row labels. if getter and paramname and paramname != '?': self.param_getters[paramname] = getter ### also bind these params to actions... continue # next param header_refs.extend([ self.parameters_grpbox, self.nt_parameters_grpbtn, self.parameters_grpbox_label ]) # now create the logic/control object for the group group = CollapsibleGroupController_Qt(self, group_desc, header_refs, hidethese, self.nt_parameters_grpbtn) ### maybe ask env for the class to use for this? self.groups.append( group ) ### needed?? only for scanning the params, AFAIK -- oh, and to maintain a python refcount. # from languageChange: if 1: # i don't know if these are needed: self.parameters_grpbox.setTitle(QString.null) self.nt_parameters_grpbtn.setText(QString.null) self.parameters_grpbox_label.setText( QtGui.QApplication.translate( self.__class__.__name__, group_desc.args[0])) # was "Nanotube Parameters" ##e note that it's questionable in the syntax design for this property of a group (overall group label) # to be in that position (desc arg 0). # == end its kids parameters_grpboxLayout.addLayout(nt_parameters_body_layout) body_frameLayout.addWidget(self.parameters_grpbox) # == end parameters groupbox continue # next group nanotube_dialogLayout.addWidget(self.body_frame) spacer14 = QSpacerItem(20, 20, QSizePolicy.Minimum, QSizePolicy.Expanding) nanotube_dialogLayout.addItem(spacer14) layout42 = QHBoxLayout(None, 4, 6, "layout42") btm_spacer = QSpacerItem(59, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) layout42.addItem(btm_spacer) self.cancel_btn = QPushButton(self, "cancel_btn") self.cancel_btn.setAutoDefault(0) #bruce 060703 bugfix layout42.addWidget(self.cancel_btn) self.ok_btn = QPushButton(self, "ok_btn") self.ok_btn.setAutoDefault(0) #bruce 060703 bugfix layout42.addWidget(self.ok_btn) nanotube_dialogLayout.addLayout(layout42) self.languageChange() self.resize( QSize(246, 618).expandedTo(self.minimumSizeHint()) ) ### this size will need to be adjusted (guess -- it's only place overall size is set) qt4todo('self.clearWState(Qt.WState_Polished)') ## self.connect(self.nt_parameters_grpbtn,SIGNAL("clicked()"),self.toggle_nt_parameters_grpbtn) #### # new: for button, methodname in ( (self.sponsor_btn, 'do_sponsor_btn'), #e generalize to more than one sponsor button (self.done_btn, 'do_done_btn'), (self.abort_btn, 'do_abort_btn'), (self.preview_btn, 'do_preview_btn'), (self.whatsthis_btn, 'do_whatsthis_btn'), (self.cancel_btn, 'do_cancel_btn'), (self.ok_btn, 'do_ok_btn')): if hasattr(self, methodname): self.connect(button, SIGNAL("clicked()"), getattr(self, methodname)) return def languageChange(self): opts = self.desc.option_attrs self.setCaption( QtGui.QApplication.translate(self.__class__.__name__, opts.caption)) # was "Nanotube" self.heading_label.setText( QtGui.QApplication.translate(self.__class__.__name__, opts.title)) # was "Nanotube" self.sponsor_btn.setText(QString.null) self.done_btn.setText(QString.null) QToolTip.add( self.done_btn, QtGui.QApplication.translate(self.__class__.__name__, "Done")) self.abort_btn.setText(QString.null) QToolTip.add( self.abort_btn, QtGui.QApplication.translate(self.__class__.__name__, "Cancel")) self.preview_btn.setText(QString.null) QToolTip.add( self.preview_btn, QtGui.QApplication.translate(self.__class__.__name__, "Preview")) self.whatsthis_btn.setText(QString.null) QToolTip.add( self.whatsthis_btn, QtGui.QApplication.translate(self.__class__.__name__, "What's This Help")) ### move these up: ## if 0: ## self.parameters_grpbox.setTitle(QString.null) ## self.nt_parameters_grpbtn.setText(QString.null) ## self.parameters_grpbox_label.setText(QtGui.QApplication.translate(self.__class__.__name__, "Nanotube Parameters")) ## if 0: ## self.members_label.setText(QtGui.QApplication.translate(self.__class__.__name__, "Members :")) ## self.length_label.setText(QtGui.QApplication.translate(self.__class__.__name__, "Length :")) ## self.chirality_n_label.setText(QtGui.QApplication.translate(self.__class__.__name__, "Chirality (n) :")) ## self.members_combox.clear() ## self.members_combox.insertItem(QtGui.QApplication.translate(self.__class__.__name__, "C - C")) ## self.members_combox.insertItem(QtGui.QApplication.translate(self.__class__.__name__, "B - N")) ## self.length_linedit.setText(QtGui.QApplication.translate(self.__class__.__name__, "20.0 A")) ## self.chirality_N_spinbox.setSuffix(QString.null) self.cancel_btn.setText( QtGui.QApplication.translate(self.__class__.__name__, "Cancel")) self.ok_btn.setText( QtGui.QApplication.translate(self.__class__.__name__, "OK")) return pass # end of class parameter_dialog_or_frame -- maybe it should be renamed
class StatusBar(QStatusBar): # {{{ def __init__(self, parent=None): QStatusBar.__init__(self, parent) self.version = get_version() self.base_msg = "%s %s" % (__appname__, self.version) if tweaks.get("use_new_db", False): self.base_msg += " [newdb]" self.device_string = "" self.update_label = UpdateLabel("") self.total = self.current = self.selected = self.library_total = 0 self.addPermanentWidget(self.update_label) self.update_label.setVisible(False) self._font = QFont() self._font.setBold(True) self.setFont(self._font) self.defmsg = QLabel("") self.defmsg.setFont(self._font) self.addWidget(self.defmsg) self.set_label() def initialize(self, systray=None): self.systray = systray self.notifier = get_notifier(systray) def device_connected(self, devname): self.device_string = _("Connected ") + devname self.set_label() def update_state(self, library_total, total, current, selected): self.library_total = library_total self.total, self.current, self.selected = total, current, selected self.set_label() def set_label(self): try: self._set_label() except: import traceback traceback.print_exc() def _set_label(self): msg = self.base_msg if self.device_string: msg += " ..::.. " + self.device_string else: msg += _(" %(created)s %(name)s") % dict(created=_("created by"), name="Kovid Goyal") if self.total != self.current: base = _("%(num)d of %(total)d books") % dict(num=self.current, total=self.total) else: base = _("%d books") % self.total if self.selected > 0: base = _("%(num)s, %(sel)d selected") % dict(num=base, sel=self.selected) if self.library_total != self.total: base = _("{0}, {1} total").format(base, self.library_total) self.defmsg.setText(u"%s\xa0\xa0\xa0\xa0[%s]" % (msg, base)) self.clearMessage() def device_disconnected(self): self.device_string = "" self.set_label() def show_message(self, msg, timeout=0): self.showMessage(msg, timeout) if self.notifier is not None and not config["disable_tray_notification"]: if isosx and isinstance(msg, unicode): try: msg = msg.encode(preferred_encoding) except UnicodeEncodeError: msg = msg.encode("utf-8") self.notifier(msg) def clear_message(self): self.clearMessage()
class StatusBar(QStatusBar): # {{{ def __init__(self, parent=None): QStatusBar.__init__(self, parent) self.version = get_version() self.base_msg = '%s %s' % (__appname__, self.version) self.device_string = '' self.update_label = UpdateLabel('') self.total = self.current = self.selected = self.library_total = 0 self.addPermanentWidget(self.update_label) self.update_label.setVisible(False) self._font = QFont() self._font.setBold(True) self.setFont(self._font) self.defmsg = QLabel('') self.defmsg.setFont(self._font) self.addWidget(self.defmsg) self.set_label() def initialize(self, systray=None): self.systray = systray self.notifier = get_notifier(systray) def device_connected(self, devname): self.device_string = _('Connected ') + devname self.set_label() def update_state(self, library_total, total, current, selected): self.library_total = library_total self.total, self.current, self.selected = total, current, selected self.set_label() def set_label(self): try: self._set_label() except: import traceback traceback.print_exc() def _set_label(self): msg = self.base_msg if self.device_string: msg += ' ..::.. ' + self.device_string else: msg += _(' %(created)s %(name)s') % dict(created=_('created by'), name='Kovid Goyal') if self.total != self.current: base = _('%(num)d of %(total)d books') % dict(num=self.current, total=self.total) else: base = _('%d books') % self.total if self.selected > 0: base = _('%(num)s, %(sel)d selected') % dict(num=base, sel=self.selected) if self.library_total != self.total: base = _('{0}, {1} total').format(base, self.library_total) self.defmsg.setText(u'%s\xa0\xa0\xa0\xa0[%s]' % (msg, base)) self.clearMessage() def device_disconnected(self): self.device_string = '' self.set_label() def show_message(self, msg, timeout=0): self.showMessage(msg, timeout) if self.notifier is not None and not config[ 'disable_tray_notification']: if isosx and isinstance(msg, unicode): try: msg = msg.encode(preferred_encoding) except UnicodeEncodeError: msg = msg.encode('utf-8') self.notifier(msg) def clear_message(self): self.clearMessage()