Esempio n. 1
0
class _OptionsSelector(QDialog):

    def __init__(self, list_options, parent=None):
        QDialog.__init__(self, parent)

        # Variables
        model = _AvailableOptionsListModel()
        for options in list_options:
            model.addOptions(options)

        # Widgets
        lbltext = QLabel('Select the options to import')

        self._combobox = QComboBox()
        self._combobox.setModel(model)

        buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)

        # Layouts
        layout = QVBoxLayout()
        layout.addWidget(lbltext)
        layout.addWidget(self._combobox)
        layout.addWidget(buttons)
        self.setLayout(layout)

        # Signals
        buttons.accepted.connect(self.accept)
        buttons.rejected.connect(self.reject)

    def options(self):
        return self._combobox.model().options(self._combobox.currentIndex())
Esempio n. 2
0
class LimitWizardPage(_ExpandableOptionsWizardPage):

    class _LimitComboBoxModel(QAbstractListModel):

        def __init__(self, limits_text=None):
            QAbstractListModel.__init__(self)

            if limits_text is None:
                limits_text = {}
            self._limits_text = limits_text.copy()

            self._limits = list(limits_text.keys())

        def rowCount(self, *args, **kwargs):
            return len(self._limits)

        def data(self, index, role=Qt.DisplayRole):
            if not index.isValid() or \
                    not (0 <= index.row() < self.rowCount()):
                return None

            if role == Qt.TextAlignmentRole:
                return Qt.AlignCenter

            if role != Qt.DisplayRole:
                return None

            limit_class = self._limits[index.row()]
            return self._limits_text[limit_class]

        def add(self, limit_class):
            if limit_class not in self._limits_text:
                raise ValueError('No text defined for limit: %s' % limit_class)
            self._limits.append(limit_class)
            self.reset()

        def remove(self, limit_class):
            self._limits.remove(limit_class)
            self.reset()

        def limitClass(self, index):
            return self._limits[index]

    class _LimitTableModel(QAbstractTableModel):

        def __init__(self):
            QAbstractTableModel.__init__(self)
            self._limits = []

        def rowCount(self, *args, **kwargs):
            return len(self._limits)

        def columnCount(self, *args, **kwargs):
            return 1

        def data(self, index, role=Qt.DisplayRole):
            if not index.isValid() or \
                    not (0 <= index.row() < len(self._limits)):
                return None

            if role == Qt.TextAlignmentRole:
                return Qt.AlignCenter

            if role == Qt.DisplayRole or role == Qt.ToolTipRole:
                limit = self._limits[index.row()]
                return str(limit) if limit is not None else ''

            return None

        def headerData(self, section , orientation, role):
            if role != Qt.DisplayRole:
                return None
            if orientation == Qt.Vertical:
                return str(section + 1)

        def flags(self, index):
            if not index.isValid():
                return Qt.ItemIsEnabled

            return Qt.ItemFlags(QAbstractTableModel.flags(self, index) |
                                Qt.ItemIsEditable)

        def setData(self, index, value, role=Qt.EditRole):
            if not index.isValid() or \
                    not (0 <= index.row() < len(self._limits)):
                return False

            row = index.row()
            self._limits[row] = value

            self.dataChanged.emit(index, index)
            return True

        def insertRows(self, row, count=1, parent=None):
            if parent is None:
                parent = QModelIndex()
            self.beginInsertRows(parent, row, row + count - 1)

            for _ in range(count):
                self._limits.insert(row, None)

            self.endInsertRows()
            return True

        def removeRows(self, row, count=1, parent=None):
            if parent is None:
                parent = QModelIndex()
            self.beginRemoveRows(parent, row, row + count - 1)

            for index in reversed(range(row, row + count)):
                self._limits.pop(index)

            self.endRemoveRows()
            return True

        def append(self, limit):
            self.insert(self.rowCount(), limit)

        def insert(self, index, limit):
            self.insertRows(index)
            self.setData(self.createIndex(index, 0), limit)

        def remove(self, limit):
            index = self._limits.index(limit)
            self.removeRows(index)

        def modify(self, index, limit):
            self.setData(self.createIndex(index, 0), limit)

        def clear(self):
            self.removeRows(0, self.rowCount())

        def limits(self):
            limits = set(self._limits)
            limits.discard(None)
            return limits

        def limit(self, index):
            return self._limits[index.row()]

    class _LimitTableDelegate(QItemDelegate):

        def __init__(self, parent=None):
            QItemDelegate.__init__(self, parent)

        def createEditor(self, parent, option, index):
            return None

        def setEditorData(self, editor, index):
            pass

        def setModelData(self, editor, model, index):
            return None

    def __init__(self, options, parent=None):
        _ExpandableOptionsWizardPage.__init__(self, options, parent)
        self.setTitle('Limit')

    def _initUI(self):
        # Variables
        self._widgets = {}
        tbl_model = self._LimitTableModel()

        # Widgets
        self._cb_limit = QComboBox()
        self._cb_limit.setModel(self._LimitComboBoxModel())

        btn_limit_add = QPushButton()
        btn_limit_add.setIcon(getIcon("list-add"))

        self._tbl_limit = QTableView()
        self._tbl_limit.setModel(tbl_model)
        self._tbl_limit.setItemDelegate(self._LimitTableDelegate())
        header = self._tbl_limit.horizontalHeader()
        header.setResizeMode(QHeaderView.Stretch)
        header.hide()
        policy = self._tbl_limit.sizePolicy()
        policy.setVerticalStretch(True)
        self._tbl_limit.setSizePolicy(policy)

        tlb_limit = QToolBar()
        spacer = QWidget()
        spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        tlb_limit.addWidget(spacer)
        act_remove = tlb_limit.addAction(getIcon("list-remove"), "Remove limit")
        act_clear = tlb_limit.addAction(getIcon("edit-clear"), "Clear")

        # Layouts
        layout = _ExpandableOptionsWizardPage._initUI(self)

        sublayout = QHBoxLayout()
        sublayout.addWidget(self._cb_limit, 1)
        sublayout.addWidget(btn_limit_add)
        layout.addRow("Select", sublayout)

        layout.addRow(self._tbl_limit)
        layout.addRow(tlb_limit)

        # Signals
        btn_limit_add.released.connect(self._onLimitAdd)
        act_remove.triggered.connect(self._onLimitRemove)
        act_clear.triggered.connect(self._onLimitClear)

        self._tbl_limit.doubleClicked.connect(self._onLimitDoubleClicked)

        tbl_model.dataChanged.connect(self.valueChanged)
        tbl_model.rowsInserted.connect(self.valueChanged)
        tbl_model.rowsRemoved.connect(self.valueChanged)

        return layout

    def _onLimitAdd(self):
        tbl_model = self._tbl_limit.model()
        cb_model = self._cb_limit.model()

        index = self._cb_limit.currentIndex()
        try:
            limit_class = cb_model.limitClass(index)
        except IndexError:
            return
        widget_class = self._widgets[limit_class]
        wdg_limit = widget_class()

        dialog = _LimitDialog(wdg_limit)
        if not dialog.exec_():
            return

        limit = dialog.limit()
        tbl_model.append(limit) # Insert table row
        cb_model.remove(limit.__class__) # Remove limit from combo box

    def _onLimitRemove(self):
        selection = self._tbl_limit.selectionModel().selection().indexes()
        if len(selection) == 0:
            QMessageBox.warning(self, "Limit", "Select a row")
            return

        tbl_model = self._tbl_limit.model()
        cb_model = self._cb_limit.model()
        for row in sorted(map(methodcaller('row'), selection), reverse=True):
            limit = tbl_model.limit(tbl_model.createIndex(row, 0))
            cb_model.add(limit.__class__) # Show limit to combo box
            tbl_model.removeRow(row) # Remove row

        if self._cb_limit.currentIndex() < 0:
            self._cb_limit.setCurrentIndex(0)

    def _onLimitClear(self):
        tbl_model = self._tbl_limit.model()
        cb_model = self._cb_limit.model()
        for row in reversed(range(tbl_model.rowCount())):
            limit = tbl_model.limit(tbl_model.createIndex(row, 0))
            cb_model.add(limit.__class__) # Show limit to combo box
            tbl_model.removeRow(row) # Remove row

        if self._cb_limit.currentIndex() < 0:
            self._cb_limit.setCurrentIndex(0)

    def _onLimitDoubleClicked(self, index):
        tbl_model = self._tbl_limit.model()
        limit = tbl_model.limit(index)
        widget_class = self._widgets[limit.__class__]
        wdg_limit = widget_class()
        wdg_limit.setValue(limit)

        dialog = _LimitDialog(wdg_limit)
        if not dialog.exec_():
            return

        tbl_model.modify(index.row(), dialog.limit())

    def initializePage(self):
        _ExpandableOptionsWizardPage.initializePage(self)

        # Clear
        self._widgets.clear()
        limits_text = {}

        # Populate combo box
        it = self._iter_widgets('pymontecarlo.ui.gui.options.limit', 'LIMITS')
        for limit_class, widget_class, programs in it:
            widget = widget_class()
            self._widgets[limit_class] = widget_class

            program_text = ', '.join(map(attrgetter('name'), programs))
            text = '{0} ({1})'.format(widget.accessibleName(), program_text)
            limits_text[limit_class] = text

            del widget

        cb_model = self._LimitComboBoxModel(limits_text)
        self._cb_limit.setModel(cb_model)
        self._cb_limit.setCurrentIndex(0)

        # Add limit(s)
        tbl_model = self._tbl_limit.model()
        tbl_model.clear()

        for limit in self.options().limits:
            tbl_model.append(limit)

    def validatePage(self):
        tbl_model = self._tbl_limit.model()

        self.options().limits.clear()
        for limit in tbl_model.limits():
            if not limit.__class__ in self._widgets:
                continue
            self.options().limits.add(limit)

        return True

    def expandCount(self):
        if self._tbl_limit.model().rowCount() == 0:
            return 0

        try:
            count = 1

            for limit in self._tbl_limit.model().limits():
                count *= len(expand(limit))

            return count
        except:
            return 0
Esempio n. 3
0
class _PhotonDistributionResultOptionsToolItem(_ResultToolItem):
    def _initUI(self):
        # Variables
        result = self.result()
        transitions = sorted(result.iter_transitions())
        transition0 = transitions[0]
        model = _TransitionListModel(transitions)

        # Widgets
        self._chk_errorbar = QCheckBox("Show error bars")
        self._chk_errorbar.setChecked(True)

        self._cb_transition = QComboBox()
        self._cb_transition.setModel(model)
        self._cb_transition.setCurrentIndex(0)

        self._chk_pg = QCheckBox("No absorption, no fluorescence")
        state = result.exists(transition0, True, False, False, False)
        self._chk_pg.setEnabled(state)
        self._chk_pg.setChecked(state)

        self._chk_eg = QCheckBox("With absorption, no fluorescence")
        state = result.exists(transition0, True, True, False, False)
        self._chk_eg.setEnabled(state)
        self._chk_eg.setChecked(state)

        self._chk_pt = QCheckBox("No absorption, with fluorescence")
        state = result.exists(transition0, True, False, True, True)
        self._chk_pt.setEnabled(state)
        self._chk_pt.setChecked(state)

        self._chk_et = QCheckBox("With absorption, with fluorescence")
        state = result.exists(transition0, True, True, True, True)
        self._chk_et.setEnabled(state)
        self._chk_et.setChecked(state)

        # Layouts
        layout = _ResultToolItem._initUI(self)
        layout.addRow(self._chk_errorbar)
        layout.addRow("Transition", self._cb_transition)

        boxlayout = QVBoxLayout()
        boxlayout.addWidget(self._chk_pg)
        boxlayout.addWidget(self._chk_eg)
        boxlayout.addWidget(self._chk_pt)
        boxlayout.addWidget(self._chk_et)

        box_generated = QGroupBox("Curves")
        box_generated.setLayout(boxlayout)
        layout.addRow(box_generated)

        # Signals
        self._cb_transition.currentIndexChanged.connect(self._onTransitionChanged)
        self._chk_pg.stateChanged.connect(self.stateChanged)
        self._chk_eg.stateChanged.connect(self.stateChanged)
        self._chk_pt.stateChanged.connect(self.stateChanged)
        self._chk_et.stateChanged.connect(self.stateChanged)
        self._chk_errorbar.stateChanged.connect(self.stateChanged)

        return layout

    def _onTransitionChanged(self):
        result = self.result()

        index = self._cb_transition.currentIndex()
        transition = self._cb_transition.model().transition(index)

        self._chk_pg.setEnabled(result.exists(transition, True, False, False, False))
        self._chk_eg.setEnabled(result.exists(transition, True, True, False, False))
        self._chk_pt.setEnabled(result.exists(transition, True, False, True, True))
        self._chk_et.setEnabled(result.exists(transition, True, True, True, True))

        self.stateChanged.emit()

    def transition(self):
        index = self._cb_transition.currentIndex()
        return self._cb_transition.model().transition(index)

    def showConditions(self):
        return (
            self._chk_pg.isChecked() and self._chk_pg.isEnabled(),
            self._chk_eg.isChecked() and self._chk_eg.isEnabled(),
            self._chk_pt.isChecked() and self._chk_pt.isEnabled(),
            self._chk_et.isChecked() and self._chk_et.isEnabled(),
        )

    def showErrorbar(self):
        return self._chk_errorbar.isChecked()
Esempio n. 4
0
    def __init__(self, results, result_key,
                 parameter_getters, x_parameter_name,
                 series=None, parent=None):
        QDialog.__init__(self, parent)

        # Variables
        self._results = results
        self._result_key = result_key
        self._parameter_getters = parameter_getters
        options = results.options

        # Widgets
        self._txt_name = QLineEdit()

        self._cb_parameters = {}
        for name, getter in parameter_getters.items():
            if name == x_parameter_name:
                continue

            combobox = QComboBox()
            values = np.array(getter(options), ndmin=1)
            combobox.setModel(_ValuesModel(values))
            self._cb_parameters[name] = combobox

        self._cb_summary_key = QComboBox()
        self._cb_summary_key.setModel(_ValuesModel([]))

        buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)

        # Layouts
        layout = QFormLayout()
        if sys.platform == 'darwin': # Fix for Mac OS
            layout.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.ExpandingFieldsGrow)
        layout.addRow('Name', self._txt_name)
        for name, combobox in self._cb_parameters.items():
            layout.addRow(name, combobox)
        layout.addRow('Summary variable', self._cb_summary_key)

        layout.addRow(buttons)

        self.setLayout(layout)

        # Signals
        buttons.accepted.connect(self._onOk)
        buttons.rejected.connect(self.reject)

        for combobox in self._cb_parameters.values():
            combobox.currentIndexChanged.connect(self._onParameterChanged)

        # Defaults
        if series is not None:
            self._txt_name.setText(series.name)

            for name, _, value in series.conditions:
                combobox = self._cb_parameters[name]
                index = combobox.model().valueIndex(value)
                combobox.setCurrentIndex(index)
            self._onParameterChanged()

            index = self._cb_summary_key.model().valueIndex(series.summary_key)
            self._cb_summary_key.setCurrentIndex(index)
        else:
            self._onParameterChanged()
Esempio n. 5
0
class _SeriesDialog(QDialog):

    def __init__(self, results, result_key,
                 parameter_getters, x_parameter_name,
                 series=None, parent=None):
        QDialog.__init__(self, parent)

        # Variables
        self._results = results
        self._result_key = result_key
        self._parameter_getters = parameter_getters
        options = results.options

        # Widgets
        self._txt_name = QLineEdit()

        self._cb_parameters = {}
        for name, getter in parameter_getters.items():
            if name == x_parameter_name:
                continue

            combobox = QComboBox()
            values = np.array(getter(options), ndmin=1)
            combobox.setModel(_ValuesModel(values))
            self._cb_parameters[name] = combobox

        self._cb_summary_key = QComboBox()
        self._cb_summary_key.setModel(_ValuesModel([]))

        buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)

        # Layouts
        layout = QFormLayout()
        if sys.platform == 'darwin': # Fix for Mac OS
            layout.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.ExpandingFieldsGrow)
        layout.addRow('Name', self._txt_name)
        for name, combobox in self._cb_parameters.items():
            layout.addRow(name, combobox)
        layout.addRow('Summary variable', self._cb_summary_key)

        layout.addRow(buttons)

        self.setLayout(layout)

        # Signals
        buttons.accepted.connect(self._onOk)
        buttons.rejected.connect(self.reject)

        for combobox in self._cb_parameters.values():
            combobox.currentIndexChanged.connect(self._onParameterChanged)

        # Defaults
        if series is not None:
            self._txt_name.setText(series.name)

            for name, _, value in series.conditions:
                combobox = self._cb_parameters[name]
                index = combobox.model().valueIndex(value)
                combobox.setCurrentIndex(index)
            self._onParameterChanged()

            index = self._cb_summary_key.model().valueIndex(series.summary_key)
            self._cb_summary_key.setCurrentIndex(index)
        else:
            self._onParameterChanged()

    def _onParameterChanged(self):
        summary_keys = set()

        for container in self._results:
            match = True
            for name, expected in self.parameterValue().items():
                getter = self._parameter_getters[name]
                actual = getter(container.options)
                if actual != expected:
                    match = False
                    break

            if not match:
                continue

            try:
                result = container[self._result_key]
            except KeyError:
                continue

            summary_keys.update(result.get_summary().keys())

        self._cb_summary_key.setModel(_ValuesModel(summary_keys))

    def _onOk(self):
        if self._cb_summary_key.currentIndex() < 0:
            return
        self.accept()

    def name(self):
        name = self._txt_name.text().strip()

        if not name:
            parts = []
            for param_name, value in self.parameterValue().items():
                parts.append('%s=%s' % (param_name, value))
            parts.append('summary=%s' % self.summaryKey())
            name = '+'.join(parts)

        return name

    def parameterValue(self):
        parameter_value = {}
        for name, combobox in self._cb_parameters.items():
            try:
                value = combobox.model().value(combobox.currentIndex())
                parameter_value[name] = value
            except IndexError:
                continue
        return parameter_value

    def summaryKey(self):
        return self._cb_summary_key.model().value(self._cb_summary_key.currentIndex())
Esempio n. 6
0
class TransferPanel(QWidget):
    '''
    Transfer Panel
    
    This Panel is the main dialog box for the Dive Computer Transfer GUI
    '''
    def __init__(self, parent=None):
        super(TransferPanel, self).__init__(parent)
        
        self._logbook = None
        self._logbookName = 'None'
        self._logbookPath = None
        
        self._createLayout()
        
        self._readSettings()
        self.setWindowTitle(self.tr('DC Transfer - %s') % self._logbookName)
        
    def _createLayout(self):
        'Create the Widget Layout'
        
        self._txtLogbook = QLineEdit()
        self._txtLogbook.setReadOnly(True)
        self._lblLogbook = QLabel(self.tr('&Logbook File:'))
        self._lblLogbook.setBuddy(self._txtLogbook)
        self._btnBrowse = QPushButton('...')
        self._btnBrowse.clicked.connect(self._btnBrowseClicked)
        self._btnBrowse.setStyleSheet('QPushButton { min-width: 24px; max-width: 24px; }')
        self._btnBrowse.setToolTip(self.tr('Browse for a Logbook'))
        
        self._cbxComputer = QComboBox()
        self._lblComputer = QLabel(self.tr('Dive &Computer:'))
        self._lblComputer.setBuddy(self._cbxComputer)
        self._btnAddComputer = QPushButton(QPixmap(':/icons/list-add.png'), self.tr(''))
        self._btnAddComputer.setStyleSheet('QPushButton { min-width: 24px; min-height: 24; max-width: 24px; max-height: 24; }')
        self._btnAddComputer.clicked.connect(self._btnAddComputerClicked)
        self._btnRemoveComputer = QPushButton(QPixmap(':/icons/list-remove.png'), self.tr(''))
        self._btnRemoveComputer.setStyleSheet('QPushButton { min-width: 24px; min-height: 24; max-width: 24px; max-height: 24; }')
        self._btnRemoveComputer.clicked.connect(self._btnRemoveComputerClicked)
        
        hbox = QHBoxLayout()
        hbox.addWidget(self._btnAddComputer)
        hbox.addWidget(self._btnRemoveComputer)
        
        gbox = QGridLayout()
        gbox.addWidget(self._lblLogbook, 0, 0)
        gbox.addWidget(self._txtLogbook, 0, 1)
        gbox.addWidget(self._btnBrowse, 0, 2)
        gbox.addWidget(self._lblComputer, 1, 0)
        gbox.addWidget(self._cbxComputer, 1, 1)
        gbox.addLayout(hbox, 1, 2)
        gbox.setColumnStretch(1, 1)
        
        self._pbTransfer = QProgressBar()
        self._pbTransfer.reset()
        self._txtStatus = QTextEdit()
        self._txtStatus.setReadOnly(True)
        
        self._btnTransfer = QPushButton(self.tr('&Transfer Dives'))
        self._btnTransfer.clicked.connect(self._btnTransferClicked)
        
        self._btnExit = QPushButton(self.tr('E&xit'))
        self._btnExit.clicked.connect(self.close)
        
        hbox = QHBoxLayout()
        hbox.addWidget(self._btnTransfer)
        hbox.addStretch()
        hbox.addWidget(self._btnExit)
        
        vbox = QVBoxLayout()
        vbox.addLayout(gbox)
        vbox.addWidget(self._pbTransfer)
        vbox.addWidget(self._txtStatus)
        vbox.addLayout(hbox)
        
        self.setLayout(vbox)
        
    def _closeLogbook(self):
        'Close the current Logbook'
        if self._logbook is None:
            return
        
        self._logbook = None
        self._logbookName = 'None'
        self._logbookPath = None
        
        self._txtLogbook.clear()
        self._cbxComputer.setModel(None)
        
        self._writeSettings()
        self.setWindowTitle(self.tr('DC Transfer - %s') % self._logbookName)
        
    def _openLogbook(self, path):
        'Open an existing Logbook'
        if self._logbook is not None:
            self._closeLogbook()
            
        if not os.path.exists(path):
            QMessageBox.critical(self, self.tr('Missing Logbook'), 
                self.tr('Logbook File "%s" does not exist.') % path)
            return
        
        #TODO: Handle a Schema Upgrade in a user-friendly manner
        self._logbook = Logbook(path, auto_update=False)
        self._logbookName = os.path.basename(path)
        self._logbookPath = path
        
        self._txtLogbook.setText(self._logbookPath)
        self._cbxComputer.setModel(DiveComputersModel(self._logbook))
        
        self._writeSettings()
        self.setWindowTitle(self.tr('DC Transfer - %s') % self._logbookName)
        
    def _readSettings(self):
        'Read main window settings from the configuration'
        settings = QSettings()
        settings.beginGroup('MainWindow')
        max = settings.value('max')
        size = settings.value('size')
        pos = settings.value('pos')
        file = settings.value('file')
        settings.endGroup()
        
        # Size and Position the Main Window
        if size is not None:
            self.resize(size)
        if pos is not None:
            self.move(pos)
            
        # HAX because QVariant is not exposed in PySide and the default
        # coercion to string is just stupid
        if max is not None and (max == 'true'):
            self.showMaximized()
        
        # Open the Logbook
        if file is not None:
            self._openLogbook(file)
        
    def _writeSettings(self):
        'Write settings to the configuration'
        settings = QSettings()
        settings.beginGroup('MainWindow')
        settings.setValue('pos', self.pos())
        settings.setValue('size', self.size())
        settings.setValue('max', self.isMaximized())
        settings.setValue('file', self._logbookPath)
        settings.endGroup()
        
    def closeEvent(self, e):
        'Intercept an OnClose event'
        self._writeSettings()
        e.accept()
        
    #--------------------------------------------------------------------------
    # Slots
    
    @QtCore.Slot()
    def _btnAddComputerClicked(self):
        'Add a Dive Computer'
        dc = AddDiveComputerWizard.RunWizard(self)
        
        if dc is not None:
            self._logbook.session.add(dc)
            self._logbook.session.commit()
            self._cbxComputer.model().reload()
            self._cbxComputer.setCurrentIndex(self._cbxComputer.findText(dc.name))
    
    @QtCore.Slot()
    def _btnRemoveComputerClicked(self):
        'Remove a Dive Computer'
        idx = self._cbxComputer.currentIndex()
        dc = self._cbxComputer.itemData(idx, Qt.UserRole+0)
        if QMessageBox.question(self, self.tr('Delete Dive Computer?'), 
                    self.tr('Are you sure you want to delete "%s"?') % dc.name,
                    QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) == QMessageBox.Yes:
            self._logbook.session.delete(dc)
            self._logbook.session.commit()
            self._cbxComputer.model().reload()
    
    @QtCore.Slot()
    def _btnBrowseClicked(self):
        'Browse for a Logbook File'
        if self._logbook is not None:
            dir = os.path.dirname(self._logbookPath)
        else:
            dir = os.path.expanduser('~')
        
        fn = QFileDialog.getOpenFileName(self,
            caption=self.tr('Select a Logbook file'), dir=dir,
            filter='Logbook Files (*.lbk);;All Files(*.*)')[0]    
        if fn == '':
            return
        if not os.path.exists(fn):
            if QMessageBox.question(self, self.tr('Create new Logbook?'), 
                    self.tr('Logbook "%s" does not exist. Would you like to create it?') % os.path.basename(fn),
                    QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) != QMessageBox.Yes:
                return
            Logbook.Create(fn)
        self._openLogbook(fn)
        
    @QtCore.Slot()
    def _btnTransferClicked(self):
        'Transfer Dives'
        idx = self._cbxComputer.currentIndex()
        dc = self._cbxComputer.itemData(idx, Qt.UserRole+0)
        
        if self._logbook.session.dirty:
            print "Flushing dirty session"
            self._logbook.rollback()
        
        self._txtLogbook.setEnabled(False)
        self._btnBrowse.setEnabled(False)
        self._cbxComputer.setEnabled(False)
        self._btnAddComputer.setEnabled(False)
        self._btnRemoveComputer.setEnabled(False)
        self._btnTransfer.setEnabled(False)
        self._btnExit.setEnabled(False)
        
        self._txtStatus.clear()
        
        thread = QThread(self)
        
        #FIXME: ZOMG HAX: Garbage Collector will eat TransferWorker when moveToThread is called
        #NOTE: Qt.QueuedConnection is important...
        self.worker = None
        self.worker = TransferWorker(dc)
        thread.started.connect(self.worker.start, Qt.QueuedConnection)
        self.worker.moveToThread(thread)
        self.worker.finished.connect(self._transferFinished, Qt.QueuedConnection)
        self.worker.finished.connect(self.worker.deleteLater, Qt.QueuedConnection)
        self.worker.finished.connect(thread.deleteLater, Qt.QueuedConnection)
        self.worker.progress.connect(self._transferProgress, Qt.QueuedConnection)
        self.worker.started.connect(self._transferStart, Qt.QueuedConnection)
        self.worker.status.connect(self._transferStatus, Qt.QueuedConnection)
        
        thread.start()
        
    @QtCore.Slot(str)
    def _transferStatus(self, msg):
        'Transfer Status Message'
        self._txtStatus.append(msg)
        
    @QtCore.Slot(int)
    def _transferStart(self, nBytes):
        'Transfer Thread Stated'
        if nBytes > 0:
            self._pbTransfer.setMaximum(nBytes)
        else:
            self._pbTransfer.setMaximum(100)
        self._pbTransfer.reset()
        
    @QtCore.Slot(int)
    def _transferProgress(self, nTransferred):
        'Transfer Thread Progress Event'
        self._pbTransfer.setValue(nTransferred)
        
    @QtCore.Slot(models.Dive)
    def _transferParsed(self, dive):
        'Transfer Thread Parsed Dive'
        self._logbook.session.add(dive)
        
    @QtCore.Slot()
    def _transferFinished(self):
        'Transfer Thread Finished'
        self._logbook.session.commit()
        
        self._txtLogbook.setEnabled(True)
        self._btnBrowse.setEnabled(True)
        self._cbxComputer.setEnabled(True)
        self._btnAddComputer.setEnabled(True)
        self._btnRemoveComputer.setEnabled(True)
        self._btnTransfer.setEnabled(True)
        self._btnExit.setEnabled(True)
Esempio n. 7
0
class DetectorWizardPage(_ExpandableOptionsWizardPage):

    class _DetectorComboBoxModel(QAbstractListModel):

        def __init__(self):
            QAbstractListModel.__init__(self)
            self._detectors = []

        def rowCount(self, *args, **kwargs):
            return len(self._detectors)

        def data(self, index, role=Qt.DisplayRole):
            if not index.isValid() or \
                    not (0 <= index.row() < self.rowCount()):
                return None

            if role == Qt.TextAlignmentRole:
                return Qt.AlignCenter

            if role != Qt.DisplayRole:
                return None

            return self._detectors[index.row()]['text']

        def setData(self, index, value, role=Qt.EditRole):
            if not index.isValid() or \
                    not (0 <= index.row() < len(self._detectors)):
                return False

            row = index.row()
            self._detectors[row] = value

            self.dataChanged.emit(index, index)
            return True

        def insertRows(self, row, count=1, parent=None):
            if count == 0:
                return False
            if parent is None:
                parent = QModelIndex()
            self.beginInsertRows(QModelIndex(), row, row + count - 1)

            for _ in range(count):
                value = {'text': '', 'class': None, 'widget_class': None}
                self._detectors.insert(row, value)

            self.endInsertRows()
            return True

        def removeRows(self, row, count=1, parent=None):
            if count == 0:
                return False
            if parent is None:
                parent = QModelIndex()
            self.beginRemoveRows(QModelIndex(), row, row + count - 1)

            for index in reversed(range(row, row + count)):
                self._detectors.pop(index)

            self.endRemoveRows()
            return True

        def append(self, text, clasz, widget_class):
            self.insert(self.rowCount(), text, clasz, widget_class)

        def insert(self, row, text, clasz, widget_class):
            self.insertRows(row)
            value = {'text': text, 'class': clasz, 'widget_class': widget_class}
            self.setData(self.createIndex(row, 0), value)

        def clear(self):
            self.removeRows(0, self.rowCount())

        def widget_class(self, index):
            return self._detectors[index]['widget_class']

    class _DetectorTableModel(QAbstractTableModel):

        def __init__(self):
            QAbstractTableModel.__init__(self)
            self._detectors = []

        def rowCount(self, *args, **kwargs):
            return len(self._detectors)

        def columnCount(self, *args, **kwargs):
            return 2

        def data(self, index, role=Qt.DisplayRole):
            if not index.isValid() or \
                    not (0 <= index.row() < len(self._detectors)):
                return None

            if role == Qt.TextAlignmentRole:
                return Qt.AlignCenter

            if role == Qt.DisplayRole or role == Qt.ToolTipRole:
                key, detector = self._detectors[index.row()]
                column = index.column()
                if column == 0:
                    return key
                elif column == 1:
                    return str(detector) if detector is not None else ''

            return None

        def headerData(self, section , orientation, role):
            if role != Qt.DisplayRole:
                return None
            if orientation == Qt.Horizontal:
                if section == 0:
                    return 'Key'
                elif section == 1:
                    return 'Detector'
            elif orientation == Qt.Vertical:
                return str(section + 1)

        def flags(self, index):
            if not index.isValid():
                return Qt.ItemIsEnabled

            return Qt.ItemFlags(QAbstractTableModel.flags(self, index) |
                                Qt.ItemIsEditable)

        def setData(self, index, value, role=Qt.EditRole):
            if not index.isValid() or \
                    not (0 <= index.row() < len(self._detectors)):
                return False

            row = index.row()
            column = index.column()
            self._detectors[row][column] = value

            self.dataChanged.emit(index, index)
            return True

        def insertRows(self, row, count=1, parent=None):
            if count == 0:
                return False
            if parent is None:
                parent = QModelIndex()
            self.beginInsertRows(parent, row, row + count - 1)

            for _ in range(count):
                self._detectors.insert(row, ['untitled', None])

            self.endInsertRows()
            return True

        def removeRows(self, row, count=1, parent=None):
            if count == 0:
                return False
            if parent is None:
                parent = QModelIndex()
            self.beginRemoveRows(parent, row, row + count - 1)

            for index in reversed(range(row, row + count)):
                self._detectors.pop(index)

            self.endRemoveRows()
            return True

        def append(self, key, detector):
            self.insert(self.rowCount(), key, detector)

        def insert(self, index, key, detector):
            self.insertRows(index)
            self.setData(self.createIndex(index, 0), key)
            self.setData(self.createIndex(index, 1), detector)

        def modify(self, index, key, detector):
            self.setData(self.createIndex(index, 0), key)
            self.setData(self.createIndex(index, 1), detector)

        def clear(self):
            self.removeRows(0, self.rowCount())

        def detectors(self):
            detectors = {}
            for key, detector in self._detectors:
                if detector is not None:
                    detectors.setdefault(key, []).append(detector)
            return detectors

        def detector(self, index):
            return self._detectors[index.row()][1]

        def key(self, index):
            return self._detectors[index.row()][0]

    class _DetectorTableDelegate(QItemDelegate):

        def __init__(self, parent=None):
            QItemDelegate.__init__(self, parent)

        def createEditor(self, parent, option, index):
            column = index.column()
            if column == 0:
                editor = QLineEdit(parent)
                editor.setValidator(QRegExpValidator(QRegExp(r"^(?!\s*$).+")))
                return editor
            elif column == 1:
                return None

        def setEditorData(self, editor, index):
            column = index.column()
            if column == 0:
                key = index.model().data(index, Qt.DisplayRole)
                editor.setText(key)

        def setModelData(self, editor, model, index):
            column = index.column()
            if column == 0:
                if not editor.hasAcceptableInput():
                    return
                model.setData(index, editor.text())

    def __init__(self, options, parent=None):
        _ExpandableOptionsWizardPage.__init__(self, options, parent)
        self.setTitle('Detector')

    def _initUI(self):
        # Variables
        self._widgets = {}
        tbl_model = self._DetectorTableModel()

        # Widgets
        self._cb_detector = QComboBox()
        self._cb_detector.setModel(self._DetectorComboBoxModel())

        btn_detector_add = QPushButton()
        btn_detector_add.setIcon(getIcon("list-add"))

        self._tbl_detector = QTableView()
        self._tbl_detector.setModel(tbl_model)
        self._tbl_detector.setItemDelegate(self._DetectorTableDelegate())
        header = self._tbl_detector.horizontalHeader()
        header.setResizeMode(1, QHeaderView.Stretch)
        policy = self._tbl_detector.sizePolicy()
        policy.setVerticalStretch(True)
        self._tbl_detector.setSizePolicy(policy)

        tlb_detector = QToolBar()
        spacer = QWidget()
        spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        tlb_detector.addWidget(spacer)
        act_remove = tlb_detector.addAction(getIcon("list-remove"), "Remove detector")
        act_clear = tlb_detector.addAction(getIcon("edit-clear"), "Clear")

        # Layouts
        layout = _ExpandableOptionsWizardPage._initUI(self)

        sublayout = QHBoxLayout()
        sublayout.addWidget(self._cb_detector, 1)
        sublayout.addWidget(btn_detector_add)
        layout.addRow("Select", sublayout)

        layout.addRow(self._tbl_detector)
        layout.addRow(tlb_detector)

        # Signals
        btn_detector_add.released.connect(self._onDetectorAdd)
        act_remove.triggered.connect(self._onDetectorRemove)
        act_clear.triggered.connect(self._onDetectorClear)

        self._tbl_detector.doubleClicked.connect(self._onDetectorDoubleClicked)

        tbl_model.dataChanged.connect(self.valueChanged)
        tbl_model.rowsInserted.connect(self.valueChanged)
        tbl_model.rowsRemoved.connect(self.valueChanged)

        return layout

    def _onDetectorAdd(self):
        index = self._tbl_detector.selectionModel().currentIndex()
        tbl_model = self._tbl_detector.model()
        cb_model = self._cb_detector.model()

        widget_class = cb_model.widget_class(self._cb_detector.currentIndex())
        wdg_detector = widget_class()

        dialog = _DetectorDialog(wdg_detector)
        if not dialog.exec_():
            return

        tbl_model.insert(index.row() + 1, dialog.key(), dialog.detector())

    def _onDetectorRemove(self):
        selection = self._tbl_detector.selectionModel().selection().indexes()
        if len(selection) == 0:
            QMessageBox.warning(self, "Detector", "Select a row")
            return

        tbl_model = self._tbl_detector.model()
        for row in sorted(map(methodcaller('row'), selection), reverse=True):
            tbl_model.removeRow(row)

    def _onDetectorClear(self):
        model = self._tbl_detector.model()
        for row in reversed(range(model.rowCount())):
            model.removeRow(row)

    def _onDetectorDoubleClicked(self, index):
        if index.column() != 1:
            return

        tbl_model = self._tbl_detector.model()
        key = tbl_model.key(index)
        detector = tbl_model.detector(index)
        widget_class = self._widgets[detector.__class__]
        wdg_detector = widget_class()
        wdg_detector.setValue(detector)

        dialog = _DetectorDialog(wdg_detector, key)
        if not dialog.exec_():
            return

        tbl_model.modify(index.row(), dialog.key(), dialog.detector())

    def initializePage(self):
        _ExpandableOptionsWizardPage.initializePage(self)

        tbl_model = self._tbl_detector.model()
        cb_model = self._cb_detector.model()

        # Clear
        self._widgets.clear()
        tbl_model.clear()
        cb_model.clear()

        # Populate combo box
        it = self._iter_widgets('pymontecarlo.ui.gui.options.detector',
                                'DETECTORS')
        for clasz, widget_class, programs in it:
            widget = widget_class()
            self._widgets[clasz] = widget_class

            program_text = ', '.join(map(attrgetter('name'), programs))
            text = '{0} ({1})'.format(widget.accessibleName(), program_text)

            cb_model.append(text, clasz, widget_class)

            del widget

        self._cb_detector.setCurrentIndex(0)

        # Add detector(s)
        for key, detectors in self.options().detectors.items():
            detectors = np.array(detectors, ndmin=1)
            for detector in detectors:
                if not detector.__class__ in self._widgets:
                    continue
                tbl_model.append(key, detector)

    def validatePage(self):
        tbl_model = self._tbl_detector.model()
        if tbl_model.rowCount() == 0:
            return False

        self.options().detectors.clear()
        self.options().detectors.update(tbl_model.detectors())

        return True

    def expandCount(self):
        if self._tbl_detector.model().rowCount() == 0:
            return 0

        try:
            count = 1

            for detectors in self._tbl_detector.model().detectors().values():
                count *= len(detectors)
                for detector in detectors:
                    count *= len(expand(detector))

            return count
        except:
            return 0
Esempio n. 8
0
class ModelWizardPage(_ExpandableOptionsWizardPage):

    class _ModelTypeComboBoxModel(QAbstractListModel):

        def __init__(self, model_types=None):
            QAbstractListModel.__init__(self)
            if model_types is None:
                model_types = []
            self._model_types = list(model_types)

        def rowCount(self, *args, **kwargs):
            return len(self._model_types)

        def data(self, index, role=Qt.DisplayRole):
            if not index.isValid() or \
                    not (0 <= index.row() < self.rowCount()):
                return None

            if role == Qt.TextAlignmentRole:
                return Qt.AlignCenter

            if role != Qt.DisplayRole:
                return None

            return str(self._model_types[index.row()])

        def modelType(self, index):
            return self._model_types[index]

    class _ModelComboBoxModel(QAbstractListModel):

        def __init__(self, models_text=None):
            QAbstractListModel.__init__(self)

            if models_text is None:
                models_text = {}
            self._models_text = models_text.copy()

            self._models = {}
            for model in models_text.keys():
                self._models.setdefault(model.type, []).append(model)

            self._model_type = None

        def rowCount(self, *args, **kwargs):
            return len(self._models.get(self._model_type, []))

        def data(self, index, role=Qt.DisplayRole):
            if not index.isValid() or \
                    not (0 <= index.row() < self.rowCount()):
                return None

            if role == Qt.TextAlignmentRole:
                return Qt.AlignCenter

            if role != Qt.DisplayRole:
                return None

            model = self._models[self._model_type][index.row()]
            return self._models_text[model]

        def setModelType(self, model_type):
            self._model_type = model_type
            self.reset()

        def model(self, index):
            return self._models[self._model_type][index]

        def add(self, model):
            if model not in self._models_text:
                raise ValueError('No text defined for model: %s' % model)
            self._models[model.type].append(model)
            self.reset()

        def remove(self, model):
            self._models[model.type].remove(model)
            self.reset()

    def __init__(self, options, parent=None):
        _ExpandableOptionsWizardPage.__init__(self, options, parent)
        self.setTitle('Model')

    def _initUI(self):
        # Widgets
        self._cb_model_type = QComboBox()
        self._cb_model_type.setModel(self._ModelTypeComboBoxModel())

        self._cb_model = QComboBox()
        self._cb_model.setModel(self._ModelComboBoxModel())
        self._cb_model.setMaxVisibleItems(10)

        btn_model_add = QPushButton()
        btn_model_add.setIcon(getIcon("list-add"))

        self._tbl_model = ModelTableWidget()

        tlb_model = QToolBar()
        spacer = QWidget()
        spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        tlb_model.addWidget(spacer)
        act_remove = tlb_model.addAction(getIcon("list-remove"), "Remove model")
        act_clear = tlb_model.addAction(getIcon("edit-clear"), "Clear")

        # Layouts
        layout = _ExpandableOptionsWizardPage._initUI(self)

        sublayout = QHBoxLayout()
        sublayout.addWidget(self._cb_model_type, 1)
        sublayout.addWidget(self._cb_model, 1)
        sublayout.addWidget(btn_model_add)
        layout.addRow("Select", sublayout)

        layout.addRow(self._tbl_model)
        layout.addRow(tlb_model)

        # Signals
        btn_model_add.released.connect(self._onModelAdd)
        act_remove.triggered.connect(self._onModelRemove)
        act_clear.triggered.connect(self._onModelClear)

        self._cb_model_type.currentIndexChanged.connect(self._onModelTypeChanged)

        self._tbl_model.dataChanged.connect(self.valueChanged)

        return layout

    def _onModelTypeChanged(self):
        cb_model = self._cb_model.model()

        index = self._cb_model_type.currentIndex()
        model_type = self._cb_model_type.model().modelType(index)
        cb_model.setModelType(model_type)

        self._cb_model.setCurrentIndex(0)

    def _onModelAdd(self):
        cb_model = self._cb_model.model()

        index = self._cb_model.currentIndex()
        try:
            model = cb_model.model(index)
        except IndexError: # No entry
            return
        self._tbl_model.addModel(model)
        cb_model.remove(model) # Remove model from combo box

        self._cb_model.setCurrentIndex(index)

    def _onModelRemove(self):
        models = self._tbl_model.currentModels()
        if len(models) == 0:
            QMessageBox.warning(self, "Model", "Select a row")
            return

        cb_model = self._cb_model.model()

        for model in models:
            cb_model.add(model) # Show model in combo box
            self._tbl_model.removeModel(model)

        if self._cb_model.currentIndex() < 0:
            self._cb_model.setCurrentIndex(0)

    def _onModelClear(self):
        models = self._tbl_model.models()
        cb_model = self._cb_model.model()

        for model in models:
            cb_model.add(model) # Show model in combo box
            self._tbl_model.removeModel(model)

        if self._cb_model.currentIndex() < 0:
            self._cb_model.setCurrentIndex(0)

    def _iter_models(self):
        allmodels = {}
        default_models = {}
        for program in self.options().programs:
            converter = program.converter_class

            for models in converter.MODELS.values():
                for model in models:
                    allmodels.setdefault(model, set()).add(program)

                    if model == converter.DEFAULT_MODELS[model.type]:
                        default_models.setdefault(model, set()).add(program)

        for model, programs in allmodels.items():
            defaults = default_models.get(model, [])
            yield model, programs, defaults

    def initializePage(self):
        _ExpandableOptionsWizardPage.initializePage(self)

        # Populate combo boxes
        model_types = set()
        models_text = {}

        for model, programs, defaults in self._iter_models():
            programs_text = []
            for program in programs:
                program_text = program.name
                if program in defaults:
                    program_text += '*'
                programs_text.append(program_text)

            program_text = ', '.join(programs_text)
            text = '{0} ({1})'.format(str(model), program_text)

            model_types.add(model.type)
            models_text[model] = text

        model_types = sorted(model_types, key=attrgetter('name'))
        cb_model_type = self._ModelTypeComboBoxModel(model_types)
        self._cb_model_type.setModel(cb_model_type)
        self._cb_model_type.setCurrentIndex(0)

        cb_model = self._ModelComboBoxModel(models_text)
        self._cb_model.setModel(cb_model)
        cb_model.setModelType(cb_model_type.modelType(0))
        self._cb_model.setCurrentIndex(0)

        # Add model(s)
        self._tbl_model.clear()
        self._tbl_model.addModels(self.options().models)

    def validatePage(self):
        self.options().models.clear()
        for model in self._tbl_model.models():
            self.options().models.add(model)

        return True

    def expandCount(self):
        try:
            count = 1

            models = {}
            for model in self._tbl_model.models():
                models.setdefault(model.type, []).append(model)

            for values in models.values():
                count *= len(values)

            return count
        except:
            return 0