예제 #1
0
class ExpInfoPanel(Panel):
    """Provides a panel with several labels displaying basic experiment info.

    This is for example the experiment title, sample name, and user name.

    It also provides several buttons with which the user can change proposal
    info, sample properties, scan environment and setups.

    Options:

    * ``sample_panel`` -- what to show when the user clicks on the "Sample"
      button.  The value must be a panel configuration, e.g. ``panel('...')``
      or ``tabbed(...)``.

      There are several panels that are useful for this:

      - ``nicos.clients.gui.panels.setup_panel.GenericSamplePanel`` -- a panel
        that only shows a single input box for the sample name.
      - ``nicos.clients.gui.panels.setup_panel.TasSamplePanel`` -- a panel that
        also shows input boxes for triple-axis sample properties (such as
        lattice constants).

    * ``popup_proposal_after`` -- if given, the proposal dialog will be opened
      when the daemon has been idle for more than the specified time interval
      (in hours).
    * ``new_exp_panel`` -- class name of the panel which should be opened after
      a new experiment has been started from the proposal info panel.
    * ``finish_exp_panel`` -- class name of the panel which should be opened
      before an experiment is finished from the proposal info panel.
    """

    panelName = 'Experiment Info'
    _viewonly = False

    def __init__(self, parent, client, options):
        Panel.__init__(self, parent, client, options)
        loadUi(self, 'panels/expinfo.ui')
        for ch in self.findChildren(NicosWidget):
            ch.setClient(client)
        client.setup.connect(self.on_client_setup)
        client.initstatus.connect(self.on_client_initstatus)

        self.detLabel.setFormatCallback(
            lambda value, strvalue: ', '.join(sorted(value)))
        self.envLabel.setFormatCallback(
            lambda value, strvalue: ', '.join(sorted(value)))

        self._sample_panel = options.get('sample_panel', GenericSamplePanel)
        self._new_exp_panel = options.get('new_exp_panel')
        self._finish_exp_panel = options.get('finish_exp_panel')
        self._timeout = options.get('popup_proposal_after', 0)
        if self._timeout:
            self._proposal_popup_timer = QTimer(interval=self._timeout * 3600000)
            self._proposal_popup_timer.setSingleShot(True)
            self._proposal_popup_timer.timeout.connect(
                self.on_proposal_popup_timer_timeout)
        else:
            self._proposal_popup_timer = None

    def hideTitle(self):
        self.titleLbl.setVisible(False)

    def setViewOnly(self, viewonly):
        self._viewonly = viewonly
        if not self._viewonly and self._timeout:
            # ask explicitly for status to restart timer if necessary
            self.client.ask('getstatus')

    def on_client_initstatus(self, initstatus):
        self.setupLabel.setText(', '.join(sorted(initstatus['setups'][1])))

    def on_client_setup(self, data):
        self.setupLabel.setText(', '.join(sorted(data[1])))

    def updateStatus(self, status, exception=False):
        if self._proposal_popup_timer:
            if status == 'idle':
                if not self._viewonly or \
                    (self.client.user_level is not None and
                     self.client.user_level < ADMIN):
                    self._proposal_popup_timer.start()
            else:
                self._proposal_popup_timer.stop()

    def on_proposal_popup_timer_timeout(self):
        if self._viewonly:
            return
        dlg = QMessageBox(self)
        dlg.setText('The experiment has been idle for more than %.1f hours.' %
                    self._timeout)
        contButton = QPushButton('Continue current experiment')
        finishAndNewButton = QPushButton('Finish and start new experiment')
        dlg.addButton(contButton, QMessageBox.RejectRole)
        dlg.addButton(finishAndNewButton, QMessageBox.ActionRole)
        dlg.exec_()
        if dlg.clickedButton() == finishAndNewButton:
            self.on_proposalBtn_clicked()
        elif dlg.clickedButton() == contButton:
            self._proposal_popup_timer.start()

    @pyqtSlot()
    def on_proposalBtn_clicked(self):
        dlg = PanelDialog(self, self.client, ExpPanel, 'Proposal info',
                          new_exp_panel=self._new_exp_panel,
                          finish_exp_panel=self._finish_exp_panel)
        dlg.exec_()

    @pyqtSlot()
    def on_setupBtn_clicked(self):
        dlg = PanelDialog(self, self.client, SetupsPanel, 'Setups')
        dlg.exec_()

    @pyqtSlot()
    def on_sampleBtn_clicked(self):
        dlg = PanelDialog(self, self.client, self._sample_panel,
                          'Sample information')
        dlg.exec_()

    @pyqtSlot()
    def on_detenvBtn_clicked(self):
        dlg = PanelDialog(self, self.client, DetEnvPanel,
                          'Detectors and environment')
        dlg.exec_()

    @pyqtSlot()
    def on_remarkBtn_clicked(self):
        dlg = dialogFromUi(self, 'panels/expinfo_remark.ui')

        def callback():
            self.showInfo('The remark will be added to the logbook as a '
                          'heading and will also appear in the data files.')
        dlg.buttonBox.helpRequested.connect(callback)

        for ch in dlg.findChildren(NicosWidget):
            ch.setClient(self.client)
        dlg.remarkEdit.setFocus()
        if not dlg.exec_():
            return
        self.client.run('Remark(%r)' % dlg.remarkEdit.getValue())
예제 #2
0
class EntryWidget(base_class, ui_class):
    def __init__(self,
                 client,
                 watcher,
                 entry,
                 shortKey,
                 showTimeStamp,
                 showTTL,
                 parent=None):
        base_class.__init__(self, parent)
        self.setupUi(self)
        self.updateTimer = QTimer(self)
        self.updateTimer.setSingleShot(True)
        self.watcher = watcher
        self.client = client
        self.entry = entry
        self.widgetValue = None
        self.setupEvents()
        self.setupWidgetUi(shortKey, showTimeStamp, showTTL)

    def setupEvents(self):
        """Sets up all events."""
        self.buttonSet.clicked.connect(self.setKey)
        self.buttonDel.clicked.connect(self.delKey)
        self.buttonWatch.clicked.connect(self.watchKey)
        self.client.signals.keyUpdated.connect(self.keyUpdated)
        self.updateTimer.timeout.connect(self.updateTimerEvent)

    def setupWidgetUi(self, shortKey, showTimeStamp, showTTL):
        """
        Sets up and generate a UI according to the data type of the value
        and whether or not time to live or time stamp should be shown.
        """
        entry = self.entry

        fm = self.labelTime.fontMetrics()
        margins = self.labelTime.getContentsMargins()
        self.labelTime.setMinimumWidth(
            fm.width(entry.convertTime(1.0)) + margins[0] + margins[2] +
            self.labelTime.sizeHint().width())

        if self.watcher is None:  # widget is already in watcher
            self.buttonWatch.hide()

        if shortKey:
            self.labelKey.setText(entry.key.rpartition('/')[2])
            self.labelKey.setToolTip(entry.key)
        else:
            self.labelKey.setText(entry.key)

        if entry.value in ('True', 'False'):
            self.widgetValue = ReadOnlyCheckBox()
            self.layoutWidget.insertWidget(4, self.widgetValue)
            self.layoutWidget.insertSpacerItem(
                5, QSpacerItem(56, 20, QSizePolicy.Expanding))
        else:
            self.widgetValue = QLineEdit()
            self.layoutWidget.insertWidget(4, self.widgetValue)
        self.widgetValue.setReadOnly(True)
        self.widgetValue.setToolTip(entry.key)

        if not showTTL:
            self.labelTTL.hide()
        if not showTimeStamp:
            self.labelTime.hide()

        self.updateValues()

    def updateValues(self):
        entry = self.entry

        if entry.expired:
            setBackgroundColor(self, expiredColor)
        elif entry.ttl:
            setBackgroundColor(self, ttlColor)

        if isinstance(self.widgetValue, ReadOnlyCheckBox):
            self.widgetValue.setChecked(entry.value == 'True')
        else:
            self.widgetValue.setText(entry.value)

        self.labelTTL.setText(str(entry.ttl or ''))
        self.labelTime.setText(entry.convertTime())

        if entry.ttl:
            # automatically refresh the value if the entry has a ttl (we don't
            # get timestamp updates from the server unless the value changes)
            time_to_update = max((entry.time + entry.ttl) - time.time(), 0)
            self.updateTimer.start(time_to_update * 1000)

    def setKey(self):
        """Sets the key locally and on the server."""
        dlg = EntryEditDialog(self)
        dlg.fillEntry(self.entry)
        dlg.valueTime.setText('')  # we want current timestamp by default
        dlg.valueKey.setReadOnly(True)
        if dlg.exec_() != QDialog.Accepted:
            return
        entry = dlg.getEntry()
        self.client.put(entry.key, entry)

    def delKey(self):
        if QMessageBox.question(self, 'Delete', 'Really delete?',
                                QMessageBox.Yes
                                | QMessageBox.No) == QMessageBox.No:
            return
        self.client.delete(self.entry.key)

    def watchKey(self):
        """Adds our key to the watcher window."""
        if not self.watcher:
            return
        widget = EntryWidget(self.client, None, self.entry, False, True, True,
                             self.watcher)
        self.watcher.addWidgetKey(widget)
        self.watcher.show()

    def keyUpdated(self, key, entry):
        if key != self.entry.key:
            return
        self.entry = entry
        self.updateValues()

    def updateTimerEvent(self):
        self.client.update(self.entry.key)