예제 #1
0
    def setupTabs(self):
        """ Setup the various tabs in the AddressWidget. """
        groups = ["ABC", "DEF", "GHI", "JKL", "MNO", "PQR", "STU", "VW", "XYZ"]

        for group in groups:
            proxyModel = QSortFilterProxyModel(self)
            proxyModel.setSourceModel(self.tableModel)
            proxyModel.setDynamicSortFilter(True)

            tableView = QTableView()
            tableView.setModel(proxyModel)
            tableView.setSortingEnabled(True)
            tableView.setSelectionBehavior(QAbstractItemView.SelectRows)
            tableView.horizontalHeader().setStretchLastSection(True)
            tableView.verticalHeader().hide()
            tableView.setEditTriggers(QAbstractItemView.NoEditTriggers)
            tableView.setSelectionMode(QAbstractItemView.SingleSelection)

            # This here be the magic: we use the group name (e.g. "ABC") to
            # build the regex for the QSortFilterProxyModel for the group's
            # tab. The regex will end up looking like "^[ABC].*", only 
            # allowing this tab to display items where the name starts with 
            # "A", "B", or "C". Notice that we set it to be case-insensitive.
            reFilter = "^[%s].*" % group

            proxyModel.setFilterRegExp(QRegExp(reFilter, Qt.CaseInsensitive))
            proxyModel.setFilterKeyColumn(0) # Filter on the "name" column
            proxyModel.sort(0, Qt.AscendingOrder)

            tableView.selectionModel().selectionChanged.connect(self.selectionChanged)

            self.addTab(tableView, group)
예제 #2
0
파일: gui05.py 프로젝트: yysynergy/pparser
class skillsWindow(QDialog):
    def __init__(self, dataModel, oberTablo):
        QDialog.__init__(self)
        self.setWindowTitle('All Skills')
        self.setWindowIcon(QIcon('elance.ico'))
        self.oberTablo = oberTablo
        #create & configure tablewiew
        self.table_view = QTableView()
        self.table_view.setModel(dataModel)
        self.table_view.setSortingEnabled(True)
        self.table_view.sortByColumn(1, Qt.DescendingOrder)
        self.table_view.resizeColumnsToContents()
        self.table_view.resizeRowsToContents()
        #http://stackoverflow.com/questions/7189305/set-optimal-size-of-a-dialog-window-containing-a-tablewidget
        #http://stackoverflow.com/questions/8766633/how-to-determine-the-correct-size-of-a-qtablewidget
        w = 0
        w += self.table_view.contentsMargins().left() +\
             self.table_view.contentsMargins().right() +\
             self.table_view.verticalHeader().width()
        w += qApp.style().pixelMetric(QStyle.PM_ScrollBarExtent)
        for i in range(len(self.table_view.model().header)):
            w += self.table_view.columnWidth(i)
        self.table_view.horizontalHeader().setStretchLastSection(True)
        self.table_view.setMinimumWidth(w)
        
        # create two buttons
        self.findEntries = QPushButton('Find entries')
        self.findEntries.clicked.connect(self.ApplyFilterToMainList)
        self.cancel = QPushButton('Cancel')
        self.cancel.clicked.connect(self.winClose)
        
        self.mainLayout = QGridLayout()
        self.mainLayout.addWidget(self.table_view, 0,0,1,3)
        self.mainLayout.addWidget(self.findEntries, 1,0)
        self.mainLayout.addWidget(self.cancel, 1,2)
        self.setLayout(self.mainLayout)
        self.show()
    
    def ApplyFilterToMainList(self):
        selection = self.table_view.selectionModel().selection()
        skills = []
        for selRange in selection:
            for index in selRange.indexes():
                skill = index.model().data(index, Qt.DisplayRole)
                skills.append(skill)
        self.oberTablo.model().emit(SIGNAL("modelAboutToBeReset()"))
        self.oberTablo.model().criteria = {'Skills':skills}
        self.oberTablo.model().emit(SIGNAL("modelReset()"))
        self.close()
    
    def winClose(self):
        self.close()
예제 #3
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
예제 #4
0
class LayerListWidget(_ParameterWidget):

    def __init__(self, parameter, parent=None):
        _ParameterWidget.__init__(self, parameter, parent)

        # Variables
        model = _LayerModel()
        self._material_class = Material

        # Actions
        act_add = QAction(getIcon("list-add"), "Add layer", self)
        act_remove = QAction(getIcon("list-remove"), "Remove layer", self)
        act_clean = QAction(getIcon('edit-clear'), "Clear", self)

        # Widgets
        self._cb_unit = UnitComboBox('m')
        self._cb_unit.setUnit('um')

        self._tbl_layers = QTableView()
        self._tbl_layers.setModel(model)
        self._tbl_layers.setItemDelegate(_LayerDelegate())
        header = self._tbl_layers.horizontalHeader()
        header.setResizeMode(QHeaderView.Stretch)
        header.setStyleSheet('color: blue')

        self._tlb_layers = QToolBar()
        spacer = QWidget()
        spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self._tlb_layers.addWidget(spacer)
        self._tlb_layers.addAction(act_add)
        self._tlb_layers.addAction(act_remove)
        self._tlb_layers.addAction(act_clean)

        # Layouts
        layout = QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)

        sublayout = QHBoxLayout()
        sublayout.addStretch()
        sublayout.addWidget(QLabel('Thickness unit'))
        sublayout.addWidget(self._cb_unit)
        layout.addLayout(sublayout)

        layout.addWidget(self._tbl_layers)
        layout.addWidget(self._tlb_layers)
        self.setLayout(layout)

        # Signals
        self.valuesChanged.connect(self._onChanged)
        self.validationRequested.connect(self._onChanged)

        act_add.triggered.connect(self._onAdd)
        act_remove.triggered.connect(self._onRemove)
        act_clean.triggered.connect(self._onClear)

        self._tbl_layers.doubleClicked.connect(self._onDoubleClicked)

        model.dataChanged.connect(self.valuesChanged)
        model.rowsInserted.connect(self.valuesChanged)
        model.rowsRemoved.connect(self.valuesChanged)

        self.validationRequested.emit()

    def _onChanged(self):
        if self.hasAcceptableInput():
            self._tbl_layers.setStyleSheet("background: none")
        else:
            self._tbl_layers.setStyleSheet("background: pink")

    def _onDoubleClicked(self, index):
        if index.column() != 0:
            return

        model = self._tbl_layers.model()
        materials = model.materials(index)

        if len(materials) == 0:
            dialog = get_material_dialog_class(self._material_class)()
        elif len(materials) == 1:
            dialog = get_material_dialog_class(self._material_class)()
            dialog.setValue(materials[0])
        else:
            dialog = MaterialListDialog()
            dialog.setMaterialClass(self._material_class)
            dialog.setValues(materials)

        dialog.setReadOnly(self.isReadOnly())

        if not dialog.exec_():
            return

        model.setData(index, dialog.values())

    def _onAdd(self):
        index = self._tbl_layers.selectionModel().currentIndex()
        model = self._tbl_layers.model()
        model.insertRows(index.row() + 1)

        # Show material dialog right away
        index = model.createIndex(index.row() + 1, 0)
        self._onDoubleClicked(index)

    def _onRemove(self):
        selection = self._tbl_layers.selectionModel().selection().indexes()
        if len(selection) == 0:
            QMessageBox.warning(self, "Layer", "Select a row")
            return

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

    def _onClear(self):
        model = self._tbl_layers.model()
        for row in reversed(range(model.rowCount())):
            model.removeRow(row)

    def values(self):
        factor = self._cb_unit.factor()

        layers = []
        for material, thickness in self._tbl_layers.model().layers():
            if not material or not thickness:
                continue
            thickness_m = np.array(thickness, ndmin=1) * factor
            layers.append(_MockLayer(material, thickness_m))

        return layers

    def setValues(self, layers):
        layers = np.array(layers, ndmin=1)
        factor = self._cb_unit.factor()

        model = self._tbl_layers.model()
        model.removeRows(0, model.rowCount())
        model.insertRows(0, len(layers))

        for i, layer in enumerate(layers):
            model.setData(model.index(i, 0), layer.material)
            model.setData(model.index(i, 1), layer.thickness_m / factor)

    def isReadOnly(self):
        return not self._cb_unit.isEnabled() and \
            not self._tlb_layers.isVisible()

    def setReadOnly(self, state):
        self._cb_unit.setEnabled(not state)
        self._tlb_layers.setVisible(not state)

        style = 'color: none' if state else 'color: blue'
        self._tbl_layers.horizontalHeader().setStyleSheet(style)
        self._tbl_layers.itemDelegate().setReadOnly(state)

    def setMaterialClass(self, clasz):
        self._material_class = clasz
예제 #5
0
class TemplateSelectDialog(QDialog):
    def refresh_templates_list(self):

        documents = documents_service.all_templates()

        self.model.removeRows(0, self.model.rowCount())

        if documents:
            for doc in sorted(list(documents), key=lambda d: d.filename):
                self._add_one_document(doc.filename, doc.template_document_id,
                                       doc.file_size, doc.description)

    def __init__(self, parent=None):
        super(TemplateSelectDialog, self).__init__(parent)

        self.setWindowTitle(_("Select a template"))

        self.template_id = []

        self.model = QStandardItemModel()
        self.view = QTableView()
        self.view.setModel(self.model)
        self.view.verticalHeader().setVisible(False)
        self.view.horizontalHeader().setVisible(False)
        self.view.setMinimumSize(500, 200)
        self.view.setShowGrid(True)
        self.view.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.view.setSelectionBehavior(QAbstractItemView.SelectRows)

        l = QVBoxLayout()

        l.addWidget(QLabel(_("Please select one or more template.")))
        self.view.doubleClicked.connect(self._doubleClicked)

        l.addWidget(QLabel(u"<h3>{}</h3>".format(_("Documents Templates"))))
        l.addWidget(self.view)

        self.buttons = QDialogButtonBox()
        self.buttons.addButton(QDialogButtonBox.StandardButton.Cancel)
        self.buttons.addButton(QDialogButtonBox.Ok)
        self.buttons.accepted.connect(self.accept)
        self.buttons.rejected.connect(self.reject)

        l.addWidget(self.buttons)

        self.setLayout(l)

    def _add_one_document(self, file_name, doc_id, file_size, description):
        """ Adds a document to the list
        """

        # file_name is either an absolute path or just a file name
        # If it is an absolute path, then the file is expected
        # to exist locally (at it absolute path location of course).
        # If not, then the file is expected to be a remote file
        # and shall be downloaded before opening.

        mainlog.debug(u"{} {} {} {}".format(file_name, doc_id, file_size,
                                            description))
        short_name = file_name
        if os.path.isabs(file_name):
            short_name = os.path.basename(file_name)
            if not os.path.isfile(file_name):
                raise Exception(u"The file {} doesn't exist".format(file_name))

        items = [QStandardItem(short_name)]
        items.append(QStandardItem(description))

        self.model.appendRow(items)
        self.model.setData(self.model.index(self.model.rowCount() - 1, 0),
                           doc_id, Qt.UserRole + 1)

        self.view.horizontalHeader().setResizeMode(0, QHeaderView.Stretch)
        self.view.horizontalHeader().setResizeMode(1, QHeaderView.Stretch)
        self.view.resizeRowsToContents()

    @Slot()
    def accept(self):
        selected_rows = self.view.selectionModel().selectedRows()
        if selected_rows:
            self.template_id = []
            for row in selected_rows:
                ndx_row = row.row()
                self.template_id.append(
                    self.model.data(self.model.index(ndx_row, 0),
                                    Qt.UserRole + 1))
        else:
            self.template_id = []
        return super(TemplateSelectDialog, self).accept()

    @Slot()
    def reject(self):
        return super(TemplateSelectDialog, self).reject()

    @Slot(QModelIndex)
    def _doubleClicked(self, ndx):
        self.accept()
예제 #6
0
class ModelTableWidget(QWidget):

    dataChanged = Signal(QModelIndex, QModelIndex)

    class _ModelTableModel(QAbstractTableModel):
        def __init__(self):
            QAbstractTableModel.__init__(self)
            self._models = []

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

        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._models)):
                return None

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

            model = self._models[index.row()]
            if model is None:
                return ""

            if role == Qt.DisplayRole or role == Qt.ToolTipRole:
                column = index.column()
                if column == 0:
                    return str(model.type)
                elif column == 1:
                    return str(model)

            return None

        def headerData(self, section, orientation, role):
            if role != Qt.DisplayRole:
                return None
            if orientation == Qt.Horizontal:
                if section == 0:
                    return "Type"
                elif section == 1:
                    return "Model"
            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))

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

            row = index.row()
            self._models[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._models.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._models.pop(index)

            self.endRemoveRows()
            return True

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

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

        def remove(self, model):
            index = self._models.index(model)
            self.removeRows(index)

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

        def models(self):
            models = set(self._models)
            models.discard(None)
            return models

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

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

        # Variables
        model = self._ModelTableModel()

        # Widgets
        self._tbl_models = QTableView()
        self._tbl_models.setModel(model)
        header = self._tbl_models.horizontalHeader()
        header.setResizeMode(QHeaderView.Stretch)
        policy = self._tbl_models.sizePolicy()
        policy.setVerticalStretch(True)
        self._tbl_models.setSizePolicy(policy)
        self._tbl_models.setSelectionMode(QTableView.SelectionMode.MultiSelection)

        # Layouts
        layout = QVBoxLayout()
        layout.addWidget(self._tbl_models)
        self.setLayout(layout)

        # Signals
        model.dataChanged.connect(self.dataChanged)

    def addModel(self, model):
        self._tbl_models.model().append(model)

    def addModels(self, models):
        for model in models:
            self.addModel(model)

    def removeModel(self, model):
        self._tbl_models.model().remove(model)

    def clear(self):
        self._tbl_models.model().clear()

    def models(self):
        return self._tbl_models.model().models()

    def currentModels(self):
        tbl_model = self._tbl_models.model()

        models = []
        for index in self._tbl_models.selectionModel().selection().indexes():
            models.append(tbl_model.model(index))

        return models
예제 #7
0
class PenelopeMaterialDialog(_MaterialDialog):

    def __init__(self, parent=None):
        _MaterialDialog.__init__(self, parent)
        self.setWindowTitle('Material')
        self.setMinimumWidth(1000)

    def _initUI(self):
        # Variables
        model_forcing = _InteractionForcingTableModel()

        # Actions
        act_add_forcing = QAction(getIcon("list-add"), "Add interaction forcing", self)
        act_remove_forcing = QAction(getIcon("list-remove"), "Remove interaction forcing", self)

        # Widgets
        self._lbl_elastic_scattering_c1 = QLabel('C1')
        self._lbl_elastic_scattering_c1.setStyleSheet("color: blue")
        self._txt_elastic_scattering_c1 = MultiNumericalLineEdit()
        self._txt_elastic_scattering_c1.setValidator(_ElasticScatteringValidator())
        self._txt_elastic_scattering_c1.setValues([0.0])

        self._lbl_elastic_scattering_c2 = QLabel('C2')
        self._lbl_elastic_scattering_c2.setStyleSheet("color: blue")
        self._txt_elastic_scattering_c2 = MultiNumericalLineEdit()
        self._txt_elastic_scattering_c2.setValidator(_ElasticScatteringValidator())
        self._txt_elastic_scattering_c2.setValues([0.0])

        self._lbl_cutoff_energy_inelastic = QLabel('Inelastic collisions')
        self._lbl_cutoff_energy_inelastic.setStyleSheet("color: blue")
        self._txt_cutoff_energy_inelastic = MultiNumericalLineEdit()
        self._txt_cutoff_energy_inelastic.setValidator(_CutoffEnergyValidator())
        self._txt_cutoff_energy_inelastic.setValues([50.0])
        self._cb_cutoff_energy_inelastic = UnitComboBox('eV')

        self._lbl_cutoff_energy_bremsstrahlung = QLabel('Bremsstrahlung emission')
        self._lbl_cutoff_energy_bremsstrahlung.setStyleSheet("color: blue")
        self._txt_cutoff_energy_bremsstrahlung = MultiNumericalLineEdit()
        self._txt_cutoff_energy_bremsstrahlung.setValidator(_CutoffEnergyValidator())
        self._txt_cutoff_energy_bremsstrahlung.setValues([50.0])
        self._cb_cutoff_energy_bremsstrahlung = UnitComboBox('eV')

        self._lbl_maximum_step_length = QLabel('Maximum step length')
        self._lbl_maximum_step_length.setStyleSheet("color: blue")
        self._txt_maximum_step_length = MultiNumericalLineEdit()
        self._txt_maximum_step_length.setValidator(_MaximumStepLengthValidator())
        self._txt_maximum_step_length.setValues([1e15])
        self._cb_maximum_step_length_unit = UnitComboBox('m')

        self._tbl_forcing = QTableView()
        self._tbl_forcing.setModel(model_forcing)
        self._tbl_forcing.setItemDelegate(_InteractionForcingDelegate())
        header = self._tbl_forcing.horizontalHeader()
        header.setResizeMode(QHeaderView.Stretch)

        self._tlb_forcing = QToolBar()
        spacer = QWidget()
        spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self._tlb_forcing.addWidget(spacer)
        self._tlb_forcing.addAction(act_add_forcing)
        self._tlb_forcing.addAction(act_remove_forcing)

        # Layouts
        layout = QHBoxLayout()

        layout.addLayout(_MaterialDialog._initUI(self), 1)

        frame = QFrame()
        frame.setFrameShape(QFrame.VLine)
        frame.setFrameShadow(QFrame.Sunken)
        layout.addWidget(frame)

        sublayout = QVBoxLayout()

        box_elastic_scattering = QGroupBox("Elastic scattering")
        boxlayout = QFormLayout()
        boxlayout.addRow(self._lbl_elastic_scattering_c1, self._txt_elastic_scattering_c1)
        boxlayout.addRow(self._lbl_elastic_scattering_c2, self._txt_elastic_scattering_c2)
        box_elastic_scattering.setLayout(boxlayout)
        sublayout.addWidget(box_elastic_scattering)

        box_cutoff_energy = QGroupBox("Cutoff energy")
        boxlayout = QFormLayout()
        boxsublayout = QHBoxLayout()
        boxsublayout.addWidget(self._txt_cutoff_energy_inelastic, 1)
        boxsublayout.addWidget(self._cb_cutoff_energy_inelastic)
        boxlayout.addRow(self._lbl_cutoff_energy_inelastic, boxsublayout)
        boxsublayout = QHBoxLayout()
        boxsublayout.addWidget(self._txt_cutoff_energy_bremsstrahlung, 1)
        boxsublayout.addWidget(self._cb_cutoff_energy_bremsstrahlung)
        boxlayout.addRow(self._lbl_cutoff_energy_bremsstrahlung, boxsublayout)
        box_cutoff_energy.setLayout(boxlayout)
        sublayout.addWidget(box_cutoff_energy)

        subsublayout = QFormLayout()
        subsubsublayout = QHBoxLayout()
        subsubsublayout.addWidget(self._txt_maximum_step_length, 1)
        subsubsublayout.addWidget(self._cb_maximum_step_length_unit)
        subsublayout.addRow(self._lbl_maximum_step_length, subsubsublayout)
        sublayout.addLayout(subsublayout)

        box_forcing = QGroupBox('Interaction forcing')
        boxlayout = QVBoxLayout()
        boxlayout.addWidget(self._tbl_forcing)
        boxlayout.addWidget(self._tlb_forcing)
        box_forcing.setLayout(boxlayout)
        sublayout.addWidget(box_forcing)

        sublayout.addStretch()

        layout.addLayout(sublayout, 1)

        # Signals
        self._txt_elastic_scattering_c1.textChanged.connect(self._onElasticScatteringC1Changed)
        self._txt_elastic_scattering_c2.textChanged.connect(self._onElasticScatteringC2Changed)
        self._txt_cutoff_energy_inelastic.textChanged.connect(self._onCutoffEnergyInelasticChanged)
        self._txt_cutoff_energy_bremsstrahlung.textChanged.connect(self._onCutoffEnergyBremsstrahlungChanged)
        self._txt_maximum_step_length.textChanged.connect(self._onMaximumStepLengthChanged)

        act_add_forcing.triggered.connect(self._onForcingAdd)
        act_remove_forcing.triggered.connect(self._onForcingRemove)

        return layout

    def _onElasticScatteringC1Changed(self):
        if self._txt_elastic_scattering_c1.hasAcceptableInput():
            self._txt_elastic_scattering_c1.setStyleSheet('background: none')
        else:
            self._txt_elastic_scattering_c1.setStyleSheet('background: pink')

    def _onElasticScatteringC2Changed(self):
        if self._txt_elastic_scattering_c2.hasAcceptableInput():
            self._txt_elastic_scattering_c2.setStyleSheet('background: none')
        else:
            self._txt_elastic_scattering_c2.setStyleSheet('background: pink')

    def _onCutoffEnergyInelasticChanged(self):
        if self._txt_cutoff_energy_inelastic.hasAcceptableInput():
            self._txt_cutoff_energy_inelastic.setStyleSheet('background: none')
        else:
            self._txt_cutoff_energy_inelastic.setStyleSheet('background: pink')

    def _onCutoffEnergyBremsstrahlungChanged(self):
        if self._txt_cutoff_energy_bremsstrahlung.hasAcceptableInput():
            self._txt_cutoff_energy_bremsstrahlung.setStyleSheet('background: none')
        else:
            self._txt_cutoff_energy_bremsstrahlung.setStyleSheet('background: pink')

    def _onMaximumStepLengthChanged(self):
        if self._txt_maximum_step_length.hasAcceptableInput():
            self._txt_maximum_step_length.setStyleSheet('background: none')
        else:
            self._txt_maximum_step_length.setStyleSheet('background: pink')

    def _onForcingAdd(self):
        index = self._tbl_forcing.selectionModel().currentIndex()
        model = self._tbl_forcing.model()
        model.insertRows(index.row() + 1)

    def _onForcingRemove(self):
        selection = self._tbl_forcing.selectionModel().selection().indexes()
        if len(selection) == 0:
            QMessageBox.warning(self, "Interaction forcing", "Select a row")
            return

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

    def _getParametersDict(self):
        params = _MaterialDialog._getParametersDict(self)

        params['c1'] = self._txt_elastic_scattering_c1.values().tolist()
        params['c2'] = self._txt_elastic_scattering_c2.values().tolist()

        wcc = self._txt_cutoff_energy_inelastic.values() * self._cb_cutoff_energy_inelastic.factor()
        params['wcc'] = wcc.tolist()

        wcr = self._txt_cutoff_energy_bremsstrahlung.values() * self._cb_cutoff_energy_bremsstrahlung.factor()
        params['wcr'] = wcr.tolist()

        dsmax = self._txt_maximum_step_length.values() * self._cb_maximum_step_length_unit.factor()
        params['dsmax'] = dsmax.tolist()

        params['forcings'] = \
            self._tbl_forcing.model().interaction_forcings()

        return params

    def _generateName(self, parameters, varied):
        name = parameters.pop('name')
        if name is None:
            name = PenelopeMaterial.generate_name(parameters['composition'])

        parts = [name]
        for key in varied:
            if key == 'composition':
                continue
            elif key == 'forcings':
                forcing = parameters[key][0]
                forcer = forcing.forcer
                wlow = forcing.weight[0]
                whigh = forcing.weight[1]
                parts.append('forcings={0:n}_{1:n}_{2:n}'.format(forcer, wlow, whigh))
            else:
                parts.append('{0:s}={1:n}'.format(key, parameters[key]))
        return '+'.join(parts)

    def _createMaterial(self, parameters, varied):
        mat = _MaterialDialog._createMaterial(self, parameters, varied)

        c1 = parameters['c1']
        c2 = parameters['c2']
        wcc = parameters['wcc']
        wcr = parameters['wcr']
        dsmax = parameters['dsmax']
        forcings = parameters['forcings']

        return PenelopeMaterial(mat.composition, mat.name, mat.density_kg_m3,
                                mat.absorption_energy_eV,
                                elastic_scattering=(c1, c2),
                                cutoff_energy_inelastic_eV=wcc,
                                cutoff_energy_bremsstrahlung_eV=wcr,
                                interaction_forcings=forcings,
                                maximum_step_length_m=dsmax)

    def setValue(self, material):
        _MaterialDialog.setValue(self, material)

        # Elastic scattering
        c1, c2 = material.elastic_scattering
        self._txt_elastic_scattering_c1.setValues(c1)
        self._txt_elastic_scattering_c2.setValues(c2)

        # Cutoff energy
        self._txt_cutoff_energy_inelastic.setValues(material.cutoff_energy_inelastic_eV)
        self._cb_cutoff_energy_inelastic.setUnit('eV')

        self._txt_cutoff_energy_bremsstrahlung.setValues(material.cutoff_energy_bremsstrahlung_eV)
        self._cb_cutoff_energy_bremsstrahlung.setUnit('eV')

        # Maximum step length
        self._txt_maximum_step_length.setValues(material.maximum_step_length_m)
        self._cb_maximum_step_length_unit.setUnit('m')

        # Interaction forcings
        forcings = material.interaction_forcings

        model = self._tbl_forcing.model()
        model.removeRows(0, model.rowCount())
        model.insertRows(1, len(forcings))

        for row, forcing in enumerate(forcings):
            model.setData(model.index(row, 0), forcing.particle)
            model.setData(model.index(row, 1), forcing.collision)
            model.setData(model.index(row, 2), forcing.forcer)
            model.setData(model.index(row, 3), forcing.weight[0])
            model.setData(model.index(row, 4), forcing.weight[1])

    def setReadOnly(self, state):
        _MaterialDialog.setReadOnly(self, state)

        style = 'color: none' if state else 'color: blue'
        self._lbl_elastic_scattering_c1.setStyleSheet(style)
        self._txt_elastic_scattering_c1.setReadOnly(state)

        self._lbl_elastic_scattering_c2.setStyleSheet(style)
        self._txt_elastic_scattering_c2.setReadOnly(state)

        self._lbl_cutoff_energy_inelastic.setStyleSheet(style)
        self._txt_cutoff_energy_inelastic.setReadOnly(state)
        self._cb_cutoff_energy_inelastic.setEnabled(not state)

        self._lbl_cutoff_energy_bremsstrahlung.setStyleSheet(style)
        self._txt_cutoff_energy_bremsstrahlung.setReadOnly(state)
        self._cb_cutoff_energy_bremsstrahlung.setEnabled(not state)

        self._lbl_maximum_step_length.setStyleSheet(style)
        self._txt_maximum_step_length.setReadOnly(state)
        self._cb_maximum_step_length_unit.setEnabled(not state)

        self._tbl_forcing.setEnabled(not state)
        self._tlb_forcing.setVisible(not state)

    def isReadOnly(self):
        return _MaterialDialog.isReadOnly(self) and \
            self._txt_elastic_scattering_c1.isReadOnly() and \
            self._txt_elastic_scattering_c2.isReadOnly() and \
            self._txt_cutoff_energy_inelastic.isReadOnly() and \
            self._txt_cutoff_energy_bremsstrahlung.isReadOnly() and \
            self._txt_maximum_step_length.isReadOnly() and \
            not self._tbl_forcing.isEnabled() and \
            not self._tlb_forcing.isVisible()
예제 #8
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
예제 #9
0
파일: gui05.py 프로젝트: yysynergy/pparser
class MainWindow(QMainWindow):
    def __init__(self, datta):
        QMainWindow.__init__(self)
        self.setWindowTitle('Project Parser')
        appIcon = QIcon('search.png')
        self.setWindowIcon(appIcon)
        self.viewPortBL = QDesktopWidget().availableGeometry().topLeft()
        self.viewPortTR = QDesktopWidget().availableGeometry().bottomRight()
        self.margin = int(QDesktopWidget().availableGeometry().width()*0.1/2)
        self.shirina = QDesktopWidget().availableGeometry().width() - self.margin*2
        self.visota = QDesktopWidget().availableGeometry().height() - self.margin*2
        self.setGeometry(self.viewPortBL.x() + self.margin, self.viewPortBL.y() + self.margin,
                         self.shirina, self.visota)
        # statusbar
        self.myStatusBar = QStatusBar()
        self.setStatusBar(self.myStatusBar)
        
        #lower long layout
        self.lowerLong = QFrame()
        self.detailsLabel = QLabel()
        self.skillsLabel = QLabel()
        self.urlLabel = QLabel()
        self.locationLabel = QLabel()
        self.skillsLabel.setText('skills')
        self.detailsLabel.setWordWrap(True)
        self.la = QVBoxLayout()
        self.la.addWidget(self.detailsLabel)
        self.la.addWidget(self.skillsLabel)
        self.la.addWidget(self.urlLabel)
        self.la.addWidget(self.locationLabel)
        self.lowerLong.setLayout(self.la)

        # table
        self.source_model = MyTableModel(self, datta, ['Id', 'Date', 'Title'])
        self.proxy_model = myTableProxy(self)
        self.proxy_model.setSourceModel(self.source_model)
        self.proxy_model.setDynamicSortFilter(True)
        self.table_view = QTableView()
        self.table_view.setModel(self.proxy_model)
        self.table_view.setAlternatingRowColors(True)
        self.table_view.resizeColumnsToContents()
        self.table_view.resizeRowsToContents()
        self.table_view.horizontalHeader().setStretchLastSection(True)
        self.table_view.setSortingEnabled(True)
        self.table_view.sortByColumn(2, Qt.AscendingOrder)

        # events
        self.selection = self.table_view.selectionModel()
        self.selection.selectionChanged.connect(self.handleSelectionChanged)
        #DO NOT use CreateIndex() method, use index()
        index = self.proxy_model.index(0,0)
        self.selection.select(index, QItemSelectionModel.Select)
        
        self.upperLong = self.table_view  

        # right side widgets
        self.right = QFrame()
        self.la1 = QVBoxLayout()
        self.btnDownload = QPushButton('Download data')
        self.btnDownload.clicked.connect(self.download)
        self.myButton = QPushButton('Show Skillls')
        self.myButton.clicked.connect(self.showAllSkills)
        self.btnSearchByWord = QPushButton('Search by word(s)')
        self.btnSearchByWord.clicked.connect(self.onSearchByWord)
        self.btnResetFilter= QPushButton('Discard Filter')
        self.btnResetFilter.clicked.connect(self.discardFilter)
        self.btnCopyURL = QPushButton('URL to Clipboard')
        self.btnCopyURL.clicked.connect(self.copyToClipboard)
        self.btnExit = QPushButton('Exit')
        self.btnExit.clicked.connect(lambda: sys.exit())
        self.dateTimeStamp = QLabel()
        self.la1.addWidget(self.btnDownload)
        self.la1.addSpacing(10)
        self.la1.addWidget(self.myButton)
        self.la1.addSpacing(10)
        self.la1.addWidget(self.btnSearchByWord)
        self.la1.addSpacing(10)
        self.la1.addWidget(self.btnResetFilter)
        self.la1.addSpacing(10)
        self.la1.addWidget(self.btnCopyURL)
        self.la1.addSpacing(70)
        self.la1.addWidget(self.btnExit)
        self.la1.addStretch(stretch=0)
        self.la1.addWidget(self.dateTimeStamp)
        self.right.setLayout(self.la1)
        self.right.setFrameShape(QFrame.StyledPanel)

        # splitters
        self.horiSplit = QSplitter(Qt.Vertical)
        self.horiSplit.addWidget(self.upperLong)
        self.horiSplit.addWidget(self.lowerLong)
        self.horiSplit.setSizes([self.visota/2, self.visota/2])
        self.vertiSplit = QSplitter(Qt.Horizontal)
        self.vertiSplit.addWidget(self.horiSplit)
        self.vertiSplit.addWidget(self.right)
        self.vertiSplit.setSizes([self.shirina*3/4, self.shirina*1/4])
        self.setCentralWidget(self.vertiSplit)
        
        self.settings = QSettings('elance.ini', QSettings.IniFormat)
        self.settings.beginGroup('DATE_STAMP')
        self.dateTimeStamp.setText('Data actuality: %s' % self.settings.value('date/time'))
        self.settings.endGroup()
        self.statusText = ''

    def handleSelectionChanged(self, selected, deselected):
        for index in selected.first().indexes():
            #print('Row %d is selected' % index.row())
            ind = index.model().mapToSource(index)
            desc = ind.model().mylist[ind.row()]['Description']
            self.detailsLabel.setText(desc)
            skills = ', '.join(ind.model().mylist[ind.row()]['Skills']).strip()
            self.skillsLabel.setText(skills)
            url = ind.model().mylist[ind.row()]['URL']
            self.urlLabel.setText(url)
            location = ind.model().mylist[ind.row()]['Location']
            self.locationLabel.setText(location)
    
    def showAllSkills(self):
        listSkills = []
        for elem in self.source_model.mylist:
            listSkills += elem['Skills']
        allSkills = Counter(listSkills)
        tbl = MyTableModel(self, allSkills.items(), ['Skill', 'Freq'])
        win = skillsWindow(tbl, self.table_view)
        win.exec_()
    
    def discardFilter(self):
        self.table_view.model().emit(SIGNAL("modelAboutToBeReset()"))
        self.table_view.model().criteria = {}
        self.table_view.model().emit(SIGNAL("modelReset()"))
        self.table_view.resizeRowsToContents()
        
    def download(self):
        self.btnDownload.setDisabled(True)
        self.statusLabel = QLabel('Connecting')
        self.progressBar = QProgressBar()
        self.progressBar.setMinimum(0)
        self.progressBar.setMaximum(100)
        self.myStatusBar.addWidget(self.statusLabel, 2)
        self.myStatusBar.addWidget(self.progressBar, 1)
        self.progressBar.setValue(1)
        self.settings.beginGroup('URLS')
        initialLink = self.settings.value('CategoriesDetailed/VahaSelected/InitialLink')
        pagingLink = self.settings.value('CategoriesDetailed/VahaSelected/PagingLink')
        self.settings.endGroup()
        downloader = Downloader(initialLink, pagingLink, 25, 5)
        downloader.messenger.downloadProgressChanged.connect(self.onDownloadProgressChanged)
        downloader.messenger.downloadComplete.connect(self.onDownloadComplete)
        downloader.download()
    
    def onDownloadComplete(self):
        #QMessageBox.information(self, 'Download complete', 'Download complete!', QMessageBox.Ok)
        self.table_view.model().emit(SIGNAL("modelAboutToBeReset()"))
        self.settings.beginGroup('DATE_STAMP')
        self.settings.setValue('date/time', time.strftime('%d-%b-%Y, %H:%M:%S'))
        self.dateTimeStamp.setText('Data actuality: %s' % self.settings.value('date/time'))
        self.settings.endGroup()
        with open("elance.json") as json_file:
            jobDB = json.load(json_file)
        for elem in jobDB:
            words = nltk.tokenize.regexp_tokenize(elem['Title'].lower(), r'\w+')
            elem['Tokens'] = words
            elem['Skills'] = [t.strip() for t in elem['Skills'].split(',')]
        self.source_model.mylist = jobDB
        self.table_view.model().emit(SIGNAL("modelReset()"))
        self.btnDownload.setEnabled(True)
        self.myStatusBar.removeWidget(self.statusLabel)
        self.myStatusBar.removeWidget(self.progressBar)
        self.myStatusBar.showMessage(self.statusText, timeout = 5000)
                
    
    def onDownloadProgressChanged(self, stata):
        self.progressBar.setValue(stata[2])
        #text = 'Processed records{:5d} of{:5d}'.format(percentage[0], percentage[1])
        bajtikov = '{:,}'.format(stata[5])
        self.statusText = 'Processed page{:4d} of{:4d}. \
               Job entries{:5d} of{:5d}. \
               Downloaded{:>12s} Bytes'.format(stata[3], stata[4],
                                              stata[0], stata[1],
                                              bajtikov)
        self.statusLabel.setText(self.statusText)
        
    def copyToClipboard(self):
        clipboard = QApplication.clipboard()
        clipboard.setText(self.urlLabel.text())
        self.myStatusBar.showMessage(self.urlLabel.text(), timeout = 3000)
    
    def onSearchByWord(self):
        text, ok = QInputDialog.getText(self, 'Search the base by word(s)', 'Enter your keyword/phrase to search for:')
        if ok:
            words = [t.strip() for t in nltk.tokenize.regexp_tokenize(text.lower(), r'\w+')]
            self.table_view.model().emit(SIGNAL("modelAboutToBeReset()"))
            self.table_view.model().criteria = {'Description' : words}
            self.table_view.model().emit(SIGNAL("modelReset()"))
예제 #10
0
class TimeTracksOverviewWidget(QWidget):

    @Slot(QModelIndex)
    def cell_entered(self,ndx):
        chrono = datetime.now()

        employee = self.employees[ndx.row()]

        a = max(1,ndx.column())
        d = date(self.base_date.year,self.base_date.month,min(calendar.monthrange(self.base_date.year,self.base_date.month)[1], max(1,ndx.column())))
        # print employee, d

        # Fill in the timetracks report panel ----------------------------

        # First we read the timetrackss and their associated OrderPart

        t_start = datetime(d.year,d.month,d.day,0,0,0,0)
        t_end = datetime(d.year,d.month,d.day,23,59,59,999999)

        # FIXME not abstract enough
        # FIXME This should be in the DAO

        tt = session().query(TimeTrack,OrderPart).\
            join(TaskOnOperation).join(Operation).join(ProductionFile).join(OrderPart).\
            filter(and_(TimeTrack.employee == employee,
                        TimeTrack.start_time >= t_start,
                        TimeTrack.start_time <= t_end)).order_by(asc(TimeTrack.start_time)).all()

        tt += session().query(TimeTrack,Order).join(TaskOnOrder).join(Order).filter(and_(TimeTrack.employee == employee, TimeTrack.start_time >= t_start, TimeTrack.start_time <= t_end)).order_by(asc(TimeTrack.start_time)).all()

        tt += session().query(TimeTrack,OperationDefinition).join(TaskOnNonBillable).join(OperationDefinition).filter(and_(TimeTrack.employee == employee, TimeTrack.start_time >= t_start, TimeTrack.start_time <= t_end)).order_by(asc(TimeTrack.start_time)).all()


        # Fill in the report panel ---------------------------------------

        self.hours_on_day_subframe.set_title(_("Hours worked on the {} by {}").format(date_to_s(d,True),employee.fullname))
        self.controller.model._buildModelFromObjects(map(lambda o : o[0],tt)) #     dao.timetrack_dao.all_for_employee(employee))

        # self.controller.model.row_protect_func = lambda obj,row: obj is not None and obj.managed_by_code

        ndx = 0
        for row in self.controller.model.table:
            if row[1]:
                row[0] = tt[ndx][1] # First column becomes the order
            ndx += 1

        self.controller.view.resizeColumnsToContents()


        # Fill in the time report panel ---------------------------------

        self.pointage_timestamp_prototype.set_fix_date(d)
        self.controller_actions.model._buildModelFromObjects(
            dao.task_action_report_dao.get_reports_for_employee_on_date(employee,d))


    @Slot()
    def refresh_action(self):
        global dao

        self.title_box.set_title(_("Time Records Overview - {}").format(date_to_my(self.base_date,True)))


        self.employees = dao.employee_dao.all()
        day_max = calendar.monthrange(self.base_date.year,self.base_date.month)[1]
        t_start = datetime(self.base_date.year,self.base_date.month,1)
        t_end   = datetime(self.base_date.year,self.base_date.month,day_max,23,59,59,999999)


        self._table_model.setRowCount( len(self.employees))
        self._table_model.setColumnCount( 1+day_max)

        headers = QStandardItemModel(1, 1+day_max)
        headers.setHeaderData(0, Qt.Orientation.Horizontal, _("Employee"))
        for i in range(day_max):
            headers.setHeaderData(i+1, Qt.Orientation.Horizontal, "{}".format(i+1))
        self.headers_view.setModel(headers) # qt's doc : The view does *not* take ownership
        self.header_model = headers

        row = 0
        for employee in self.employees:
            # mainlog.debug(u"refresh action employee {}".format(employee))

            self._table_model.setData(self._table_model.index(row,0),employee.fullname,Qt.DisplayRole) # FIXME Use a delegate
            self._table_model.setData(self._table_model.index(row,0),employee,Qt.UserRole) # FIXME Use a delegate

            tracks = session().query(TimeTrack).filter(and_(TimeTrack.employee_id == employee.employee_id, TimeTrack.start_time >= t_start,TimeTrack.start_time <= t_end)).all()

            # One bucket per day
            buckets = [0] * day_max
            for t in tracks:
                mainlog.debug("Bucket {}".format(t))
                buckets[t.start_time.day - 1] += t.duration

            for b in range(len(buckets)):
                if buckets[b] != 0:
                    self._table_model.setData(self._table_model.index(row,b+1),duration_to_s(buckets[b]),Qt.DisplayRole)
                else:
                    self._table_model.setData(self._table_model.index(row,b+1),None,Qt.DisplayRole)

                if buckets[b] >= 0:
                    # Clear the background
                    self._table_model.setData(self._table_model.index(row,b+1),None,Qt.BackgroundRole)
                else:
                    self._table_model.setData(self._table_model.index(row,b+1),QBrush(QColor(255,128,128)),Qt.TextColorRole)

                self._table_model.setData(self._table_model.index(row,b+1),Qt.AlignRight,Qt.TextAlignmentRole)
            row += 1


        # Compute all mondays indices
        monday = 0
        if t_start.weekday() > 0:
            monday = 7 - t_start.weekday()
        all_mondays = []

        while monday < day_max:
            all_mondays.append(monday)
            monday += 7

        today = date.today()

        for row in range(len(self.employees)):
            # Mark mondays
            for col in all_mondays:
                # col + 1 to account for the employee column
                self._table_model.setData(self._table_model.index(row,col + 1),QBrush(QColor(230,230,255)),Qt.BackgroundRole)

            # Mark today
            if today.month == self.base_date.month and today.year == self.base_date.year:
                self._table_model.setData(self._table_model.index(row,today.day),QBrush(QColor(255,255,128)),Qt.BackgroundRole)

        #for i in range(len(all_mondays)):
        self.table_view.resizeColumnsToContents()

        # mainlog.debug("Reset selection")
        ndx = self.table_view.currentIndex()

        self.table_view.selectionModel().clear()
        # self.table_view.selectionModel().clearSelection()
        # self.table_view.selectionModel().select( self.table_view.model().index(ndx.row(),ndx.column()), QItemSelectionModel.Select)
        # self.table_view.selectionModel().select( self.table_view.model().index(ndx.row(),ndx.column()), QItemSelectionModel.Select)
        self.table_view.selectionModel().setCurrentIndex( self.table_view.model().index(ndx.row(),ndx.column()), QItemSelectionModel.Select)

        # self.cell_entered(self.table_view.currentIndex())


    @Slot()
    def month_today(self):
        self.base_date = date.today()
        self.refresh_action()


    @Slot()
    def month_before(self):
        m = self.base_date.month

        if m > 1:
            self.base_date = date(self.base_date.year,m - 1,self.base_date.day)
        else:
            self.base_date = date(self.base_date.year - 1,12,self.base_date.day)
        self.refresh_action()

    @Slot()
    def month_after(self):
        m = self.base_date.month

        if self.base_date.year < date.today().year or m < date.today().month:
            if m < 12:
                self.base_date = date(self.base_date.year,m + 1,self.base_date.day)
            else:
                self.base_date = date(self.base_date.year + 1,1,self.base_date.day)
            self.refresh_action()

    @Slot()
    def edit_timetrack_no_ndx(self):
        ndx = self.table_view.currentIndex()
        if ndx.isValid() and ndx.column() >= 0 and ndx.row() >= 0:
            self.edit_timetrack(ndx)
        else:
            showWarningBox(_("Can't edit"),_("You must first select a day/person."))


    @Slot(QModelIndex)
    def edit_timetrack(self,ndx):
        global dao
        global user_session

        if not user_session.has_any_roles(['TimeTrackModify']):
            return

        m = self.base_date.month
        edit_date = date(self.base_date.year,m,ndx.column()) # +1 already in because of employee's names
        employee = self._table_model.data(self._table_model.index(ndx.row(),0),Qt.UserRole) # FIXME Use a delegate
        d = EditTimeTracksDialog(self,dao,edit_date)
        d.set_employee_and_date(employee,edit_date)
        d.exec_()
        if d.result() == QDialog.Accepted:
            self.refresh_action()
        d.deleteLater()


    @Slot()
    def editTaskActionReports(self):
        if not user_session.has_any_roles(['TimeTrackModify']):
            return

        m = self.base_date.month
        ndx = self.table_view.currentIndex()

        if ndx.isValid() and ndx.column() >= 0 and ndx.row() >= 0:
            edit_date = date(self.base_date.year,m,ndx.column()) # +1 already in because of employee's names
            employee = self._table_model.data(self._table_model.index(ndx.row(),0),Qt.UserRole) # FIXME Use a delegate

            d = EditTaskActionReportsDialog(dao,self,edit_date)
            d.set_employee_date(employee, edit_date)
            d.exec_()
            if d.result() == QDialog.Accepted:
                self.refresh_action()
            d.deleteLater()
        else:
            showWarningBox(_("Can't edit"),_("You must first select a day/person."))


    @Slot(QModelIndex)
    def timetrack_changed(self,ndx):

        selected_timetrack = self.controller.model.object_at(ndx)

        # Update the colors in the timetrack views
        # to show what action reports correspond to the
        # selected timetrack

        self.controller_actions.model.current_timetrack = selected_timetrack
        self.controller_actions.model.beginResetModel()
        self.controller_actions.model.endResetModel()

        # Make sure the first of the action reports is shown in the
        # table

        action_reports = self.controller_actions.model.objects
        for i in range(len(action_reports)-1,-1,-1):
            if action_reports[i] and action_reports[i].timetrack == selected_timetrack:
                self.controller_actions.view.scrollTo(self.controller_actions.model.index(i,0))
                break


    def __init__(self,parent):
        super(TimeTracksOverviewWidget,self).__init__(parent)

        self.base_date = date.today()

        headers = QStandardItemModel(1, 31 + 1)
        headers.setHeaderData(0, Qt.Orientation.Horizontal, _("Employee"))
        for i in range(31):
            headers.setHeaderData(i+1, Qt.Orientation.Horizontal, "{}".format(i+1))

        self._table_model = QStandardItemModel(1, 31+1, None)


        self.headers_view = QHeaderView(Qt.Orientation.Horizontal,self)
        self.header_model = headers
        self.headers_view.setResizeMode(QHeaderView.ResizeToContents)
        self.headers_view.setModel(self.header_model) # qt's doc : The view does *not* take ownership

        self.table_view = QTableView(None)
        self.table_view.setModel(self._table_model)
        self.table_view.setHorizontalHeader(self.headers_view)
        self.table_view.verticalHeader().hide()
        self.table_view.setAlternatingRowColors(True)
        # self.table_view.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.table_view.setEditTriggers(QAbstractItemView.NoEditTriggers)


        navbar = NavBar(self, [ (_("Month before"), self.month_before),
                                (_("Today"),self.month_today),
                                (_("Month after"), self.month_after)])

        self.title_box = TitleWidget(_("Time Records Overview"),self,navbar)
        self.vlayout = QVBoxLayout(self)
        self.vlayout.setObjectName("Vlayout")
        self.vlayout.addWidget(self.title_box)


        self.setLayout(self.vlayout)


        self.hours_per_pers_subframe = SubFrame(_("Hours worked per person"), self.table_view, self)

        self.vlayout.addWidget(self.hours_per_pers_subframe)


        hlayout = QHBoxLayout()

        prototype = []
        prototype.append( OrderPartOnTaskPrototype(None, _('Order Part')))
        prototype.append( TaskOnOrderPartPrototype('task', _('Task'),on_date=date.today()))
        prototype.append( DurationPrototype('duration',_('Duration')))
        prototype.append( TimestampPrototype('start_time',_('Start time'),fix_date=date.today()))
        prototype.append( DatePrototype('encoding_date',_('Recorded at'),editable=False))

        self.controller = PrototypeController(self,prototype)
        self.controller.setModel(TrackingProxyModel(self,prototype))
        self.controller.view.setColumnWidth(1,300)
        self.controller.view.horizontalHeader().setResizeMode(QHeaderView.ResizeToContents)
        self.controller.view.horizontalHeader().setResizeMode(1,QHeaderView.Stretch)

        navbar = NavBar(self, [ (_("Edit"), self.edit_timetrack_no_ndx)])
        self.hours_on_day_subframe = SubFrame(_("Total times on day"), self.controller.view, self,navbar)
        hlayout.addWidget(self.hours_on_day_subframe)


        prototype = []
        # prototype.append( EmployeePrototype('reporter', _('Description'), dao.employee_dao.all()))

        prototype.append( TaskDisplayPrototype('task', _('Task')))
        self.pointage_timestamp_prototype = TimestampPrototype('time',_('Hour'),editable=False,fix_date=date.today())
        prototype.append( self.pointage_timestamp_prototype)
        prototype.append( TaskActionTypePrototype('kind',_('Action')))
        prototype.append( TextLinePrototype('origin_location',_('Origin')))
        prototype.append( TextLinePrototype('editor',_('Editor'),editable=False,default='master'))


        self.controller_actions = PrototypeController(self,prototype)
        self.controller_actions.setModel(ActionReportModel(self,prototype))

        navbar = NavBar(self, [ (_("Edit"), self.editTaskActionReports)])
        hlayout.addWidget(SubFrame(_("Time records"),self.controller_actions.view,self,navbar))
        self.controller_actions.view.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.controller_actions.view.doubleClicked.connect(self.editTaskActionReports)

        self.controller_actions.view.horizontalHeader().setResizeMode(0,QHeaderView.Stretch)
        self.controller_actions.view.horizontalHeader().setResizeMode(3,QHeaderView.ResizeToContents)
        self.controller_actions.view.horizontalHeader().setResizeMode(4,QHeaderView.ResizeToContents)

        self.vlayout.addLayout(hlayout)

        self.vlayout.setStretch(0,0)
        self.vlayout.setStretch(1,300)
        self.vlayout.setStretch(2,200)

        # self.table_view.setSelectionBehavior(QAbstractItemView.SelectRows)
        #self.table_view.entered.connect(self.cell_entered)

        self.table_view.selectionModel().currentChanged.connect(self.cell_entered)
        self.table_view.doubleClicked.connect(self.edit_timetrack)
        self.controller.view.selectionModel().currentChanged.connect(self.timetrack_changed)
        self.controller.view.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.refresh_action()