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)
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()
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
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
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()
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
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()
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
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()"))
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()