def _createScrollArea(self): scrollArea = QScrollArea(self) scrollArea.setObjectName('scrollArea') scrollArea.setWidgetResizable(True) scrollWidget = QWidget(scrollArea) scrollWidget.setObjectName('scrollWidget') scrollArea.setWidget(scrollWidget) scrollLayout = QVBoxLayout(scrollWidget) scrollLayout.setObjectName('scrollLayout') self.layout.addWidget(scrollArea) return scrollWidget, scrollLayout
def create_doc_tab_populate_combobox(self): """ Creates the supporting document component widget. """ self.doc_tab_data() self.docs_tab = QTabWidget() self.docs_tab_index = OrderedDict() for i, (id, doc) in enumerate(self.doc_types.iteritems()): self.docs_tab_index[doc] = i # the tab widget containing the document widget layout # and the child of the tab. tab_widget = QWidget() tab_widget.setObjectName(doc) # The layout of the tab widget cont_layout = QVBoxLayout(tab_widget) cont_layout.setObjectName(u'widget_layout_{}'.format(doc)) # the scroll area widget inside the tab widget. scroll_area = QScrollArea(tab_widget) scroll_area.setFrameShape(QFrame.NoFrame) scroll_area.setObjectName(u'tab_scroll_area_{}'.format(doc)) layout_widget = QWidget() # the widget the is under the scroll area content and # the widget containing the document widget layout # This widget is hidden and shown based on the STR number layout_widget.setObjectName(u'widget_{}'.format(doc)) doc_widget_layout = QVBoxLayout(layout_widget) doc_widget_layout.setObjectName( u'doc_widget_layout_{}'.format(doc)) doc_widget = QWidget() doc_widget.setObjectName(u'doc_widget_{}_{}'.format( doc, self.str_number)) doc_widget_layout.addWidget(doc_widget) # the layout containing document widget. ### This is the layout that is registered to add uploaded # supporting documents widgets into. tab_layout = QVBoxLayout(doc_widget) tab_layout.setObjectName(u'layout_{}_{}'.format( doc, self.str_number)) scroll_area.setWidgetResizable(True) scroll_area.setWidget(layout_widget) cont_layout.addWidget(scroll_area) # Add the tab widget with the document # type name to create a tab. self.docs_tab.addTab(tab_widget, doc) self.container_box.addWidget(self.docs_tab, 1) if len(self.str_numbers) == 1: self.doc_type_cbo.addItem(doc, id)
class SkillWidget(TraitWidget): """ @brief Das Widget, in welchem sämtliche Fertigkeiten angeordnet sind. Wird bei irgendeiner Fertigkeit der Spazialisierungen-Knopf gedrückt, werden alle anderen Spezialisierungs-Knöpfe ausgeschalten. """ specialtiesActivated = Signal(bool, object) def __init__(self, template, character, parent=None): super(SkillWidget, self).__init__(template, character, parent) self.__layout = QVBoxLayout() self.setLayout(self.__layout) self.__scrollArea = QScrollArea() ## Die Auflistung der Fertigkeiten soll auch unter Windows einen transparenten Hintergrund haben. self.__scrollArea.setObjectName("transparentWidget") ## \todo Sollte nicht vom Betriebssystem, sondern vom verwendeten Style abhängen. if os.name == "nt": self.__scrollArea.setStyleSheet( "QWidget#transparentWidget { background: transparent; }") self.__layout.addWidget(self.__scrollArea) self.__scrollLayout = QVBoxLayout() self.__scrollWidget = QWidget() ## Die Auflistung der Fertigkeiten soll auch unter Windows einen transparenten Hintergrund haben. Indem ich den selben Namen wie zuvor vergebe, wirkt auch das Stylsheet auf dieses Widget. self.__scrollWidget.setObjectName("transparentWidget") #self.__scrollWidget.setStyleSheet( "QWidget#transparentWidget { background-color:transparent; }" ) #scrollWidget.setMinimumSize(this.width(), 400); self.__scrollWidget.setLayout(self.__scrollLayout) typ = "Skill" ## Eine Liste, in der alle Eigenschafts-Widgets aufgelistet werden. self.__traitWidgets = [] for item in Config.CATEGORIES_MAIN: #Debug.debug(self._character.traits) # Für jede Kategorie wird ein eigener Abschnitt erzeugt. widgetSkillCategory = QGroupBox() widgetSkillCategory.setTitle(item) widgetSkillCategory.setFlat(True) layoutSkillCategory = QVBoxLayout() widgetSkillCategory.setLayout(layoutSkillCategory) self.__scrollLayout.addWidget(widgetSkillCategory) __list = list(self._character.traits[typ][item].items()) __list.sort() for skill in __list: # Anlegen des Widgets, das diese Eigenschaft repräsentiert. traitWidget = CharaTrait(skill[1], self) traitWidget.buttonText = 0 traitWidget.setDescriptionHidden(True) traitWidget.enableButton( 0 ) # Zu Beginn sollen die Spezailisierungen nicht enabled sein. # Dieses Widget auch an Liste anhängen, damit ich einfacher darauf zugreifen kann. traitListItem = traitWidget self.__traitWidgets.append(traitListItem) # Es werden nur Fertigkeiten der richtigen Alters- und Zeit-Kategorie angezeigt. self.hideReasonChanged.connect(traitWidget.hideOrShowTrait) # Fertigkeiten haben Spezialisierungen. traitWidget.specialtiesClicked.connect( self.uncheckOtherButtons) traitWidget.specialtiesClicked.connect( self.specialtiesActivated.emit) ## Wenn sich die Spezialisierungen ändern, sollen die veränderten Spezialisierungen auch angezeigt werden. Das wird so gelöst, als wäre der Knopf für die Spezialisierungen erneut gedrückt worden. #skill.specialtiesChanged.connect(self.emitSpecialtiesActivated) layoutSkillCategory.addWidget(traitWidget) self.maxTraitChanged.connect(traitWidget.setMaximum) # Stretch einfügen, damit die Eigenschaften besser angeordnet sind. self.__scrollLayout.addStretch() self.__scrollArea.setWidget(self.__scrollWidget) self.__scrollArea.setWidgetResizable(True) self.__scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.__scrollArea.setMinimumWidth( self.__scrollArea.viewport().minimumWidth()) def uncheckOtherButtons(self, sw, trait): """ Über diese Funktion werden alle anderen Spezialisierungs-Knöpfe deaktiviert, sobald einer aktiviert wird. """ #Debug.debug("Drücke {}".format(skillName)) if sw: for item in self.__traitWidgets: if item.name != trait.name: item.setSpecialtyButtonChecked(False)
class EntityEditorDialog(QDialog, MapperMixin): """ Dialog for editing entity attributes. """ addedModel = pyqtSignal(object) def __init__( self, entity, model=None, parent=None, manage_documents=True, collect_model=False ): """ Class constructor. :param entity: Entity object corresponding to a table object. :type entity: Entity :param model: Data object for loading data into the form widgets. If the model is set, then the editor dialog is assumed to be in edit mode. :type model: object :param parent: Parent widget that the form belongs to. :type parent: QWidget :param manage_documents: True if the dialog should provide controls for managing supporting documents. Only applicable if the entity allows for supporting documents to be attached. :type manage_documents: bool :param collect_model: If set to True only returns the filled form model without saving it to the database. :type collect_model: Boolean :return: If collect_model, returns SQLAlchemy Model """ QDialog.__init__(self, parent) self.collection_suffix = self.tr('Collection') #Set minimum width self.setMinimumWidth(350) #Flag for mandatory columns self.has_mandatory = False self._entity = entity self._fk_browsers = OrderedDict() #Set notification layout bar self.vlNotification = QVBoxLayout() self.vlNotification.setObjectName('vlNotification') self._notifBar = NotificationBar(self.vlNotification) # Set manage documents only if the entity supports documents if self._entity.supports_documents: self._manage_documents = manage_documents else: self._manage_documents = False #Setup entity model self._ent_document_model = None if self._entity.supports_documents: ent_model, self._ent_document_model = entity_model( self._entity, with_supporting_document=True ) else: ent_model = entity_model(self._entity) if not model is None: ent_model = model MapperMixin.__init__(self, ent_model) self.collect_model = collect_model #Initialize UI setup self._init_gui() #Set title editor_trans = self.tr('Editor') title = u'{0} {1}'.format( format_name(self._entity.short_name), editor_trans ) self.setWindowTitle(title) def _init_gui(self): #Setup base elements self.gridLayout = QGridLayout(self) self.gridLayout.setObjectName('glMain') self.gridLayout.addLayout( self.vlNotification, 0, 0, 1, 1 ) #Set column widget area column_widget_area = self._setup_columns_content_area() self.gridLayout.addWidget( column_widget_area, 1, 0, 1, 1 ) #Add notification for mandatory columns if applicable next_row = 2 if self.has_mandatory: self.required_fields_lbl = QLabel(self) msg = self.tr( 'Please fill out all required (*) fields.' ) msg = self._highlight_asterisk(msg) self.required_fields_lbl.setText(msg) self.gridLayout.addWidget( self.required_fields_lbl, next_row, 0, 1, 2 ) #Bump up row reference next_row += 1 self.buttonBox = QDialogButtonBox(self) self.buttonBox.setOrientation(Qt.Horizontal) self.buttonBox.setStandardButtons( QDialogButtonBox.Cancel|QDialogButtonBox.Save ) self.buttonBox.setObjectName('buttonBox') self.gridLayout.addWidget( self.buttonBox, next_row, 0, 1, 1 ) if self.collect_model: self.buttonBox.accepted.connect( self.on_model_added ) self.buttonBox.rejected.connect( self.cancel ) else: #Connect to MapperMixin slots self.buttonBox.accepted.connect( self.submit ) self.buttonBox.rejected.connect( self.cancel ) def on_model_added(self): model = self.submit(True) self.addedModel.emit(model) def _setup_columns_content_area(self): #Only use this if entity supports documents self.entity_tab_widget = None self.doc_widget = None self.entity_scroll_area = QScrollArea(self) self.entity_scroll_area.setFrameShape(QFrame.NoFrame) self.entity_scroll_area.setWidgetResizable(True) self.entity_scroll_area.setObjectName('scrollArea') self.scroll_widget_contents = QWidget() self.scroll_widget_contents.setObjectName( 'scrollAreaWidgetContents' ) #Grid layout for controls self.gl = QGridLayout(self.scroll_widget_contents) self.gl.setObjectName('gl_widget_contents') #Append column labels and widgets table_name = self._entity.name columns = table_column_names(table_name) #Iterate entity column and assert if they exist row_id = 0 for c in self._entity.columns.values(): if not c.name in columns and not isinstance(c, VirtualColumn): continue #Get widget factory column_widget = ColumnWidgetRegistry.create( c, self.scroll_widget_contents ) if not column_widget is None: header = c.header() self.c_label = QLabel(self.scroll_widget_contents) #Format label text if it is a mandatory field if c.mandatory: header = '{0} *'.format(c.header()) #Highlight asterisk header = self._highlight_asterisk(header) self.c_label.setText(header) self.gl.addWidget(self.c_label, row_id, 0, 1, 1) self.column_widget = column_widget self.gl.addWidget(self.column_widget, row_id, 1, 1, 1) #Add user tip if specified for the column configuration if c.user_tip: self.tip_lbl = UserTipLabel(user_tip=c.user_tip) self.gl.addWidget(self.tip_lbl, row_id, 2, 1, 1) if c.mandatory and not self.has_mandatory: self.has_mandatory = True col_name = c.name #Replace name accordingly based on column type if isinstance(c, MultipleSelectColumn): col_name = c.model_attribute_name #Add widget to MapperMixin collection self.addMapping( col_name, self.column_widget, c.mandatory, pseudoname=c.header() ) #Bump up row_id row_id += 1 self.entity_scroll_area.setWidget( self.scroll_widget_contents ) #Check if there are children and add foreign key browsers ch_entities = self.children_entities() if len(ch_entities) > 0: if self.entity_tab_widget is None: self.entity_tab_widget = QTabWidget(self) #Add primary tab if necessary self._add_primary_attr_widget() for ch in ch_entities: self._add_fk_browser(ch) #Add tab widget if entity supports documents if self._entity.supports_documents: self.doc_widget = SupportingDocumentsWidget( self._entity.supporting_doc, self._ent_document_model, self ) #Map the source document manager object self.addMapping( 'documents', self.doc_widget.source_document_manager ) if self.entity_tab_widget is None: self.entity_tab_widget = QTabWidget(self) #Add attribute tab self._add_primary_attr_widget() #Add supporting documents tab self.entity_tab_widget.addTab( self.doc_widget, self.tr('Supporting Documents') ) #Return the correct widget if not self.entity_tab_widget is None: return self.entity_tab_widget return self.entity_scroll_area def _add_primary_attr_widget(self): # Check if the primary entity # exists and add if it does not pr_txt = self.tr('Primary') if not self.entity_tab_widget is None: tab_txt = self.entity_tab_widget.tabText(0) if not tab_txt == pr_txt: self.entity_tab_widget.addTab( self.entity_scroll_area, pr_txt ) def _add_fk_browser(self, child_entity): # Create and add foreign key # browser to the collection attr = u'{0}_collection'.format( child_entity.name ) #Return if the attribute does not exist if not hasattr(self._model, attr): return fkb = ForeignKeyMapper( child_entity, self, notification_bar=self._notifBar, can_filter=True ) #Add to mapped collection self.addMapping( attr, fkb ) self.entity_tab_widget.addTab( fkb, u'{0} {1}'.format( child_entity.short_name, self.collection_suffix ) ) #Add to the collection self._fk_browsers[child_entity.name] = fkb def children_entities(self): """ :return: Returns a list of children entities that refer to the main entity as the parent. :rtype: list """ return [ch for ch in self._entity.children() if ch.TYPE_INFO == Entity.TYPE_INFO] def document_widget(self): """ :return: Returns the widget for managing the supporting documents for an entity if enabled. :rtype: SupportingDocumentsWidget """ return self.doc_widget def source_document_manager(self): """ :return: Returns an instance of the SourceDocumentManager only if supporting documents are enabled for the given entity. Otherwise, None if supporting documents are not enabled. :rtype: SourceDocumentManager """ if self.doc_widget is None: return None return self.doc_widget.source_document_manager def _highlight_asterisk(self, text): #Highlight asterisk in red c = '*' #Do not format if there is no asterisk if text.find(c) == -1: return text asterisk_highlight = '<span style=\" color:#ff0000;\">*</span>' text = text.replace(c, asterisk_highlight) return u'<html><head/><body><p>{0}</p></body></html>'.format(text)
class EntityEditorDialog(QDialog, MapperMixin): """ Dialog for editing entity attributes. """ addedModel = pyqtSignal(object) def __init__( self, entity, model=None, parent=None, manage_documents=True, collect_model=False, parent_entity=None, exclude_columns=[], plugin = None ): """ Class constructor. :param entity: Entity object corresponding to a table object. :type entity: Entity :param model: Data object for loading data into the form widgets. If the model is set, then the editor dialog is assumed to be in edit mode. :type model: object :param parent: Parent widget that the form belongs to. :type parent: QWidget :param manage_documents: True if the dialog should provide controls for managing supporting documents. Only applicable if the entity allows for supporting documents to be attached. :type manage_documents: bool :param collect_model: If set to True only returns the filled form model without saving it to the database. :type collect_model: Boolean :param parent_entity: The parent entity of the editor :type parent_entity: Object :param exclude_columns: List of columns to be excluded if in a list. :type exclude_columns: List :return: If collect_model, returns SQLAlchemy Model """ QDialog.__init__(self, parent) self.entity_table_model = {} self.collection_suffix = self.tr('Collection') #Set minimum width self.setMinimumWidth(450) self.plugin = plugin #Flag for mandatory columns self.has_mandatory = False self.reload_form = False self._entity = entity self.edit_model = model self.column_widgets = OrderedDict() self._parent = parent self.exclude_columns = exclude_columns self.entity_tab_widget = None self._disable_collections = False self.filter_val = None self.parent_entity = parent_entity self.child_models = OrderedDict() self.entity_scroll_area = None self.entity_editor_widgets = OrderedDict() # Set notification layout bar self.vlNotification = QVBoxLayout() self.vlNotification.setObjectName('vlNotification') self._notifBar = NotificationBar(self.vlNotification) self.do_not_check_dirty = False # Set manage documents only if the entity supports documents if self._entity.supports_documents: self._manage_documents = manage_documents else: self._manage_documents = False # Setup entity model self._ent_document_model = None if self._entity.supports_documents: self.ent_model, self._ent_document_model = entity_model( self._entity, with_supporting_document=True ) else: self.ent_model = entity_model(self._entity) if not model is None: self.ent_model = model MapperMixin.__init__(self, self.ent_model, entity) self.collect_model = collect_model self.register_column_widgets() try: if isinstance(parent._parent, EntityEditorDialog): # hide collections form child editor self._disable_collections = True except AttributeError: self._parent._parent = None # Set title editor_trans = self.tr('Editor') if self._entity.label is not None: if self._entity.label != '': title_str = self._entity.label else: title_str = format_name(self._entity.short_name) else: title_str = format_name(self._entity.short_name) self.title = u'{0} {1}'.format(title_str, editor_trans) self.setWindowTitle(self.title) self._init_gui() self.adjustSize() self._get_entity_editor_widgets() if isinstance(parent._parent, EntityEditorDialog): self.parent_entity = parent.parent_entity self.set_parent_values() # make the size smaller to differentiate from parent and as it # only has few tabs. self.adjustSize() self.attribute_mappers = self._attr_mapper_collection # Exception title for editor extension exceptions self._ext_exc_msg = self.tr( 'An error has occured while executing Python code in the editor ' 'extension:' ) # Register custom editor extension if specified self._editor_ext = entity_dlg_extension(self) if not self._editor_ext is None: self._editor_ext.post_init() # Initialize CascadingFieldContext objects self._editor_ext.connect_cf_contexts() def _init_gui(self): # Setup base elements self.gridLayout = QGridLayout(self) self.gridLayout.setObjectName('glMain') self.gridLayout.addLayout( self.vlNotification, 0, 0, 1, 1 ) QApplication.processEvents() #set widgets values column_widget_area = self._setup_columns_content_area() self.gridLayout.addWidget( column_widget_area, 1, 0, 1, 1 ) QApplication.processEvents() # Add notification for mandatory columns if applicable next_row = 2 if self.has_mandatory: self.required_fields_lbl = QLabel(self) msg = self.tr( 'Please fill out all required (*) fields.' ) msg = self._highlight_asterisk(msg) self.required_fields_lbl.setText(msg) self.gridLayout.addWidget( self.required_fields_lbl, next_row, 0, 1, 2 ) # Bump up row reference next_row += 1 self.buttonBox = QDialogButtonBox(self) self.buttonBox.setObjectName('buttonBox') self.gridLayout.addWidget( self.buttonBox, next_row, 0, 1, 1 ) self.buttonBox.setOrientation(Qt.Horizontal) self.buttonBox.setStandardButtons( QDialogButtonBox.Cancel|QDialogButtonBox.Save ) if self.edit_model is None: if not self.collect_model: self.save_new_button = QPushButton( QApplication.translate( 'EntityEditorDialog', 'Save and New' ) ) self.buttonBox.addButton( self.save_new_button, QDialogButtonBox.ActionRole ) # edit model, collect model # adding new record for child # Saving in parent editor if not isinstance(self._parent._parent, EntityEditorDialog): # adding a new record if self.edit_model is None: # saving when digitizing. if self.collect_model: self.buttonBox.accepted.connect(self.on_model_added) # saving parent editor else: self.buttonBox.accepted.connect(self.save_parent_editor) self.save_new_button.clicked.connect(self.save_and_new) # updating existing record else: if not self.collect_model: # updating existing record of the parent editor self.buttonBox.accepted.connect(self.save_parent_editor) else: self.buttonBox.accepted.connect(self.on_model_added) # Saving in child editor else: # save and new record if self.edit_model is None: self.buttonBox.accepted.connect(self.on_child_saved) self.save_new_button.clicked.connect( lambda: self.on_child_saved(True) ) else: # When updating an existing child editor save to the db self.buttonBox.accepted.connect( self.on_child_saved ) #self.buttonBox.accepted.connect(self.submit) self.buttonBox.rejected.connect(self.cancel) @property def notification_bar(self): """ :return: Returns the dialog's notification bar. :rtype: NotificationBar """ return self._notifBar def save_parent_editor(self): """ Saves the parent editor and its children. """ self.submit() self.save_children() def set_parent_values(self): """ Sets the parent display column for the child. """ if self.parent_entity is None: return for col in self._entity.columns.values(): if col.TYPE_INFO == 'FOREIGN_KEY': parent_entity = col.parent if parent_entity == self.parent_entity: self.parent_widgets_value_setter(self._parent._parent, col) def parent_widgets_value_setter(self, parent, col): """ Finds and sets the value from parent widget and set it to the column widget of a child using the child column. :param parent: The parent widget :type parent: QWidget :param col: The child column object :type col: Object """ for parent_col, parent_widget in parent.column_widgets.iteritems(): if parent_col.name == col.name: self.single_parent_value_setter(col, parent_widget) break if parent_col.name in col.entity_relation.display_cols: self.single_parent_value_setter(col, parent_widget) break def single_parent_value_setter(self, col, parent_widget): """ Gets value from parent widget and set it to the column widget of a child using the child column. :param parent: The parent widget :type parent: QWidget :param col: The child column object :type col: Object """ local_widget = self.column_widgets[col] local_widget.show_clear_button() self.filter_val = parent_widget.text() local_widget.setText(self.filter_val) def save_and_new(self): """ A slot raised when Save and New button is click. It saves the form without showing a success message. Then it sets reload_form property to True so that entity_browser can re-load the form. """ from stdm.ui.entity_browser import ( EntityBrowserWithEditor ) self.submit(False, True) self.save_children() if self.is_valid: self.addedModel.emit(self.model()) self.setModel(self.ent_model()) self.clear() self.child_models.clear() for index in range(0, self.entity_tab_widget.count()-1): if isinstance( self.entity_tab_widget.widget(index), EntityBrowserWithEditor ): child_browser = self.entity_tab_widget.widget(index) child_browser.remove_rows() def on_model_added(self): """ A slot raised when a form is submitted with collect model set to True. There will be no success message and the form does not close. """ self.submit(True) self.addedModel.emit(self.model()) def closeEvent(self, event): ''' Raised when a request to close the window is received. Check the dirty state of input controls and prompt user to save if dirty. ''' if self.do_not_check_dirty: event.accept() return isDirty, userResponse = self.checkDirty() if isDirty: if userResponse == QMessageBox.Yes: # We need to ignore the event so that validation and # saving operations can be executed event.ignore() self.submit() elif userResponse == QMessageBox.No: event.accept() elif userResponse == QMessageBox.Cancel: event.ignore() else: event.accept() def on_child_saved(self, save_and_new=False): """ A slot raised when the save or save and new button is clicked. It sets the child_models dictionary of the parent when saved. :param save_and_new: A boolean indicating the save and new button is clicked to trigger the slot. :type save_and_new: Boolean """ if self.parent_entity is None: return self.submit(True) insert_pos = self._parent.tbEntity.model().rowCount() + 1 # Save to parent editor so that it is persistent. self._parent._parent.child_models[insert_pos, self._entity] = \ self.model() self.addedModel.emit(self.model()) if not save_and_new: self.accept() else: if self.is_valid: #self.addedModel.emit(self.model()) self.setModel(self.ent_model()) self.clear() self.set_parent_values() def save_children(self): """ Saves children models into the database by assigning the the id of the parent for foreign key column. """ if len(self.child_models) < 1: return children_obj = [] for row_entity, model in self.child_models.iteritems(): row_pos = row_entity[0] entity = row_entity[1] ent_model = entity_model(entity) entity_obj = ent_model() for col in entity.columns.values(): if col.TYPE_INFO == 'FOREIGN_KEY': if col.parent.name == self._entity.name: setattr(model, col.name, self.model().id) children_obj.append(model) entity_obj.saveMany(children_obj) def register_column_widgets(self): """ Registers the column widgets. """ # Append column labels and widgets table_name = self._entity.name columns = table_column_names(table_name) self.scroll_widget_contents = QWidget() self.scroll_widget_contents.setObjectName( 'scrollAreaWidgetContents' ) for c in self._entity.columns.values(): if c.name in self.exclude_columns: continue if not c.name in columns and not isinstance(c, VirtualColumn): continue # Get widget factory column_widget = ColumnWidgetRegistry.create( c, self.scroll_widget_contents, host=self ) self.column_widgets[c] = column_widget def _setup_columns_content_area(self): # Only use this if entity supports documents # self.entity_tab_widget = None self.doc_widget = None self.entity_scroll_area = QScrollArea(self) self.entity_scroll_area.setFrameShape(QFrame.NoFrame) self.entity_scroll_area.setWidgetResizable(True) self.entity_scroll_area.setObjectName('scrollArea') # Grid layout for controls self.gl = QGridLayout(self.scroll_widget_contents) self.gl.setObjectName('gl_widget_contents') # Append column labels and widgets table_name = self._entity.name columns = table_column_names(table_name) # Iterate entity column and assert if they exist row_id = 0 for c, column_widget in self.column_widgets.iteritems(): if c.name in self.exclude_columns: continue if not c.name in columns and not isinstance(c, VirtualColumn): continue if column_widget is not None: header = c.ui_display() self.c_label = QLabel(self.scroll_widget_contents) # Format label text if it is a mandatory field if c.mandatory: header = u'{0} *'.format(c.ui_display()) #Highlight asterisk header = self._highlight_asterisk(header) self.c_label.setText(header) self.gl.addWidget(self.c_label, row_id, 0, 1, 1) self.column_widget = column_widget self.gl.addWidget(self.column_widget, row_id, 1, 1, 1) #Add user tip if specified for the column configuration if c.user_tip: self.tip_lbl = UserTipLabel(user_tip=c.user_tip) self.gl.addWidget(self.tip_lbl, row_id, 2, 1, 1) if c.mandatory and not self.has_mandatory: self.has_mandatory = True col_name = c.name #Replace name accordingly based on column type if isinstance(c, MultipleSelectColumn): col_name = c.model_attribute_name # Add widget to MapperMixin collection self.addMapping( col_name, self.column_widget, c.mandatory, pseudoname=c.ui_display() ) # Bump up row_id row_id += 1 self.entity_scroll_area.setWidget(self.scroll_widget_contents) if self.entity_tab_widget is None: self.entity_tab_widget = QTabWidget(self) # Check if there are children and add foreign key browsers # Add primary tab if necessary self._add_primary_attr_widget() if not self._disable_collections: ch_entities = self.children_entities() for col, ch in ch_entities.iteritems(): if hasattr(col.entity_relation, 'show_in_parent'): if col.entity_relation.show_in_parent != '0': self._add_fk_browser(ch, col) else: self._add_fk_browser(ch, col) #Add tab widget if entity supports documents if self._entity.supports_documents: self.doc_widget = SupportingDocumentsWidget( self._entity.supporting_doc, self._ent_document_model, self ) # Map the source document manager object self.addMapping( 'documents', self.doc_widget.source_document_manager ) # # # Add attribute tab # self._add_primary_attr_widget() # Add supporting documents tab self.entity_tab_widget.addTab( self.doc_widget, self.tr('Supporting Documents') ) # Return the correct widget if not self.entity_tab_widget is None: return self.entity_tab_widget return self.entity_scroll_area def _add_primary_attr_widget(self): # Check if the primary entity # exists and add if it does not pr_txt = self.tr('Primary') if not self.entity_tab_widget is None: tab_txt = self.entity_tab_widget.tabText(0) if not tab_txt == pr_txt: self.entity_tab_widget.addTab( self.entity_scroll_area, pr_txt ) def _add_fk_browser(self, child_entity, column): # Create and add foreign key # browser to the collection from stdm.ui.entity_browser import ( EntityBrowserWithEditor ) attr = u'{0}_collection'.format(child_entity.name) # Return if the attribute does not exist if not hasattr(self._model, attr): return entity_browser = EntityBrowserWithEditor( child_entity, self, MANAGE, False, plugin=self.plugin ) entity_browser.buttonBox.setVisible(False) entity_browser.record_filter = [] if len(child_entity.label) > 2: column_label = child_entity.label else: # Split and join to filter out entity name prefix # e.g. 'lo_parcel' to 'parcel' column_label = format_name(" ".join(child_entity.name.split("_", 1)[1:])) self.entity_tab_widget.addTab( entity_browser, u'{0}'.format( column_label ) ) self.set_filter(child_entity, entity_browser) def set_filter(self, entity, browser): col = self.filter_col(entity) child_model = entity_model(entity) child_model_obj = child_model() col_obj = getattr(child_model, col.name) if self.model() is not None: if self.model().id is None: browser.filtered_records = [] else: browser.filtered_records = child_model_obj.queryObject().filter( col_obj == self.model().id ).all() if self.edit_model is not None: browser.filtered_records = child_model_obj.queryObject().filter( col_obj == self.edit_model.id ).all() if self.edit_model is None and self.model() is None: browser.filtered_records = [] def filter_col(self, child_entity): for col in child_entity.columns.values(): if col.TYPE_INFO == 'FOREIGN_KEY': parent_entity = col.parent if parent_entity == self._entity: return col def children_entities(self): """ :return: Returns a list of children entities that refer to the main entity as the parent. :rtype: OrderedDict """ child_columns = OrderedDict() for ch in self._entity.children(): if ch.TYPE_INFO == Entity.TYPE_INFO: for col in ch.columns.values(): if hasattr(col, 'entity_relation'): if col.parent.name == self._entity.name: child_columns[col] = ch return child_columns def document_widget(self): """ :return: Returns the widget for managing the supporting documents for an entity if enabled. :rtype: SupportingDocumentsWidget """ return self.doc_widget def source_document_manager(self): """ :return: Returns an instance of the SourceDocumentManager only if supporting documents are enabled for the given entity. Otherwise, None if supporting documents are not enabled. :rtype: SourceDocumentManager """ if self.doc_widget is None: return None return self.doc_widget.source_document_manager def _highlight_asterisk(self, text): # Highlight asterisk in red c = '*' # Do not format if there is no asterisk if text.find(c) == -1: return text asterisk_highlight = '<span style=\" color:#ff0000;\">*</span>' text = text.replace(c, asterisk_highlight) return u'<html><head/><body><p>{0}</p></body></html>'.format(text) def _custom_validate(self): """ Override of the MapperMixin which enables custom editor extensions to inject additional validation before saving form data. :return: Return True if the validation was successful, otherwise False. :rtype: bool """ if not self._editor_ext is None: return self._editor_ext.validate() # Return True if there is no custom editor extension specified return True def _post_save(self, model): """ Include additional post-save logic by custom extensions. :param model: SQLAlchemy model :type model: object """ if not self._editor_ext is None: self._editor_ext.post_save(model) def _get_entity_editor_widgets(self): """ Gets entity editor widgets and appends them to a dictionary """ if self.entity_tab_widget: tab_count = self.entity_tab_widget.count() for i in range(tab_count): tab_object = self.entity_tab_widget.widget(i) tab_text = self.entity_tab_widget.tabText(i) self.entity_editor_widgets[tab_text] = tab_object else: self.entity_editor_widgets['no_tab'] = self.entity_scroll_area
class EntityEditorDialog(QDialog, MapperMixin): """ Dialog for editing entity attributes. """ addedModel = pyqtSignal(object) def __init__(self, entity, model=None, parent=None, manage_documents=True, collect_model=False, parent_entity=None, exclude_columns=[], plugin=None): """ Class constructor. :param entity: Entity object corresponding to a table object. :type entity: Entity :param model: Data object for loading data into the form widgets. If the model is set, then the editor dialog is assumed to be in edit mode. :type model: object :param parent: Parent widget that the form belongs to. :type parent: QWidget :param manage_documents: True if the dialog should provide controls for managing supporting documents. Only applicable if the entity allows for supporting documents to be attached. :type manage_documents: bool :param collect_model: If set to True only returns the filled form model without saving it to the database. :type collect_model: Boolean :param parent_entity: The parent entity of the editor :type parent_entity: Object :param exclude_columns: List of columns to be excluded if in a list. :type exclude_columns: List :return: If collect_model, returns SQLAlchemy Model """ QDialog.__init__(self, parent) self.entity_table_model = {} self.collection_suffix = self.tr('Collection') #Set minimum width self.setMinimumWidth(450) self.plugin = plugin #Flag for mandatory columns self.has_mandatory = False self.reload_form = False self._entity = entity self.edit_model = model self.column_widgets = OrderedDict() self._parent = parent self.exclude_columns = exclude_columns self.entity_tab_widget = None self._disable_collections = False self.filter_val = None self.parent_entity = parent_entity self.child_models = OrderedDict() self.entity_scroll_area = None self.entity_editor_widgets = OrderedDict() # Set notification layout bar self.vlNotification = QVBoxLayout() self.vlNotification.setObjectName('vlNotification') self._notifBar = NotificationBar(self.vlNotification) self.do_not_check_dirty = False # Set manage documents only if the entity supports documents if self._entity.supports_documents: self._manage_documents = manage_documents else: self._manage_documents = False # Setup entity model self._ent_document_model = None if self._entity.supports_documents: self.ent_model, self._ent_document_model = entity_model( self._entity, with_supporting_document=True) else: self.ent_model = entity_model(self._entity) if not model is None: self.ent_model = model MapperMixin.__init__(self, self.ent_model, entity) self.collect_model = collect_model self.register_column_widgets() try: if isinstance(parent._parent, EntityEditorDialog): # hide collections form child editor self._disable_collections = True except AttributeError: self._parent._parent = None # Set title editor_trans = self.tr('Editor') if self._entity.label is not None: if self._entity.label != '': title_str = self._entity.label else: title_str = format_name(self._entity.short_name) else: title_str = format_name(self._entity.short_name) self.title = u'{0} {1}'.format(title_str, editor_trans) self.setWindowTitle(self.title) self._init_gui() self.adjustSize() self._get_entity_editor_widgets() if isinstance(parent._parent, EntityEditorDialog): self.parent_entity = parent.parent_entity self.set_parent_values() # make the size smaller to differentiate from parent and as it # only has few tabs. self.adjustSize() self.attribute_mappers = self._attr_mapper_collection # Exception title for editor extension exceptions self._ext_exc_msg = self.tr( 'An error has occured while executing Python code in the editor ' 'extension:') # Register custom editor extension if specified self._editor_ext = entity_dlg_extension(self) if not self._editor_ext is None: self._editor_ext.post_init() # Initialize CascadingFieldContext objects self._editor_ext.connect_cf_contexts() def _init_gui(self): # Setup base elements self.gridLayout = QGridLayout(self) self.gridLayout.setObjectName('glMain') self.gridLayout.addLayout(self.vlNotification, 0, 0, 1, 1) QApplication.processEvents() #set widgets values column_widget_area = self._setup_columns_content_area() self.gridLayout.addWidget(column_widget_area, 1, 0, 1, 1) QApplication.processEvents() # Add notification for mandatory columns if applicable next_row = 2 if self.has_mandatory: self.required_fields_lbl = QLabel(self) msg = self.tr('Please fill out all required (*) fields.') msg = self._highlight_asterisk(msg) self.required_fields_lbl.setText(msg) self.gridLayout.addWidget(self.required_fields_lbl, next_row, 0, 1, 2) # Bump up row reference next_row += 1 self.buttonBox = QDialogButtonBox(self) self.buttonBox.setObjectName('buttonBox') self.gridLayout.addWidget(self.buttonBox, next_row, 0, 1, 1) self.buttonBox.setOrientation(Qt.Horizontal) self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Save) if self.edit_model is None: if not self.collect_model: self.save_new_button = QPushButton( QApplication.translate('EntityEditorDialog', 'Save and New')) self.buttonBox.addButton(self.save_new_button, QDialogButtonBox.ActionRole) # edit model, collect model # adding new record for child # Saving in parent editor if not isinstance(self._parent._parent, EntityEditorDialog): # adding a new record if self.edit_model is None: # saving when digitizing. if self.collect_model: self.buttonBox.accepted.connect(self.on_model_added) # saving parent editor else: self.buttonBox.accepted.connect(self.save_parent_editor) self.save_new_button.clicked.connect(self.save_and_new) # updating existing record else: if not self.collect_model: # updating existing record of the parent editor self.buttonBox.accepted.connect(self.save_parent_editor) else: self.buttonBox.accepted.connect(self.on_model_added) # Saving in child editor else: # save and new record if self.edit_model is None: self.buttonBox.accepted.connect(self.on_child_saved) self.save_new_button.clicked.connect( lambda: self.on_child_saved(True)) else: # When updating an existing child editor save to the db self.buttonBox.accepted.connect(self.on_child_saved) #self.buttonBox.accepted.connect(self.submit) self.buttonBox.rejected.connect(self.cancel) @property def notification_bar(self): """ :return: Returns the dialog's notification bar. :rtype: NotificationBar """ return self._notifBar def save_parent_editor(self): """ Saves the parent editor and its children. """ self.submit() self.save_children() def set_parent_values(self): """ Sets the parent display column for the child. """ if self.parent_entity is None: return for col in self._entity.columns.values(): if col.TYPE_INFO == 'FOREIGN_KEY': parent_entity = col.parent if parent_entity == self.parent_entity: self.parent_widgets_value_setter(self._parent._parent, col) def parent_widgets_value_setter(self, parent, col): """ Finds and sets the value from parent widget and set it to the column widget of a child using the child column. :param parent: The parent widget :type parent: QWidget :param col: The child column object :type col: Object """ for parent_col, parent_widget in parent.column_widgets.iteritems(): if parent_col.name == col.name: self.single_parent_value_setter(col, parent_widget) break if parent_col.name in col.entity_relation.display_cols: self.single_parent_value_setter(col, parent_widget) break def single_parent_value_setter(self, col, parent_widget): """ Gets value from parent widget and set it to the column widget of a child using the child column. :param parent: The parent widget :type parent: QWidget :param col: The child column object :type col: Object """ local_widget = self.column_widgets[col] local_widget.show_clear_button() self.filter_val = parent_widget.text() local_widget.setText(self.filter_val) def save_and_new(self): """ A slot raised when Save and New button is click. It saves the form without showing a success message. Then it sets reload_form property to True so that entity_browser can re-load the form. """ from stdm.ui.entity_browser import (EntityBrowserWithEditor) self.submit(False, True) self.save_children() if self.is_valid: self.addedModel.emit(self.model()) self.setModel(self.ent_model()) self.clear() self.child_models.clear() for index in range(0, self.entity_tab_widget.count() - 1): if isinstance(self.entity_tab_widget.widget(index), EntityBrowserWithEditor): child_browser = self.entity_tab_widget.widget(index) child_browser.remove_rows() def on_model_added(self): """ A slot raised when a form is submitted with collect model set to True. There will be no success message and the form does not close. """ self.submit(True) self.addedModel.emit(self.model()) def closeEvent(self, event): ''' Raised when a request to close the window is received. Check the dirty state of input controls and prompt user to save if dirty. ''' if self.do_not_check_dirty: event.accept() return isDirty, userResponse = self.checkDirty() if isDirty: if userResponse == QMessageBox.Yes: # We need to ignore the event so that validation and # saving operations can be executed event.ignore() self.submit() elif userResponse == QMessageBox.No: event.accept() elif userResponse == QMessageBox.Cancel: event.ignore() else: event.accept() def on_child_saved(self, save_and_new=False): """ A slot raised when the save or save and new button is clicked. It sets the child_models dictionary of the parent when saved. :param save_and_new: A boolean indicating the save and new button is clicked to trigger the slot. :type save_and_new: Boolean """ if self.parent_entity is None: return self.submit(True) insert_pos = self._parent.tbEntity.model().rowCount() + 1 # Save to parent editor so that it is persistent. self._parent._parent.child_models[insert_pos, self._entity] = \ self.model() self.addedModel.emit(self.model()) if not save_and_new: self.accept() else: if self.is_valid: #self.addedModel.emit(self.model()) self.setModel(self.ent_model()) self.clear() self.set_parent_values() def save_children(self): """ Saves children models into the database by assigning the the id of the parent for foreign key column. """ if len(self.child_models) < 1: return children_obj = [] for row_entity, model in self.child_models.iteritems(): row_pos = row_entity[0] entity = row_entity[1] ent_model = entity_model(entity) entity_obj = ent_model() for col in entity.columns.values(): if col.TYPE_INFO == 'FOREIGN_KEY': if col.parent.name == self._entity.name: setattr(model, col.name, self.model().id) children_obj.append(model) entity_obj.saveMany(children_obj) def register_column_widgets(self): """ Registers the column widgets. """ # Append column labels and widgets table_name = self._entity.name columns = table_column_names(table_name) self.scroll_widget_contents = QWidget() self.scroll_widget_contents.setObjectName('scrollAreaWidgetContents') for c in self._entity.columns.values(): if c.name in self.exclude_columns: continue if not c.name in columns and not isinstance(c, VirtualColumn): continue # Get widget factory column_widget = ColumnWidgetRegistry.create( c, self.scroll_widget_contents, host=self) self.column_widgets[c] = column_widget def _setup_columns_content_area(self): # Only use this if entity supports documents # self.entity_tab_widget = None self.doc_widget = None self.entity_scroll_area = QScrollArea(self) self.entity_scroll_area.setFrameShape(QFrame.NoFrame) self.entity_scroll_area.setWidgetResizable(True) self.entity_scroll_area.setObjectName('scrollArea') # Grid layout for controls self.gl = QGridLayout(self.scroll_widget_contents) self.gl.setObjectName('gl_widget_contents') # Append column labels and widgets table_name = self._entity.name columns = table_column_names(table_name) # Iterate entity column and assert if they exist row_id = 0 for c, column_widget in self.column_widgets.iteritems(): if c.name in self.exclude_columns: continue if not c.name in columns and not isinstance(c, VirtualColumn): continue if column_widget is not None: header = c.ui_display() self.c_label = QLabel(self.scroll_widget_contents) # Format label text if it is a mandatory field if c.mandatory: header = u'{0} *'.format(c.ui_display()) #Highlight asterisk header = self._highlight_asterisk(header) self.c_label.setText(header) self.gl.addWidget(self.c_label, row_id, 0, 1, 1) self.column_widget = column_widget self.gl.addWidget(self.column_widget, row_id, 1, 1, 1) #Add user tip if specified for the column configuration if c.user_tip: self.tip_lbl = UserTipLabel(user_tip=c.user_tip) self.gl.addWidget(self.tip_lbl, row_id, 2, 1, 1) if c.mandatory and not self.has_mandatory: self.has_mandatory = True col_name = c.name #Replace name accordingly based on column type if isinstance(c, MultipleSelectColumn): col_name = c.model_attribute_name # Add widget to MapperMixin collection self.addMapping(col_name, self.column_widget, c.mandatory, pseudoname=c.ui_display()) # Bump up row_id row_id += 1 self.entity_scroll_area.setWidget(self.scroll_widget_contents) if self.entity_tab_widget is None: self.entity_tab_widget = QTabWidget(self) # Check if there are children and add foreign key browsers # Add primary tab if necessary self._add_primary_attr_widget() if not self._disable_collections: ch_entities = self.children_entities() for col, ch in ch_entities.iteritems(): if hasattr(col.entity_relation, 'show_in_parent'): if col.entity_relation.show_in_parent != '0': self._add_fk_browser(ch, col) else: self._add_fk_browser(ch, col) #Add tab widget if entity supports documents if self._entity.supports_documents: self.doc_widget = SupportingDocumentsWidget( self._entity.supporting_doc, self._ent_document_model, self) # Map the source document manager object self.addMapping('documents', self.doc_widget.source_document_manager) # # # Add attribute tab # self._add_primary_attr_widget() # Add supporting documents tab self.entity_tab_widget.addTab(self.doc_widget, self.tr('Supporting Documents')) # Return the correct widget if not self.entity_tab_widget is None: return self.entity_tab_widget return self.entity_scroll_area def _add_primary_attr_widget(self): # Check if the primary entity # exists and add if it does not pr_txt = self.tr('Primary') if not self.entity_tab_widget is None: tab_txt = self.entity_tab_widget.tabText(0) if not tab_txt == pr_txt: self.entity_tab_widget.addTab(self.entity_scroll_area, pr_txt) def _add_fk_browser(self, child_entity, column): # Create and add foreign key # browser to the collection from stdm.ui.entity_browser import (EntityBrowserWithEditor) attr = u'{0}_collection'.format(child_entity.name) # Return if the attribute does not exist if not hasattr(self._model, attr): return entity_browser = EntityBrowserWithEditor(child_entity, self, MANAGE, False, plugin=self.plugin) entity_browser.buttonBox.setVisible(False) entity_browser.record_filter = [] if len(child_entity.label) > 2: column_label = child_entity.label else: # Split and join to filter out entity name prefix # e.g. 'lo_parcel' to 'parcel' column_label = format_name(" ".join( child_entity.name.split("_", 1)[1:])) self.entity_tab_widget.addTab(entity_browser, u'{0}'.format(column_label)) self.set_filter(child_entity, entity_browser) def set_filter(self, entity, browser): col = self.filter_col(entity) child_model = entity_model(entity) child_model_obj = child_model() col_obj = getattr(child_model, col.name) if self.model() is not None: if self.model().id is None: browser.filtered_records = [] else: browser.filtered_records = child_model_obj.queryObject( ).filter(col_obj == self.model().id).all() if self.edit_model is not None: browser.filtered_records = child_model_obj.queryObject().filter( col_obj == self.edit_model.id).all() if self.edit_model is None and self.model() is None: browser.filtered_records = [] def filter_col(self, child_entity): for col in child_entity.columns.values(): if col.TYPE_INFO == 'FOREIGN_KEY': parent_entity = col.parent if parent_entity == self._entity: return col def children_entities(self): """ :return: Returns a list of children entities that refer to the main entity as the parent. :rtype: OrderedDict """ child_columns = OrderedDict() for ch in self._entity.children(): if ch.TYPE_INFO == Entity.TYPE_INFO: for col in ch.columns.values(): if hasattr(col, 'entity_relation'): if col.parent.name == self._entity.name: child_columns[col] = ch return child_columns def document_widget(self): """ :return: Returns the widget for managing the supporting documents for an entity if enabled. :rtype: SupportingDocumentsWidget """ return self.doc_widget def source_document_manager(self): """ :return: Returns an instance of the SourceDocumentManager only if supporting documents are enabled for the given entity. Otherwise, None if supporting documents are not enabled. :rtype: SourceDocumentManager """ if self.doc_widget is None: return None return self.doc_widget.source_document_manager def _highlight_asterisk(self, text): # Highlight asterisk in red c = '*' # Do not format if there is no asterisk if text.find(c) == -1: return text asterisk_highlight = '<span style=\" color:#ff0000;\">*</span>' text = text.replace(c, asterisk_highlight) return u'<html><head/><body><p>{0}</p></body></html>'.format(text) def _custom_validate(self): """ Override of the MapperMixin which enables custom editor extensions to inject additional validation before saving form data. :return: Return True if the validation was successful, otherwise False. :rtype: bool """ if not self._editor_ext is None: return self._editor_ext.validate() # Return True if there is no custom editor extension specified return True def _post_save(self, model): """ Include additional post-save logic by custom extensions. :param model: SQLAlchemy model :type model: object """ if not self._editor_ext is None: self._editor_ext.post_save(model) def _get_entity_editor_widgets(self): """ Gets entity editor widgets and appends them to a dictionary """ if self.entity_tab_widget: tab_count = self.entity_tab_widget.count() for i in range(tab_count): tab_object = self.entity_tab_widget.widget(i) tab_text = self.entity_tab_widget.tabText(i) self.entity_editor_widgets[tab_text] = tab_object else: self.entity_editor_widgets['no_tab'] = self.entity_scroll_area
class SkillWidget(TraitWidget): """ @brief Das Widget, in welchem sämtliche Fertigkeiten angeordnet sind. Wird bei irgendeiner Fertigkeit der Spazialisierungen-Knopf gedrückt, werden alle anderen Spezialisierungs-Knöpfe ausgeschalten. """ specialtiesActivated = Signal(bool, object) def __init__(self, template, character, parent=None): super(SkillWidget, self).__init__(template, character, parent) self.__layout = QVBoxLayout() self.setLayout( self.__layout ) self.__scrollArea = QScrollArea() ## Die Auflistung der Fertigkeiten soll auch unter Windows einen transparenten Hintergrund haben. self.__scrollArea.setObjectName("transparentWidget") ## \todo Sollte nicht vom Betriebssystem, sondern vom verwendeten Style abhängen. if os.name == "nt": self.__scrollArea.setStyleSheet( "QWidget#transparentWidget { background: transparent; }" ) self.__layout.addWidget( self.__scrollArea) self.__scrollLayout = QVBoxLayout() self.__scrollWidget = QWidget() ## Die Auflistung der Fertigkeiten soll auch unter Windows einen transparenten Hintergrund haben. Indem ich den selben Namen wie zuvor vergebe, wirkt auch das Stylsheet auf dieses Widget. self.__scrollWidget.setObjectName("transparentWidget") #self.__scrollWidget.setStyleSheet( "QWidget#transparentWidget { background-color:transparent; }" ) #scrollWidget.setMinimumSize(this.width(), 400); self.__scrollWidget.setLayout(self.__scrollLayout) typ = "Skill" ## Eine Liste, in der alle Eigenschafts-Widgets aufgelistet werden. self.__traitWidgets = [] for item in Config.CATEGORIES_MAIN: #Debug.debug(self._character.traits) # Für jede Kategorie wird ein eigener Abschnitt erzeugt. widgetSkillCategory = QGroupBox() widgetSkillCategory.setTitle(item) widgetSkillCategory.setFlat(True) layoutSkillCategory = QVBoxLayout() widgetSkillCategory.setLayout( layoutSkillCategory ); self.__scrollLayout.addWidget( widgetSkillCategory ) __list = list( self._character.traits[typ][item].items() ) __list.sort() for skill in __list: # Anlegen des Widgets, das diese Eigenschaft repräsentiert. traitWidget = CharaTrait( skill[1], self ) traitWidget.buttonText = 0 traitWidget.setDescriptionHidden( True ) traitWidget.enableButton(0) # Zu Beginn sollen die Spezailisierungen nicht enabled sein. # Dieses Widget auch an Liste anhängen, damit ich einfacher darauf zugreifen kann. traitListItem = traitWidget self.__traitWidgets.append(traitListItem) # Es werden nur Fertigkeiten der richtigen Alters- und Zeit-Kategorie angezeigt. self.hideReasonChanged.connect(traitWidget.hideOrShowTrait) # Fertigkeiten haben Spezialisierungen. traitWidget.specialtiesClicked.connect(self.uncheckOtherButtons) traitWidget.specialtiesClicked.connect(self.specialtiesActivated.emit) ## Wenn sich die Spezialisierungen ändern, sollen die veränderten Spezialisierungen auch angezeigt werden. Das wird so gelöst, als wäre der Knopf für die Spezialisierungen erneut gedrückt worden. #skill.specialtiesChanged.connect(self.emitSpecialtiesActivated) layoutSkillCategory.addWidget( traitWidget ) self.maxTraitChanged.connect(traitWidget.setMaximum) # Stretch einfügen, damit die Eigenschaften besser angeordnet sind. self.__scrollLayout.addStretch() self.__scrollArea.setWidget(self.__scrollWidget) self.__scrollArea.setWidgetResizable(True) self.__scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.__scrollArea.setMinimumWidth(self.__scrollArea.viewport().minimumWidth()) def uncheckOtherButtons( self, sw, trait ): """ Über diese Funktion werden alle anderen Spezialisierungs-Knöpfe deaktiviert, sobald einer aktiviert wird. """ #Debug.debug("Drücke {}".format(skillName)) if sw: for item in self.__traitWidgets: if item.name != trait.name: item.setSpecialtyButtonChecked(False)
def __init__(self, parent=None): QDialog.__init__(self, parent) self.resize(400, 500) self.setWindowTitle("Aerodrome Surfaces Criteria") sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.sizePolicy().hasHeightForWidth()) self.setSizePolicy(sizePolicy) verticalLayoutDlg = QVBoxLayout(self) verticalLayoutDlg.setObjectName(("verticalLayoutDlg")) scrollArea = QScrollArea(self) scrollArea.setObjectName("scrollArea") scrollArea.setWidgetResizable(True) scrollAreaWidgetContents = QWidget(scrollArea) scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents") # scrollAreaWidgetContents.setGeometry(QRect(0, 0, 380, 280)) vLayoutScrollArea = QVBoxLayout(scrollAreaWidgetContents) vLayoutScrollArea.setObjectName("vLayoutScrollArea") scrollArea.setWidget(scrollAreaWidgetContents) verticalLayoutDlg.addWidget(scrollArea) self.groupBox = GroupBox(self) self.groupBox.Caption = "" vLayoutScrollArea.addWidget(self.groupBox) self.panel = Frame(self.groupBox) self.groupBox.Add = self.panel self.pnlName = TextBoxPanel(self.panel) self.pnlName.LabelWidth = 0 self.panel.Add = self.pnlName self.gbApproach = GroupBox(self.panel) self.gbApproach.Caption = "Approach" self.panel.Add = self.gbApproach self.pnlAPP_InnerEdge = DistanceBoxPanel(self.gbApproach, DistanceUnits.M) self.pnlAPP_InnerEdge.Caption = "Inner Edge" self.pnlAPP_InnerEdge.Button = None self.gbApproach.Add = self.pnlAPP_InnerEdge self.pnlAPP_DistFromTHR = DistanceBoxPanel(self.gbApproach, DistanceUnits.M) self.pnlAPP_DistFromTHR.Caption = "Distance From Threshold" self.pnlAPP_DistFromTHR.Button = None self.gbApproach.Add = self.pnlAPP_DistFromTHR self.pnlAPP_Divergence = AngleGradientBoxPanel(self.gbApproach) self.pnlAPP_Divergence.CaptionUnits = AngleGradientSlopeUnits.Percent self.pnlAPP_Divergence.Caption = "Divergence (each side)" self.gbApproach.Add = self.pnlAPP_Divergence self.gbApproach1 = GroupBox(self.gbApproach) self.gbApproach1.Caption = "First Section" self.gbApproach.Add = self.gbApproach1 self.pnlAPP_Length1 = DistanceBoxPanel(self.gbApproach1, DistanceUnits.M) self.pnlAPP_Length1.Caption = "Length" self.pnlAPP_Length1.Button = None self.gbApproach1.Add = self.pnlAPP_Length1 self.pnlAPP_Slope1 = AngleGradientBoxPanel(self.gbApproach1) self.pnlAPP_Slope1.CaptionUnits = AngleGradientSlopeUnits.Percent self.pnlAPP_Slope1.Caption = "Slope" self.gbApproach1.Add = self.pnlAPP_Slope1 self.gbApproach2 = GroupBox(self.gbApproach) self.gbApproach2.Caption = "Second Section" self.gbApproach.Add = self.gbApproach2 self.pnlAPP_Length2 = DistanceBoxPanel(self.gbApproach2, DistanceUnits.M) self.pnlAPP_Length2.Caption = "Length" self.pnlAPP_Length2.Button = None self.gbApproach2.Add = self.pnlAPP_Length2 self.pnlAPP_Slope2 = AngleGradientBoxPanel(self.gbApproach2) self.pnlAPP_Slope2.CaptionUnits = AngleGradientSlopeUnits.Percent self.pnlAPP_Slope2.Caption = "Slope" self.gbApproach2.Add = self.pnlAPP_Slope2 self.gbApproach3 = GroupBox(self.gbApproach) self.gbApproach3.Caption = "Horizontal Section" self.gbApproach.Add = self.gbApproach3 self.pnlAPP_Length3 = DistanceBoxPanel(self.gbApproach3, DistanceUnits.M) self.pnlAPP_Length3.Caption = "Length" self.pnlAPP_Length3.Button = None self.gbApproach3.Add = self.pnlAPP_Length3 self.pnlAPP_TotalLength = DistanceBoxPanel(self.gbApproach3, DistanceUnits.M) self.pnlAPP_TotalLength.Caption = "Total Length" self.pnlAPP_TotalLength.Button = None self.gbApproach3.Add = self.pnlAPP_TotalLength self.gbBalkedLanding = GroupBox(self.panel) self.gbBalkedLanding.Caption = "Balked Landing" self.panel.Add = self.gbBalkedLanding self.pnlBL_InnerEdge = DistanceBoxPanel(self.gbBalkedLanding, DistanceUnits.M) self.pnlBL_InnerEdge.Caption = "Length of Inner Edge" self.pnlBL_InnerEdge.Button = None self.gbBalkedLanding.Add = self.pnlBL_InnerEdge self.pnlBL_DistFromTHR = Frame(self.gbBalkedLanding, "HL") self.gbBalkedLanding.Add = self.pnlBL_DistFromTHR self.cmbBL_DistFromTHR = ComboBoxPanel(self.pnlBL_DistFromTHR) self.cmbBL_DistFromTHR.CaptionUnits = "m" self.cmbBL_DistFromTHR.Caption = "Distance From Threshold" self.pnlBL_DistFromTHR.Add = self.cmbBL_DistFromTHR self.txtBL_DistFromTHR = DistanceBoxPanel(self.pnlBL_DistFromTHR, DistanceUnits.M) self.txtBL_DistFromTHR.LabelWidth = 0 self.txtBL_DistFromTHR.Button = None self.pnlBL_DistFromTHR.Add = self.txtBL_DistFromTHR self.pnlBL_Divergence = AngleGradientBoxPanel(self.gbBalkedLanding) self.pnlBL_Divergence.CaptionUnits = AngleGradientSlopeUnits.Percent self.pnlBL_Divergence.Caption = "Divergence (each side)" self.gbBalkedLanding.Add = self.pnlBL_Divergence self.pnlBL_Slope = AngleGradientBoxPanel(self.gbBalkedLanding) self.pnlBL_Slope.CaptionUnits = AngleGradientSlopeUnits.Percent self.pnlBL_Slope.Caption = "Slope" self.gbBalkedLanding.Add = self.pnlBL_Slope self.gbConical = GroupBox(self.panel) self.gbConical.Caption = "Conical" self.panel.Add = self.gbConical self.pnlCON_Slope = AngleGradientBoxPanel(self.gbConical) self.pnlCON_Slope.CaptionUnits = AngleGradientSlopeUnits.Percent self.pnlCON_Slope.Caption = "Slope" self.gbConical.Add = self.pnlCON_Slope self.pnlCON_Height = AltitudeBoxPanel(self.gbConical) self.pnlCON_Height.CaptionUnits = "m" self.pnlCON_Height.Caption = "Height" self.gbConical.Add = self.pnlCON_Height self.gbInnerApproach = GroupBox(self.panel) self.gbInnerApproach.Caption = "Inner Approach" self.panel.Add = self.gbInnerApproach self.pnlIA_Width = DistanceBoxPanel(self.gbInnerApproach, DistanceUnits.M) self.pnlIA_Width.Caption = "Width" self.pnlIA_Width.Button = None self.gbInnerApproach.Add = self.pnlIA_Width self.pnlIA_DistFromTHR = DistanceBoxPanel(self.gbInnerApproach, DistanceUnits.M) self.pnlIA_DistFromTHR.Caption = "Distance From Threshold" self.pnlIA_DistFromTHR.Button = None self.gbInnerApproach.Add = self.pnlIA_DistFromTHR self.pnlIA_Length = DistanceBoxPanel(self.gbInnerApproach, DistanceUnits.M) self.pnlIA_Length.Caption = "Length" self.pnlIA_Length.Button = None self.gbInnerApproach.Add = self.pnlIA_Length self.pnlIA_Slope = AngleGradientBoxPanel(self.gbInnerApproach) self.pnlIA_Slope.CaptionUnits = AngleGradientSlopeUnits.Percent self.pnlIA_Slope.Caption = "Slope" self.gbInnerApproach.Add = self.pnlIA_Slope self.gbInnerHorizontal = GroupBox(self.panel) self.gbInnerHorizontal.Caption = "Inner Horizontal" self.panel.Add = self.gbInnerHorizontal self.pnlIH_Location = ComboBoxPanel(self.gbInnerHorizontal) self.pnlIH_Location.Caption = "Location" self.gbInnerHorizontal.Add = self.pnlIH_Location self.pnlIH_Height = AltitudeBoxPanel(self.gbInnerHorizontal) self.pnlIH_Height.CaptionUnits = "m" self.pnlIH_Height.Caption = "Height" self.gbInnerHorizontal.Add = self.pnlIH_Height self.pnlIH_Radius = DistanceBoxPanel(self.gbInnerHorizontal, DistanceUnits.M) self.pnlIH_Radius.Caption = "Radius" self.pnlIH_Radius.Button = None self.gbInnerHorizontal.Add = self.pnlIH_Radius self.gbInnerTransitional = GroupBox(self.panel) self.gbInnerTransitional.Caption = "Inner Transitional" self.panel.Add = self.gbInnerTransitional self.pnlIT_Slope = AngleGradientBoxPanel(self.gbInnerTransitional) self.pnlIT_Slope.CaptionUnits = AngleGradientSlopeUnits.Percent self.pnlIT_Slope.Caption = "Slope" self.gbInnerTransitional.Add = self.pnlIT_Slope self.gbNavAid = GroupBox(self.panel) self.gbNavAid.Caption = "1:10 Navigational Aid" self.panel.Add = self.gbNavAid self.pnlNA_Slope = AngleGradientBoxPanel(self.gbNavAid) self.pnlNA_Slope.CaptionUnits = AngleGradientSlopeUnits.Percent self.pnlNA_Slope.Caption = "Slope" self.gbNavAid.Add = self.pnlNA_Slope self.gbOuterHorizontal = GroupBox(self.panel) self.gbOuterHorizontal.Caption = "Outer Horizontal" self.panel.Add = self.gbOuterHorizontal self.pnlOH_Height = AltitudeBoxPanel(self.gbOuterHorizontal) self.pnlOH_Height.CaptionUnits = "m" self.pnlOH_Height.Caption = "Height" self.gbOuterHorizontal.Add = self.pnlOH_Height self.pnlOH_Radius = DistanceBoxPanel(self.gbOuterHorizontal, DistanceUnits.M) self.pnlOH_Radius.Caption = "Radius" self.pnlOH_Radius.Button = None self.gbOuterHorizontal.Add = self.pnlOH_Radius self.gbStrip = GroupBox(self.panel) self.gbStrip.Caption = "Strip" self.panel.Add = self.gbStrip self.pnlS_Width = DistanceBoxPanel(self.gbStrip, DistanceUnits.M) self.pnlS_Width.Caption = "Width" self.pnlS_Width.Button = None self.gbStrip.Add = self.pnlS_Width self.pnlS_Length = DistanceBoxPanel(self.gbStrip, DistanceUnits.M) self.pnlS_Length.Caption = "Length" self.pnlS_Length.Button = None self.gbStrip.Add = self.pnlS_Length self.gbTakeOff = GroupBox(self.panel) self.gbTakeOff.Caption = "Take-off " self.panel.Add = self.gbTakeOff self.pnlTO_InnerEdge = DistanceBoxPanel(self.gbTakeOff, DistanceUnits.M) self.pnlTO_InnerEdge.Caption = "Length of Inner Edge" self.pnlTO_InnerEdge.Button = None self.gbTakeOff.Add = self.pnlTO_InnerEdge self.pnlTO_DistFromEND = Frame(self.gbTakeOff, "HL") self.gbTakeOff.Add = self.pnlTO_DistFromEND self.cmbTO_DistFromEND = ComboBoxPanel(self.pnlTO_DistFromEND) self.cmbTO_DistFromEND.CaptionUnits = "m" self.cmbTO_DistFromEND.Caption = "Distance From Runway End" self.pnlTO_DistFromEND.Add = self.cmbTO_DistFromEND self.txtTO_DistFromEND = DistanceBoxPanel(self.pnlTO_DistFromEND, DistanceUnits.M) self.txtTO_DistFromEND.LabelWidth = 0 self.txtTO_DistFromEND.Button = None self.pnlTO_DistFromEND.Add = self.txtTO_DistFromEND self.pnlTO_Divergence = AngleGradientBoxPanel(self.gbTakeOff) self.pnlTO_Divergence.CaptionUnits = AngleGradientSlopeUnits.Percent self.pnlTO_Divergence.Caption = "Divergence (each side)" self.gbTakeOff.Add = self.pnlTO_Divergence self.pnlTO_FinalWidth = DistanceBoxPanel(self.gbTakeOff, DistanceUnits.M) self.pnlTO_FinalWidth.Caption = "Final Width" self.pnlTO_FinalWidth.Button = None self.gbTakeOff.Add = self.pnlTO_FinalWidth self.pnlTO_Length = DistanceBoxPanel(self.gbTakeOff, DistanceUnits.M) self.pnlTO_Length.Caption = "Length" self.pnlTO_Length.Button = None self.gbTakeOff.Add = self.pnlTO_Length self.pnlTO_Slope = AngleGradientBoxPanel(self.gbTakeOff) self.pnlTO_Slope.CaptionUnits = AngleGradientSlopeUnits.Percent self.pnlTO_Slope.Caption = "Slope" self.gbTakeOff.Add = self.pnlTO_Slope self.gbTransitional = GroupBox(self.panel) self.gbTransitional.Caption = "Transitional" self.panel.Add = self.gbTransitional self.pnlT_Slope = AngleGradientBoxPanel(self.gbTransitional) self.pnlT_Slope.CaptionUnits = AngleGradientSlopeUnits.Percent self.pnlT_Slope.Caption = "Slope" self.gbTransitional.Add = self.pnlT_Slope self.btnBoxOkCancel = QDialogButtonBox(self) self.btnBoxOkCancel.setObjectName(("btnBoxOkCancel")) self.btnBoxOkCancel.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok) self.btnSave = self.btnBoxOkCancel.button(QDialogButtonBox.Ok) self.btnSave.setText("Save") self.connect(self.btnBoxOkCancel, SIGNAL("accepted()"), self.acceptDlg) self.connect(self.btnBoxOkCancel, SIGNAL("rejected()"), self.reject) vLayoutScrollArea.addWidget(self.btnBoxOkCancel) self.cmbBL_DistFromTHR.Items = AerodromeSurfacesBalkedLandingFrom.Items self.pnlIH_Location.Items = AerodromeSurfacesInnerHorizontalLocation.Items self.cmbTO_DistFromEND.Items = AerodromeSurfacesTakeOffFrom.Items self.connect(self.pnlT_Slope, SIGNAL("Event_0"), self.method_6) self.connect(self.pnlTO_Slope, SIGNAL("Event_0"), self.method_6) self.connect(self.pnlTO_Length, SIGNAL("Event_0"), self.method_6) self.connect(self.pnlTO_FinalWidth, SIGNAL("Event_0"), self.method_6) self.connect(self.pnlTO_Divergence, SIGNAL("Event_0"), self.method_6) self.connect(self.txtTO_DistFromEND, SIGNAL("Event_0"), self.method_6) self.connect(self.cmbTO_DistFromEND, SIGNAL("Event_0"), self.method_6) self.connect(self.pnlTO_InnerEdge, SIGNAL("Event_0"), self.method_6) self.connect(self.pnlS_Length, SIGNAL("Event_0"), self.method_6) self.connect(self.pnlS_Width, SIGNAL("Event_0"), self.method_6) self.connect(self.pnlOH_Radius, SIGNAL("Event_0"), self.method_6) self.connect(self.pnlOH_Height, SIGNAL("Event_0"), self.method_6) self.connect(self.pnlNA_Slope, SIGNAL("Event_0"), self.method_6) self.connect(self.pnlIT_Slope, SIGNAL("Event_0"), self.method_6) self.connect(self.pnlIH_Radius, SIGNAL("Event_0"), self.method_6) self.connect(self.pnlIH_Height, SIGNAL("Event_0"), self.method_6) self.connect(self.pnlIH_Location, SIGNAL("Event_0"), self.method_6) self.connect(self.pnlIA_Slope, SIGNAL("Event_0"), self.method_6) self.connect(self.pnlIA_Length, SIGNAL("Event_0"), self.method_6) self.connect(self.pnlIA_DistFromTHR, SIGNAL("Event_0"), self.method_6) self.connect(self.pnlIA_Width, SIGNAL("Event_0"), self.method_6) self.connect(self.pnlCON_Height, SIGNAL("Event_0"), self.method_6) self.connect(self.pnlCON_Slope, SIGNAL("Event_0"), self.method_6) self.connect(self.pnlBL_Slope, SIGNAL("Event_0"), self.method_6) self.connect(self.pnlBL_Divergence, SIGNAL("Event_0"), self.method_6) self.connect(self.txtBL_DistFromTHR, SIGNAL("Event_0"), self.method_6) self.connect(self.cmbBL_DistFromTHR, SIGNAL("Event_0"), self.cmbBL_DistFromTHR_currentIndexChanged) self.connect(self.pnlBL_InnerEdge, SIGNAL("Event_0"), self.method_6) self.connect(self.pnlAPP_TotalLength, SIGNAL("Event_0"), self.method_6) self.connect(self.pnlAPP_Length3, SIGNAL("Event_0"), self.method_6) self.connect(self.pnlAPP_Slope2, SIGNAL("Event_0"), self.method_6) self.connect(self.pnlAPP_Length2, SIGNAL("Event_0"), self.method_6) self.connect(self.pnlAPP_Slope1, SIGNAL("Event_0"), self.method_6) self.connect(self.pnlAPP_Length1, SIGNAL("Event_0"), self.method_6) self.connect(self.pnlAPP_Divergence, SIGNAL("Event_0"), self.method_6) self.connect(self.pnlAPP_DistFromTHR, SIGNAL("Event_0"), self.method_6) self.connect(self.pnlAPP_InnerEdge, SIGNAL("Event_0"), self.method_6) self.connect(self.pnlName, SIGNAL("Event_0"), self.method_6) self.modified = False self.criteria = None
def create_doc_tab_populate_combobox(self): """ Creates the supporting document component widget. """ self.doc_tab_data() self.docs_tab = QTabWidget() self.docs_tab_index = OrderedDict() for i, (id, doc) in enumerate(self.doc_types.iteritems()): self.docs_tab_index[doc] = i # the tab widget containing the document widget layout # and the child of the tab. tab_widget = QWidget() tab_widget.setObjectName(doc) # The layout of the tab widget cont_layout = QVBoxLayout(tab_widget) cont_layout.setObjectName( u'widget_layout_{}'.format(doc) ) # the scroll area widget inside the tab widget. scroll_area = QScrollArea(tab_widget) scroll_area.setFrameShape(QFrame.NoFrame) scroll_area.setObjectName( u'tab_scroll_area_{}'.format(doc) ) layout_widget = QWidget() # the widget the is under the scroll area content and # the widget containing the document widget layout # This widget is hidden and shown based on the STR number layout_widget.setObjectName( u'widget_{}'.format(doc) ) doc_widget_layout = QVBoxLayout(layout_widget) doc_widget_layout.setObjectName( u'doc_widget_layout_{}'.format( doc ) ) doc_widget = QWidget() doc_widget.setObjectName( u'doc_widget_{}_{}'.format(doc, self.str_number) ) doc_widget_layout.addWidget(doc_widget) # the layout containing document widget. ### This is the layout that is registered to add uploaded # supporting documents widgets into. tab_layout = QVBoxLayout(doc_widget) tab_layout.setObjectName( u'layout_{}_{}'.format(doc, self.str_number) ) scroll_area.setWidgetResizable(True) scroll_area.setWidget(layout_widget) cont_layout.addWidget(scroll_area) # Add the tab widget with the document # type name to create a tab. self.docs_tab.addTab(tab_widget, doc) self.container_box.addWidget(self.docs_tab, 1) if len(self.str_numbers) == 1: self.doc_type_cbo.addItem(doc, id)
class AdvancedSearch(EntityEditorDialog): def __init__(self, entity, parent): EntityEditorDialog.__init__(self, entity, parent=parent) self.parent = parent def _init_gui(self): # Setup base elements self.gridLayout = QGridLayout(self) self.gridLayout.setObjectName('glMain') self.gridLayout.addLayout(self.vlNotification, 0, 0, 1, 1) QApplication.processEvents() column_widget_area = self._setup_columns_content_area() self.gridLayout.addWidget(column_widget_area, 1, 0, 1, 1) QApplication.processEvents() # Add notification for mandatory columns if applicable next_row = 2 # Set title search_trans = self.tr('Advanced Search') if self._entity.label is not None: if self._entity.label != '': title_str = self._entity.label else: title_str = format_name(self._entity.short_name) else: title_str = format_name(self._entity.short_name) title = u'{0} {1}'.format(title_str, search_trans) self.do_not_check_dirty = True self.setWindowTitle(title) # if self.has_mandatory: # self.required_fields_lbl = QLabel(self) # msg = self.tr( # 'Please fill out all required (*) fields.' # ) # msg = self._highlight_asterisk(msg) # self.required_fields_lbl.setText(msg) # self.gridLayout.addWidget( # self.required_fields_lbl, next_row, 0, 1, 2 # ) # # Bump up row reference # next_row += 1 self.buttonBox = QDialogButtonBox(self) self.buttonBox.setObjectName('buttonBox') self.gridLayout.addWidget(self.buttonBox, next_row, 0, 1, 1) self.buttonBox.setOrientation(Qt.Horizontal) self.search = QPushButton( QApplication.translate('EntityEditorDialog', 'Search')) self.buttonBox.addButton(self.search, QDialogButtonBox.ActionRole) self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel) self.search.clicked.connect(self.on_search) # # # # edit model, collect model # # adding new record for child # # # Saving in parent editor # if not isinstance(self._parent._parent, EntityEditorDialog): # # adding a new record # if self.edit_model is None: # # saving when digitizing. # if self.collect_model: # self.buttonBox.accepted.connect(self.on_model_added) # # saving parent editor # else: # self.buttonBox.accepted.connect(self.save_parent_editor) # self.save_new_button.clicked.connect(self.save_and_new) # # updating existing record # else: # if not self.collect_model: # # updating existing record of the parent editor # self.buttonBox.accepted.connect(self.save_parent_editor) # else: # self.buttonBox.accepted.connect(self.on_model_added) # # Saving in child editor # else: # # save and new record # if self.edit_model is None: # self.buttonBox.accepted.connect(self.on_child_saved) # self.save_new_button.clicked.connect( # lambda: self.on_child_saved(True) # ) # # else: # # When updating an existing child editor save to the db # self.buttonBox.accepted.connect( # self.on_child_saved # ) # #self.buttonBox.accepted.connect(self.submit) # self.buttonBox.rejected.connect(self.cancel) def on_search(self): search_data = {} for column in self._entity.columns.values(): if column.name in entity_display_columns(self._entity): if column.name == 'id': continue handler = self.attribute_mappers[column.name].valueHandler() value = handler.value() if value != handler.default() and bool(value): search_data[column.name] = value # self.search_db(search_data) result = self.search_db_raw(search_data) self.parent._tableModel.removeRows(0, self.parent._tableModel.rowCount()) if result is not None: found = QApplication.translate('AdvancedSearch', 'records found') new_title = '{} - {} {}'.format(self.title, result.rowcount, found) if result.rowcount > 3000: title = QApplication.translate('AdvancedSearch', 'Advanced Search') message = QApplication.translate( 'AdvancedSearch', 'The search result returned {0} records, which is above the ' 'search result limit. <br>Would you like to see the first 3000 ' 'records?'.format("{:,}".format(result.rowcount))) res, chk_result = simple_dialog(self, title, message) if res: self.setWindowTitle(new_title) self.parent._initializeData(result) else: return else: self.setWindowTitle(new_title) self.parent._initializeData(result) def search_db(self, search_data): ent_model_obj = self.ent_model() # query = ent_model_obj.queryObject() for attr, value in search_data.iteritems(): ent_model_obj.queryObject().filter( getattr(self.ent_model(), attr) == value) # now we can run the query # print ent_model_obj.queryObject(), vars(ent_model_obj.queryObject()) # print str(ent_model_obj.queryObject()) results = ent_model_obj.queryObject().all() def search_db_raw(self, search_data): sql = u"SELECT * FROM {} WHERE ".format(self._entity.name) # query = ent_model_obj.queryObject() param = [] if len(search_data) == 0: return None for attr, value in search_data.iteritems(): if isinstance(value, (int, float)): param.append(u'{} = {}'.format(unicode(attr), unicode(value))) if isinstance(value, (unicode, str)): param.append(u"{} = '{}'".format(unicode(attr), unicode(value))) final_sql = u'{} {}'.format(sql, ' AND '.join(param)) # sql_text = text(final_sql) results = fetch_with_filter(final_sql) # now we can run the query return results def _setup_columns_content_area(self): # Only use this if entity supports documents # self.entity_tab_widget = None self.doc_widget = None self.entity_scroll_area = QScrollArea(self) self.entity_scroll_area.setFrameShape(QFrame.NoFrame) self.entity_scroll_area.setWidgetResizable(True) self.entity_scroll_area.setObjectName('scrollArea') # Grid layout for controls self.gl = QGridLayout(self.scroll_widget_contents) self.gl.setObjectName('gl_widget_contents') # Append column labels and widgets table_name = self._entity.name columns = table_column_names(table_name) # Iterate entity column and assert if they exist row_id = 0 for c, column_widget in self.column_widgets.iteritems(): if c.name in self.exclude_columns: continue if isinstance(c, MultipleSelectColumn): continue if not c.name in columns and not isinstance(c, VirtualColumn): continue if column_widget is not None: header = c.ui_display() self.c_label = QLabel(self.scroll_widget_contents) self.c_label.setText(header) self.gl.addWidget(self.c_label, row_id, 0, 1, 1) if c.TYPE_INFO == 'AUTO_GENERATED': column_widget.setReadOnly(False) column_widget.btn_load.hide() self.gl.addWidget(column_widget, row_id, 1, 1, 1) col_name = c.name # Add widget to MapperMixin collection self.addMapping(col_name, column_widget, c.mandatory, pseudoname=c.ui_display()) # Bump up row_id row_id += 1 self.entity_scroll_area.setWidget(self.scroll_widget_contents) if self.entity_tab_widget is None: self.entity_tab_widget = QTabWidget(self) # Check if there are children and add foreign key browsers # Add primary tab if necessary self._add_primary_attr_widget() # self.entity_tab_widget.setTabEnabled(0, False) # enable/disable the tab # set the style sheet self.setStyleSheet( "QTabBar::tab::selected {width: 0; height: 0; margin: 0; " "padding: 0; border: none;} ") # Return the correct widget if self.entity_tab_widget is not None: return self.entity_tab_widget return self.entity_scroll_area def closeEvent(self, event): ''' Raised when a request to close the window is received. Check the dirty state of input controls and prompt user to save if dirty. ''' event.accept() def cancel(self): ''' Slot for closing the dialog. Checks the dirty state first before closing. ''' self.reject()
class AdvancedSearch(EntityEditorDialog): def __init__(self, entity, parent): EntityEditorDialog.__init__(self, entity, parent=parent) self.parent = parent def _init_gui(self): # Setup base elements self.gridLayout = QGridLayout(self) self.gridLayout.setObjectName('glMain') self.gridLayout.addLayout( self.vlNotification, 0, 0, 1, 1 ) QApplication.processEvents() column_widget_area = self._setup_columns_content_area() self.gridLayout.addWidget( column_widget_area, 1, 0, 1, 1 ) QApplication.processEvents() # Add notification for mandatory columns if applicable next_row = 2 # Set title search_trans = self.tr('Advanced Search') if self._entity.label is not None: if self._entity.label != '': title_str = self._entity.label else: title_str = format_name(self._entity.short_name) else: title_str = format_name(self._entity.short_name) title = u'{0} {1}'.format(title_str, search_trans) self.do_not_check_dirty = True self.setWindowTitle(title) # if self.has_mandatory: # self.required_fields_lbl = QLabel(self) # msg = self.tr( # 'Please fill out all required (*) fields.' # ) # msg = self._highlight_asterisk(msg) # self.required_fields_lbl.setText(msg) # self.gridLayout.addWidget( # self.required_fields_lbl, next_row, 0, 1, 2 # ) # # Bump up row reference # next_row += 1 self.buttonBox = QDialogButtonBox(self) self.buttonBox.setObjectName('buttonBox') self.gridLayout.addWidget( self.buttonBox, next_row, 0, 1, 1 ) self.buttonBox.setOrientation(Qt.Horizontal) self.search = QPushButton( QApplication.translate( 'EntityEditorDialog', 'Search' ) ) self.buttonBox.addButton( self.search, QDialogButtonBox.ActionRole ) self.buttonBox.setStandardButtons( QDialogButtonBox.Cancel ) self.search.clicked.connect(self.on_search) # # # # edit model, collect model # # adding new record for child # # # Saving in parent editor # if not isinstance(self._parent._parent, EntityEditorDialog): # # adding a new record # if self.edit_model is None: # # saving when digitizing. # if self.collect_model: # self.buttonBox.accepted.connect(self.on_model_added) # # saving parent editor # else: # self.buttonBox.accepted.connect(self.save_parent_editor) # self.save_new_button.clicked.connect(self.save_and_new) # # updating existing record # else: # if not self.collect_model: # # updating existing record of the parent editor # self.buttonBox.accepted.connect(self.save_parent_editor) # else: # self.buttonBox.accepted.connect(self.on_model_added) # # Saving in child editor # else: # # save and new record # if self.edit_model is None: # self.buttonBox.accepted.connect(self.on_child_saved) # self.save_new_button.clicked.connect( # lambda: self.on_child_saved(True) # ) # # else: # # When updating an existing child editor save to the db # self.buttonBox.accepted.connect( # self.on_child_saved # ) # #self.buttonBox.accepted.connect(self.submit) # self.buttonBox.rejected.connect(self.cancel) def on_search(self): search_data = {} for column in self._entity.columns.values(): if column.name in entity_display_columns(self._entity): if column.name == 'id': continue handler = self.attribute_mappers[ column.name].valueHandler() value = handler.value() if value != handler.default() and bool(value): search_data[column.name] = value # self.search_db(search_data) result = self.search_db_raw(search_data) self.parent._tableModel.removeRows(0, self.parent._tableModel.rowCount()) if result is not None: found = QApplication.translate('AdvancedSearch', 'records found') new_title = '{} - {} {}'.format(self.title, result.rowcount, found) if result.rowcount > 3000: title = QApplication.translate( 'AdvancedSearch', 'Advanced Search' ) message = QApplication.translate( 'AdvancedSearch', 'The search result returned {0} records, which is above the ' 'search result limit. <br>Would you like to see the first 3000 ' 'records?'.format("{:,}".format(result.rowcount )) ) res, chk_result = simple_dialog(self, title, message) if res: self.setWindowTitle(new_title) self.parent._initializeData(result) else: return else: self.setWindowTitle(new_title) self.parent._initializeData(result) def search_db(self, search_data): ent_model_obj = self.ent_model() # query = ent_model_obj.queryObject() for attr, value in search_data.iteritems(): ent_model_obj.queryObject().filter( getattr(self.ent_model(), attr) == value) # now we can run the query # print ent_model_obj.queryObject(), vars(ent_model_obj.queryObject()) # print str(ent_model_obj.queryObject()) results = ent_model_obj.queryObject().all() def search_db_raw(self, search_data): sql = u"SELECT * FROM {} WHERE ".format(self._entity.name) # query = ent_model_obj.queryObject() param = [] if len(search_data) == 0: return None for attr, value in search_data.iteritems(): if isinstance(value, (int, float)): param.append(u'{} = {}'.format(unicode(attr), unicode(value))) if isinstance(value, (unicode, str)): param.append(u"{} = '{}'".format(unicode(attr), unicode(value))) final_sql = u'{} {}'.format(sql, ' AND '.join(param)) # sql_text = text(final_sql) results = fetch_with_filter(final_sql) # now we can run the query return results def _setup_columns_content_area(self): # Only use this if entity supports documents # self.entity_tab_widget = None self.doc_widget = None self.entity_scroll_area = QScrollArea(self) self.entity_scroll_area.setFrameShape(QFrame.NoFrame) self.entity_scroll_area.setWidgetResizable(True) self.entity_scroll_area.setObjectName('scrollArea') # Grid layout for controls self.gl = QGridLayout(self.scroll_widget_contents) self.gl.setObjectName('gl_widget_contents') # Append column labels and widgets table_name = self._entity.name columns = table_column_names(table_name) # Iterate entity column and assert if they exist row_id = 0 for c, column_widget in self.column_widgets.iteritems(): if c.name in self.exclude_columns: continue if isinstance(c, MultipleSelectColumn): continue if not c.name in columns and not isinstance(c, VirtualColumn): continue if column_widget is not None: header = c.ui_display() self.c_label = QLabel(self.scroll_widget_contents) self.c_label.setText(header) self.gl.addWidget(self.c_label, row_id, 0, 1, 1) if c.TYPE_INFO == 'AUTO_GENERATED': column_widget.setReadOnly(False) column_widget.btn_load.hide() self.gl.addWidget(column_widget, row_id, 1, 1, 1) col_name = c.name # Add widget to MapperMixin collection self.addMapping( col_name, column_widget, c.mandatory, pseudoname=c.ui_display() ) # Bump up row_id row_id += 1 self.entity_scroll_area.setWidget(self.scroll_widget_contents) if self.entity_tab_widget is None: self.entity_tab_widget = QTabWidget(self) # Check if there are children and add foreign key browsers # Add primary tab if necessary self._add_primary_attr_widget() # self.entity_tab_widget.setTabEnabled(0, False) # enable/disable the tab # set the style sheet self.setStyleSheet( "QTabBar::tab::selected {width: 0; height: 0; margin: 0; " "padding: 0; border: none;} ") # Return the correct widget if self.entity_tab_widget is not None: return self.entity_tab_widget return self.entity_scroll_area def closeEvent(self, event): ''' Raised when a request to close the window is received. Check the dirty state of input controls and prompt user to save if dirty. ''' event.accept() def cancel(self): ''' Slot for closing the dialog. Checks the dirty state first before closing. ''' self.reject()