class ElCol(NicosWidget, QAbstractButton): def __init__(self, client, parent=None): QAbstractButton.__init__(self, parent) self.flag = False self.pixmap = QPixmap(path.join(widgetpath, 'focus.png')) self.pixmap2 = QPixmap(path.join(widgetpath, 'collimator.png')) NicosWidget.__init__(self) self.setClient(client) self.current = self._client.getDeviceValue('ellcol') self.currmap = self.pixmap if self.current == 'Ell' else self.pixmap2 self.repaint() self.clicked.connect(self.on_clicked) def paintEvent(self, event): painter = QPainter(self) if self.flag is False: painter.drawPixmap(event.rect(), self.currmap) self.rect = event.rect() else: pixmap = self.pixmap if self.current == 'Ell' else self.pixmap2 painter.drawPixmap(event.rect(), pixmap) self.rect = event.rect() self.currmap = pixmap self.flag = False def registerKeys(self): self.registerDevice('ellcol') def on_devValueChange(self, dev, value, strvalue, unitvalue, expired): self.current = value self.flag = True self.repaint() def sizeHint(self): return self.pixmap.size() def enterEvent(self, event): pass def leaveEvent(self, event): pass def on_clicked(self): data = 'Ell' if self.current == 'Col' else 'Col' self._client.tell('exec', "ellcol.move('%s')" % data)
class MessageView(QTextBrowser): def __init__(self, parent): QTextBrowser.__init__(self, parent) self._messages = [] self._actionlabel = None self._currentuser = None self.setFullTimestamps(False) self._background_image = None self._background_image_area = None self.text_curson_position = QTextCursor.End def setFullTimestamps(self, on): if on: self.formatTime = format_time_full self.formatImportantTime = lambda timeval: ': ' else: self.formatTime = format_time self.formatImportantTime = \ lambda timeval: ' ' + format_time_full(timeval) def setActionLabel(self, label): self._actionlabel = label def clear(self): QTextBrowser.clear(self) self._messages = [] def clearAlmostEverything(self): # Clears all messages, except the last input command with its output. # This is used for clearing output on NewExperiment, because the event # that clears the messages arrives *after* the command has run. msgs = self._messages[:] self.clear() i = 0 for i in range(len(msgs) - 1, -1, -1): if msgs[i][2] == INPUT: break self.addMessages(msgs[i:]) def scrollToBottom(self): bar = self.verticalScrollBar() bar.setValue(bar.maximum()) def getLatest(self, n=5): # Return latest n commands together with warning/error output. inputcount = 0 retmsgs = [] for i in range(len(self._messages) - 1, -1, -1): if self._messages[i][2] == INPUT: retmsgs.append(self._messages[i]) inputcount += 1 if inputcount == n: break elif self._messages[i][2] >= WARNING: retmsgs.append(self._messages[i]) return retmsgs[::-1] def formatMessage(self, message, actions=True): # message is a sequence: # (logger, time, levelno, message, exc_text, reqid) fmt = None levelno = message[2] if message[0] == 'nicos': name = '' else: name = '%-10s: ' % message[0] if message[5] == '0': # simulation result started by console name = '(sim) ' + name if levelno == ACTION: if actions and self._actionlabel: action = message[3].strip() if action: self._actionlabel.setText('Status: ' + action) self._actionlabel.show() else: self._actionlabel.hide() return '', None elif levelno <= DEBUG: text = name + message[3] fmt = grey elif levelno <= INFO: if message[3].startswith(' > '): fmt = QTextCharFormat(bold) fmt.setAnchor(True) command = to_utf8(message[3][4:].strip()) fmt.setAnchorHref('exec:' + urllib.parse.quote(command)) return name + message[3], fmt text = name + message[3] elif levelno == INPUT: m = command_re.match(message[3]) if m: fmt = QTextCharFormat(bold) fmt.setAnchor(True) command = to_utf8(m.group(2)) fmt.setAnchorHref('exec:' + urllib.parse.quote(command)) if m.group(1) != self._currentuser: fmt.setForeground(QBrush(QColor('#0000C0'))) return message[3], fmt m = script_re.match(message[3]) if m: fmt = QTextCharFormat(bold) if m.group(2): command = to_utf8(m.group(2)) fmt.setAnchor(True) fmt.setAnchorHref('edit:' + urllib.parse.quote(command)) if m.group(1) != self._currentuser: fmt.setForeground(QBrush(QColor('#0000C0'))) return message[3], fmt m = update_re.match(message[3]) if m: fmt = QTextCharFormat(bold) if m.group(2): command = to_utf8(m.group(2)) fmt.setAnchor(True) fmt.setAnchorHref('edit:' + urllib.parse.quote(command)) if m.group(1) != self._currentuser: fmt.setForeground(QBrush(QColor('#006090'))) else: fmt.setForeground(QBrush(QColor('#00A000'))) return message[3], fmt return message[3], bold elif levelno <= WARNING: text = levels[levelno] + ': ' + name + message[3] fmt = magenta else: text = levels[levelno] + self.formatImportantTime(message[1]) + \ name + message[3] fmt = redbold if message[4] and fmt: # need to construct a new unique object for this fmt = QTextCharFormat(fmt) # show traceback info on click fmt.setAnchor(True) tbinfo = to_utf8(message[4]) fmt.setAnchorHref('trace:' + urllib.parse.quote(tbinfo)) return text, fmt def addText(self, text, fmt=None): textcursor = self.textCursor() textcursor.movePosition(self.text_curson_position) textcursor.setCharFormat(fmt or std) textcursor.insertText(from_maybe_utf8(text)) def addMessage(self, message): bar = self.verticalScrollBar() prevmax = bar.maximum() prevval = bar.value() text, fmt = self.formatMessage(message) if text: # not for ACTIONs self.addText(self.formatTime(message[1]), grey) self.addText(text, fmt) self._messages.append(message) # only scroll to bottom if we were there already if prevval >= prevmax - 5: self.scrollToBottom() def addMessages(self, messages): textcursor = self.textCursor() textcursor.movePosition(self.text_curson_position) formatter = self.formatMessage for message in messages: text, fmt = formatter(message, actions=False) if text: textcursor.setCharFormat(grey) textcursor.insertText(self.formatTime(message[1])) textcursor.setCharFormat(fmt or std) textcursor.insertText(text) self._messages.append(message) def getOutputString(self): return self.toPlainText() def findNext(self, what, regex=False): cursor = self.textCursor() if regex: rx = QRegExp(what, Qt.CaseInsensitive) newcurs = self.document().find(rx, cursor) else: newcurs = self.document().find(what, cursor) self.setTextCursor(newcurs) return not newcurs.isNull() def occur(self, what, regex=False): content = self.toPlainText().split('\n') if regex: regexp = QRegExp(what, Qt.CaseInsensitive) content = [line for line in content if regexp.indexIn(line) >= 0] else: what = what.lower() content = [line for line in content if what in line.lower()] content = '\n'.join(content) window = QMainWindow(self) window.resize(600, 800) window.setWindowTitle('Lines matching %r' % what) widget = QTextEdit(window) widget.setFont(self.font()) window.setCentralWidget(widget) widget.setText(content) window.show() def setBackgroundImage(self, filepath): self._background_image = QPixmap(filepath) self.recalculateBackgroundArea() def recalculateBackgroundArea(self): if self._background_image is None: return # recalculate the rect to draw the background image into size = self._background_image.size() # scale to viewport size and add some margin size.scale(self.viewport().size() - QSize(30, 30), Qt.KeepAspectRatio) # center background image p = (self.viewport().size() - size) / 2 self._background_image_area = QRect(p.width(), p.height(), size.width(), size.height()) def scrollContentsBy(self, x, y): QTextBrowser.scrollContentsBy(self, x, y) if self._background_image: # repaint viewport on scoll to preserve the background image. # Using 'update' to let qt optimize the process (speed/flickering) self.viewport().update() def enableReverseScrolling(self, value): if value: self.text_curson_position = QTextCursor.Start else: self.text_curson_position = QTextCursor.End def resizeEvent(self, ev): # recalculate the background area only if necessary self.recalculateBackgroundArea() QTextBrowser.resizeEvent(self, ev) def paintEvent(self, ev): if self._background_image: # draw background image if any (should be mostly transparent!) painter = QPainter() painter.begin(self.viewport()) painter.drawPixmap(self._background_image_area, self._background_image) painter.end() QTextBrowser.paintEvent(self, ev)