Beispiel #1
0
 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
Beispiel #2
0
    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)
Beispiel #4
0
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)
Beispiel #5
0
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
Beispiel #6
0
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)
Beispiel #8
0
    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
Beispiel #9
0
    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)
Beispiel #10
0
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()
Beispiel #11
0
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()