Source code for vdat.gui.buttons_menu

"""Panel containing buttons to run reduction steps"""
from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

import traceback

from PyQt4 import QtGui
try:
    from PyQt4.QtCore import QString
except ImportError:  # For Python3
    QString = str
import six

from vdat.gui.queue import get_queue
from vdat.gui.fplane import yield_selected_ifus
import vdat.command_interpreter as vci
import vdat.config as vconf
import vdat.database as vdb


[docs]class ButtonsMenu(QtGui.QStackedWidget): """Parent widget containing the buttons to run the reduction steps Parameters ---------- parent : :class:`QtWidget` instance The QtWidget that the menu is attached to name : string name of the widget Attributes ---------- """ def __init__(self, parent=None, name="buttons_widget"): super(ButtonsMenu, self).__init__(parent=parent) # map each of the sub widget containing groups of buttons self._subwidgets_map = {} self.setObjectName(name) # create an empty widget to hide the other ones when nothing has been # selected blank_widget = QtGui.QWidget(parent=self) blank_widget.setObjectName('blank') blank_index = self.addWidget(blank_widget) self.setCurrentIndex(blank_index) self.setMinimumWidth(100) self.setMaximumWidth(300)
[docs] def get_subwidget(self, name): """Returns a sub-widget called ``name``. Create it if needed""" try: return self._subwidgets_map[name] except KeyError: subwidget = ButtonWidget(parent=self, name=name) self._subwidgets_map[name] = subwidget self.addWidget(subwidget) return subwidget
[docs] def setCurrentWidgetByName(self, name): """Set the current widget by name Parameters ---------- name : string name associated with the widget """ widget = self._subwidgets_map[name] super(ButtonsMenu, self).setCurrentWidget(widget)
[docs]class ButtonWidget(QtGui.QWidget): """Actual widget containing the buttons Parameters ---------- parent : :class:`QtWidget` instance The QtWidget that the menu is attached to name : string name of the widget """ def __init__(self, parent=None, name=''): super(ButtonWidget, self).__init__(parent=parent) # map each of the sub widget containing groups of buttons self._button_map = {} self.name = name self.setObjectName(name) self.layout = QtGui.QVBoxLayout() self.layout.setObjectName(name + "layout") self.setLayout(self.layout)
[docs] def add_button(self, name, commands, tool_tip=None): """Adds a button to the widget. Parameters ---------- name : string name of the button commands : list of strings, optional strings defining the commands tool_tip : string, optional text that appears as a tool tip when the user hovers their mouse over the button """ button = CommandButton(name, commands, tool_tip=tool_tip, parent=self) # Save it in case we need it later self._button_map[name] = button self.layout.addWidget(button)
[docs] def add_stretch(self, stretch=1): """Add a stretch to the layout containing the buttons Parameters ---------- stretch : int, optional stretch factor """ self.layout.addStretch(stretch)
[docs]class CommandButton(QtGui.QPushButton): """Custom class implementing the button. Parameters ---------- name : string name of the button commands : list of strings, optional strings defining the commands tool_tip : string, optional text that appears as a tool tip when the user hovers their mouse over the button parent : :class:`QtWidget` instance The QtWidget that the menu is attached to Attributes ---------- commands """ def __init__(self, name, commands, tool_tip=None, parent=None): super(CommandButton, self).__init__(parent=parent) if isinstance(commands, six.string_types): commands = [commands] self.commands = commands self.command_names = [c.split()[0] for c in self.commands] if parent: object_name = parent.objectName() + name else: object_name = name self.setObjectName(object_name) self.setText(name) if tool_tip is not None: self.setToolTip(tool_tip) self.clicked.connect(self._callback())
[docs] def _callback(self): def make_commands(): submit_to_queue = [] ihmpids = self._selected_ifus() if not ihmpids: return for name, command in zip(self.command_names, self.commands): try: command_conf = self._config_with_dirs(name) cmd_interpreter = vci.CommandInterpreter(command, command_conf, selected=ihmpids) submit_to_queue.append([cmd_interpreter, name, command]) except Exception as e: self._error_dialog(e, command) return queue = get_queue() for sq in submit_to_queue: queue.add_command(*sq) return make_commands
[docs] def _config_with_dirs(self, command_name): """Get the command configuration and add ``target_dir``, ``zero_dir`` and ``cal_dir`` to the configuration. Parameters ---------- command_name : string name of the command Returns ------- command_conf : dict configuration dictionary for the command at hand """ command_conf = vconf.get_config('commands', section=command_name) dirs_conf = vconf.get_config('main', section='redux_dirs') # the target, or selected, directory is selected command_conf['target_dir'] = dirs_conf['selected_dir'] # if no calibration and/or zero directory are selected, get them from # the database db_entry = (vdb.VDATDir.select() .where(vdb.VDATDir.path == command_conf['target_dir']) .get()) command_conf['zero_dir'] = dirs_conf.get('zro_dir', getattr(db_entry.zero_dir, 'path', '')) command_conf['cal_dir'] = dirs_conf.get('cal_dir', getattr(db_entry.cal_dir, 'path', '')) return command_conf
[docs] def _error_dialog(self, error, command): """Create the dialog to show the error Parameters ---------- error : :class:`Exception` instance error raised by the constructor command : string full command string """ box = QtGui.QMessageBox(parent=self) text = ("The following exceptions has been raised while" " parsing the command: '{}'\n:{}".format(command, error)) box.setText(text) if isinstance(error, (vci.exceptions.CIError, vconf.MissingConfigurationSectionError)): informative_text = ('Make sure that the command configuration' ' file and the command that you want to run' ' are in sync') icon = QtGui.QMessageBox.Warning else: informative_text = ("The error is unexpected and it is probably a" " bug. If you want to inspect the error click" " on the 'Show details' button to see the full" " traceback. If you want to report the error" " to the developers, please ") icon = QtGui.QMessageBox.Critical box.setInformativeText(informative_text) box.setIcon(icon) tb_text = traceback.format_exc() box.setDetailedText(tb_text) box.exec_()
[docs] def _selected_ifus(self): """Collect the selected IFUs and return a list of ifu Return ------ ihmpid : list list of ifu head mount plate IDs """ ihmpids = [ifu.ihmpid for ifu in yield_selected_ifus()] if ihmpids: return ihmpids else: box = QtGui.QMessageBox(parent=self) box.setText("Please select the IFUs by clicking on them or via " " the 'Select' menu") box.setIcon(QtGui.QMessageBox.Warning) box.exec_()
[docs]def setup_buttons(parent=None): """Set up and return the buttons Parameters ---------- parent : :class:`PyQt4.QtGui.QWidget` parent of the button widget Returns ------- :class:`ButtonsMenu` button widgets container """ button_config = vconf.get_config('buttons') buttons_menu = ButtonsMenu(parent) # loop through the entries in the configuration file for k, v in six.iteritems(button_config): b_widget = buttons_menu.get_subwidget(k) # the value ``v`` is a list of buttons for button in v: b_widget.add_button(**button) # Push the buttons to the top of the layout b_widget.add_stretch() return buttons_menu