Esempio n. 1
0
    def setData(self, index, value, role=Qt.EditRole):
        """Value should be a function taking no arguments that returns the data to
        be set

        This function will then be called in the model_thread
        """
        assert object_thread(self)
        #
        # prevent data of being set in rows not actually in this model
        #
        if (not index.isValid()) or (index.model() != self):
            return False

        if role == Qt.EditRole:

            # if the field is not editable, don't waste any time and get out of here
            # editable should be explicitely True, since the _get_field_attribute_value
            # might return intermediary values such as ValueLoading ??
            if self._get_field_attribute_value(index, "editable") != True:
                return

            locker = QtCore.QMutexLocker(self._mutex)
            flushed = index.row() not in self.unflushed_rows
            self.unflushed_rows.add(index.row())
            self._update_requests.append((flushed, index.row(), index.column(), value))
            locker.unlock()
            post(self._handle_update_requests)

        return True
Esempio n. 2
0
 def _current_index_changed(self, current_index):
     assert object_thread(self)
     for tab_index, (first_column,
                     last_column) in six.iteritems(self.groups):
         for column_index in range(first_column, last_column):
             self.table_widget.setColumnHidden(column_index,
                                               tab_index != current_index)
Esempio n. 3
0
 def __init__(self, gui_context, parent=None):
     QtWidgets.QLabel.__init__(self, parent)
     assert object_thread(self)
     self.gui_context = gui_context
     self.setFont(self._number_of_rows_font)
     self.selected_count = 0
     self.set_item_view(gui_context.item_view)
Esempio n. 4
0
    def handle_entity_update(self, sender, entity):
        """Handles the entity signal, indicating that the model is out of
        date"""
        assert object_thread(self)
        self.logger.debug( '%s %s received entity update signal' % \
                     ( self.__class__.__name__, self.admin.get_verbose_name() ) )
        if sender != self:
            try:
                row = self.display_cache.get_row_by_entity(entity)
            except KeyError:
                self.logger.debug('entity not in cache')
                return
            #
            # Because the entity is updated, it might no longer be in our
            # collection, therefore, make sure we don't access the collection
            # to strip data of the entity
            #
            def create_entity_update(row, entity):
                def entity_update():
                    columns = self._columns
                    self._add_data(columns, row, entity)
                    return row

                return entity_update

            post(create_entity_update(row, entity), self._emit_changes)
        else:
            self.logger.debug('duplicate update')
Esempio n. 5
0
 def __init__(self, gui_context, parent):
     QtWidgets.QWidget.__init__(self, parent)
     assert object_thread(self)
     self.gui_context = gui_context
     layout = QtWidgets.QVBoxLayout()
     widget_layout = QtWidgets.QHBoxLayout()
     search = self.search_widget(self)
     self.setFocusProxy(search)
     search.expand_search_options_signal.connect(self.expand_search_options)
     title = UserTranslatableLabel(
         self.gui_context.admin.get_verbose_name_plural(), self)
     title.setFont(self._title_font)
     widget_layout.addWidget(title)
     widget_layout.addWidget(search)
     number_of_rows = self.rows_widget(gui_context, parent=self)
     number_of_rows.setObjectName('number_of_rows')
     widget_layout.addWidget(number_of_rows)
     layout.addLayout(widget_layout, 0)
     self._expanded_filters_created = False
     self._expanded_search = QtWidgets.QWidget()
     self._expanded_search.hide()
     layout.addWidget(self._expanded_search, 1)
     self.setLayout(layout)
     self.setSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed)
     self.search = search
Esempio n. 6
0
    def set_layouts(self):
        assert object_thread( self )
        self._vlayout = QVBoxLayout()
        self._vlayout.setSpacing(0)
        self._vlayout.setContentsMargins(0,0,0,0)

        # needed in case we have a widget that changes the size
        # of the widget and can be hidden
        # this prevents the ChangeObjects dialog from being scaleable,
        # therefor commented out
        #self._vlayout.setSizeConstraint(QLayout.SetFixedSize)

        banner_layout = QGridLayout()
        banner_layout.setColumnStretch(0, 1)
        banner_layout.addWidget(QLabel(), 0, 1, Qt.AlignRight)
        banner_layout.addLayout(QVBoxLayout(), 0, 0)

        # TODO: allow banner widget to be supplied
        banner_widget = QWidget()
        banner_widget.setLayout(banner_layout)

        self._vlayout.addWidget(banner_widget)
        self._vlayout.addWidget(HSeparator())
        self._vlayout.addWidget(QFrame(), 1)
        self._vlayout.addWidget(HSeparator())
        self._vlayout.addWidget(QWidget())
        self.setLayout(self._vlayout)
Esempio n. 7
0
 def _emit_changes(self, row):
     assert object_thread(self)
     if row != None:
         column_count = self.columnCount()
         top_left = self.index(row, 0)
         bottom_right = self.index(row, column_count - 1)
         self.dataChanged.emit(top_left, bottom_right)
Esempio n. 8
0
 def set_field_attributes(self, editable = True,
                                background_color = None,
                                tooltip = None, **kwargs):
     assert object_thread( self )
     self.set_enabled(editable)
     self.set_background_color(background_color)
     self.layout().itemAt(0).widget().setToolTip(unicode(tooltip or ''))
Esempio n. 9
0
 def keyPressEvent(self, e):
     assert object_thread(self)
     if self.hasFocus() and e.key() in (QtCore.Qt.Key_Enter,
                                        QtCore.Qt.Key_Return):
         self.keyboard_selection_signal.emit()
     else:
         super(TableWidget, self).keyPressEvent(e)
Esempio n. 10
0
    def remove_rows( self, rows, delete = True ):
        """Remove the entity associated with this row from this collection
        @param rows: a list with the numbers of the rows to remove
        @param delete: delete the entity as well
        
        The rows_removed signal will be emitted when the removal was 
        successful, otherwise the exception_signal will be emitted.
        """
        assert object_thread( self )
        self.logger.debug( 'remove rows' )

        def create_delete_function( rows ):

            def delete_function():
                """Remove all rows from the underlying collection
                :return: the number of rows left in the collection"""
                try:
                    objects_to_remove = [self._get_object( row ) for row in rows]
                    self.remove_objects( objects_to_remove, delete )
                    self.rows_removed_signal.emit()
                except Exception, exc:
                    exc_info = register_exception( logger,
                                                   'exception while removing rows',
                                                   exc )
                    self.exception_signal.emit( exc_info )

            return delete_function
Esempio n. 11
0
 def _emit_changes(self, row):
     assert object_thread(self)
     if row != None:
         column_count = self.columnCount()
         top_left = self.index(row, 0)
         bottom_right = self.index(row, column_count - 1)
         self.dataChanged.emit(top_left, bottom_right)
Esempio n. 12
0
    def setData(self, index, value, role=Qt.EditRole):
        """Value should be a function taking no arguments that returns the data to
        be set

        This function will then be called in the model_thread
        """
        assert object_thread(self)
        #
        # prevent data of being set in rows not actually in this model
        #
        if (not index.isValid()) or (index.model() != self):
            return False

        if role == Qt.EditRole:

            # if the field is not editable, don't waste any time and get out of here
            # editable should be explicitely True, since the _get_field_attribute_value
            # might return intermediary values such as ValueLoading ??
            if self._get_field_attribute_value(index, 'editable') != True:
                return

            locker = QtCore.QMutexLocker(self._mutex)
            flushed = (index.row() not in self.unflushed_rows)
            self.unflushed_rows.add(index.row())
            self._update_requests.append(
                (flushed, index.row(), index.column(), value))
            locker.unlock()
            post(self._handle_update_requests)

        return True
Esempio n. 13
0
 def headerData(self, section, orientation, role):
     """In case the columns have not been set yet, don't even try to get
     information out of them
     """
     assert object_thread(self)
     if orientation == Qt.Vertical:
         if role == Qt.SizeHintRole:
             if self.header_icon != None:
                 return QtCore.QVariant(
                     QtCore.QSize(self.iconSize.width() + 10,
                                  self._vertical_header_height))
             else:
                 # if there is no icon, the line numbers will be displayed, so create some space for those
                 return QtCore.QVariant(
                     QtCore.QSize(
                         QtGui.QFontMetrics(self._header_font).size(
                             Qt.TextSingleLine, str(self._rows)).width() +
                         10, self._vertical_header_height))
         if role == Qt.DecorationRole:
             return self.form_icon
         elif role == Qt.DisplayRole:
             if self.header_icon != None:
                 return QtCore.QVariant('')
     return super(CollectionProxy, self).headerData(section, orientation,
                                                    role)
Esempio n. 14
0
 def __init__(self, lines_per_row=1, parent=None):
     QtWidgets.QTableView.__init__(self, parent)
     logger.debug('create TableWidget')
     assert object_thread(self)
     self._columns_changed = dict()
     self.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
     self.setEditTriggers(QtWidgets.QAbstractItemView.SelectedClicked
                          | QtWidgets.QAbstractItemView.DoubleClicked
                          | QtWidgets.QAbstractItemView.CurrentChanged)
     self.setSizePolicy(QtGui.QSizePolicy.Expanding,
                        QtGui.QSizePolicy.Expanding)
     self.horizontalHeader().setClickable(True)
     self._header_font_required = QtWidgets.QApplication.font()
     self._header_font_required.setBold(True)
     line_height = QtGui.QFontMetrics(
         QtWidgets.QApplication.font()).lineSpacing()
     self._minimal_row_height = line_height * lines_per_row + 2 * self.margin
     self.verticalHeader().setDefaultSectionSize(self._minimal_row_height)
     self.setHorizontalScrollMode(
         QtWidgets.QAbstractItemView.ScrollPerPixel)
     self.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
     self.horizontalHeader().sectionClicked.connect(
         self.horizontal_section_clicked)
     self.horizontalHeader().sectionResized.connect(
         self._save_section_width)
Esempio n. 15
0
 def set_filters_and_actions(self, filters_and_actions):
     """sets filters for the tableview"""
     assert object_thread(self)
     filters, actions = filters_and_actions
     from camelot.view.controls.filterlist import FilterList
     from camelot.view.controls.actionsbox import ActionsBox
     logger.debug('setting filters for tableview')
     filters_widget = self.findChild(FilterList, 'filters')
     actions_widget = self.findChild(ActionsBox, 'actions')
     if filters_widget:
         filters_widget.filters_changed_signal.disconnect(
             self.rebuild_query)
         self.filters_layout.removeWidget(filters_widget)
         filters_widget.deleteLater()
     if actions_widget:
         self.filters_layout.removeWidget(actions_widget)
         actions_widget.deleteLater()
     if filters:
         splitter = self.findChild(QtGui.QWidget, 'splitter')
         filters_widget = FilterList(filters, parent=splitter)
         filters_widget.setObjectName('filters')
         self.filters_layout.addWidget(filters_widget)
         filters_widget.filters_changed_signal.connect(self.rebuild_query)
     #
     # filters might have default values, so we can only build the queries now
     #
     self.rebuild_query()
     if actions:
         actions_widget = ActionsBox(parent=self,
                                     gui_context=self.gui_context)
         actions_widget.setObjectName('actions')
         actions_widget.set_actions(actions)
         self.filters_layout.addWidget(actions_widget)
Esempio n. 16
0
    def set_layouts(self):
        assert object_thread(self)
        self._vlayout = QtWidgets.QVBoxLayout()
        self._vlayout.setSpacing(0)
        self._vlayout.setContentsMargins(0, 0, 0, 0)

        # needed in case we have a widget that changes the size
        # of the widget and can be hidden
        # this prevents the ChangeObjects dialog from being scaleable,
        # therefor commented out
        #self._vlayout.setSizeConstraint(QLayout.SetFixedSize)

        banner_layout = QtWidgets.QGridLayout()
        banner_layout.setColumnStretch(0, 1)
        banner_layout.addWidget(QtWidgets.QLabel(), 0, 1, Qt.AlignRight)
        banner_layout.addLayout(QtWidgets.QVBoxLayout(), 0, 0)

        # TODO: allow banner widget to be supplied
        banner_widget = QtWidgets.QWidget()
        banner_widget.setLayout(banner_layout)

        self._vlayout.addWidget(banner_widget)
        self._vlayout.addWidget(HSeparator())
        self._vlayout.addWidget(QtWidgets.QFrame(), 1)
        self._vlayout.addWidget(HSeparator())
        self._vlayout.addWidget(QtWidgets.QWidget())
        self.setLayout(self._vlayout)
Esempio n. 17
0
 def set_filters_and_actions( self, filters_and_actions ):
     """sets filters for the tableview"""
     assert object_thread( self )
     filters, actions = filters_and_actions
     from camelot.view.controls.filterlist import FilterList
     from camelot.view.controls.actionsbox import ActionsBox
     logger.debug( 'setting filters for tableview' )
     filters_widget = self.findChild(FilterList, 'filters')
     actions_widget = self.findChild(ActionsBox, 'actions')
     if filters_widget:
         filters_widget.filters_changed_signal.disconnect( self.rebuild_query )
         self.filters_layout.removeWidget(filters_widget)
         filters_widget.deleteLater()
     if actions_widget:
         self.filters_layout.removeWidget(actions_widget)
         actions_widget.deleteLater()
     if filters:
         splitter = self.findChild( QtGui.QWidget, 'splitter' )
         filters_widget = FilterList( filters, parent=splitter )
         filters_widget.setObjectName('filters')
         self.filters_layout.addWidget( filters_widget )
         filters_widget.filters_changed_signal.connect( self.rebuild_query )
     #
     # filters might have default values, so we can only build the queries now
     #
     self.rebuild_query()
     if actions:
         actions_widget = ActionsBox( parent = self,
                                      gui_context = self.gui_context )
         actions_widget.setObjectName( 'actions' )
         actions_widget.set_actions( actions )
         self.filters_layout.addWidget( actions_widget )
Esempio n. 18
0
 def delete_selected_rows(self):
     assert object_thread( self )
     logger.debug( 'delete selected rows called' )
     confirmed = True
     rows = set( index.row() for index in self.selectedIndexes() )
     if not rows:
         return
     if self._admin.get_delete_mode()=='on_confirm':
         if QtGui.QMessageBox.question(self,
                                       _('Please confirm'),
                                       unicode(self._admin.get_delete_message(None)),
                                       QtGui.QMessageBox.Yes,
                                       QtGui.QMessageBox.No) == QtGui.QMessageBox.No:
             confirmed = False
     if confirmed:
         #
         # if there is an open editor on a row that will be deleted, there
         # might be an assertion failure in QT, or the data of the editor 
         # might be pushed to the row that replaces the deleted one
         #
         progress_dialog = ProgressDialog(_('Removing'))
         self.model().rows_removed_signal.connect( progress_dialog.finished )
         self.model().exception_signal.connect( progress_dialog.exception )
         self.close_editor()
         self.model().remove_rows( set( rows ) )
         progress_dialog.exec_()
Esempio n. 19
0
 def _fill_expanded_search_options(self, columns):
     """Given the columns in the table view, present the user
     with more options to filter rows in the table
     :param columns: a list of tuples with field names and attributes
     """
     assert object_thread( self )
     from camelot.view.controls.filter_operator import FilterOperator
     from camelot.view.flowlayout import FlowLayout
     layout = FlowLayout()
     layout.setSpacing( 2 )
     layout.setContentsMargins( 0, 0, 0, 0 )
     for i, (field, attributes) in enumerate(columns):
         if 'operators' in attributes and attributes['operators']:
             box = QtGui.QGroupBox()
             box_layout = QtGui.QVBoxLayout()
             box_layout.setContentsMargins( 1, 1, 1, 1 )
             widget = FilterOperator( self._admin.entity,
                                      field, attributes,
                                      box )
             box_layout.addWidget( widget )
             box.setLayout( box_layout )
             widget.filter_changed_signal.connect( self._filter_changed )
             layout.addWidget( box )
     #layout.addStretch()
     self._expanded_search.setLayout( layout )
     self._expanded_filters_created = True
Esempio n. 20
0
 def setRowCount(self, rows):
     """Callback method to set the number of rows
     @param rows the new number of rows
     """
     assert object_thread(self)
     self._rows = rows
     self.layoutChanged.emit()
Esempio n. 21
0
    def set_admin(self, admin):
        """Switch to a different subclass, where admin is the admin object of the
        subclass"""
        assert object_thread(self)
        logger.debug('set_admin called')
        self.admin = admin
        if self.table:
            self.table.model().layoutChanged.disconnect(
                self.tableLayoutChanged)
            self.table_layout.removeWidget(self.table)
            self.table.deleteLater()
            self.table.model().deleteLater()
        splitter = self.findChild(QtGui.QWidget, 'splitter')
        self.table = self.AdminTableWidget(self.admin, splitter)
        self.table.setObjectName('AdminTableWidget')
        new_model = self.create_table_model(admin)
        self.table.setModel(new_model)
        self.table.verticalHeader().sectionClicked.connect(self.sectionClicked)
        self.table.keyboard_selection_signal.connect(
            self.on_keyboard_selection_signal)
        self.table.model().layoutChanged.connect(self.tableLayoutChanged)
        self.tableLayoutChanged()
        self.table_layout.insertWidget(1, self.table)
        self.gui_context = self.application_gui_context.copy(
            ListActionGuiContext)
        self.gui_context.view = self
        self.gui_context.admin = self.admin
        self.gui_context.item_view = self.table

        def get_filters_and_actions():
            return (admin.get_filters(), admin.get_list_actions())

        post(get_filters_and_actions, self.set_filters_and_actions)
Esempio n. 22
0
 def __init__( self, parent, admin ):
     QtGui.QWidget.__init__( self, parent )
     assert object_thread( self )
     self._admin = admin
     layout = QtGui.QVBoxLayout()
     widget_layout = QtGui.QHBoxLayout()
     search = self.search_widget( self )
     search.expand_search_options_signal.connect(
         self.expand_search_options )
     title = UserTranslatableLabel( admin.get_verbose_name_plural(),
                                    self )
     title.setFont( self._title_font )
     widget_layout.addWidget( title )
     widget_layout.addWidget( search )
     if self.rows_widget:
         self.number_of_rows = self.rows_widget( self )
         widget_layout.addWidget( self.number_of_rows )
     else:
         self.number_of_rows = None
     layout.addLayout( widget_layout, 0 )
     self._expanded_filters_created = False
     self._expanded_search = QtGui.QWidget()
     self._expanded_search.hide()
     layout.addWidget( self._expanded_search, 1 )
     self.setLayout( layout )
     self.setSizePolicy( QSizePolicy.Minimum, QSizePolicy.Fixed )
     self.setNumberOfRows( 0 )
     self.search = search
Esempio n. 23
0
 def _fill_expanded_search_options(self, columns):
     """Given the columns in the table view, present the user
     with more options to filter rows in the table
     :param columns: a list of tuples with field names and attributes
     """
     assert object_thread(self)
     from camelot.view.controls.filter_operator import FilterOperator
     from camelot.view.flowlayout import FlowLayout
     layout = FlowLayout()
     layout.setSpacing(2)
     layout.setContentsMargins(0, 0, 0, 0)
     for i, (field, attributes) in enumerate(columns):
         if 'operators' in attributes and attributes['operators']:
             box = QtGui.QGroupBox()
             box_layout = QtGui.QVBoxLayout()
             box_layout.setContentsMargins(1, 1, 1, 1)
             widget = FilterOperator(self._admin.entity, field, attributes,
                                     box)
             box_layout.addWidget(widget)
             box.setLayout(box_layout)
             widget.filter_changed_signal.connect(self._filter_changed)
             layout.addWidget(box)
     #layout.addStretch()
     self._expanded_search.setLayout(layout)
     self._expanded_filters_created = True
Esempio n. 24
0
 def __init__(self, parent, admin):
     QtGui.QWidget.__init__(self, parent)
     assert object_thread(self)
     self._admin = admin
     layout = QtGui.QVBoxLayout()
     widget_layout = QtGui.QHBoxLayout()
     search = self.search_widget(self)
     search.expand_search_options_signal.connect(self.expand_search_options)
     title = UserTranslatableLabel(admin.get_verbose_name_plural(), self)
     title.setFont(self._title_font)
     widget_layout.addWidget(title)
     widget_layout.addWidget(search)
     if self.rows_widget:
         self.number_of_rows = self.rows_widget(self)
         widget_layout.addWidget(self.number_of_rows)
     else:
         self.number_of_rows = None
     layout.addLayout(widget_layout, 0)
     self._expanded_filters_created = False
     self._expanded_search = QtGui.QWidget()
     self._expanded_search.hide()
     layout.addWidget(self._expanded_search, 1)
     self.setLayout(layout)
     self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
     self.setNumberOfRows(0)
     self.search = search
Esempio n. 25
0
 def handleRowUpdate(self, row):
     """Handles the update of a row when this row might be out of date"""
     assert object_thread(self)
     self.display_cache.delete_by_row(row)
     self.edit_cache.delete_by_row(row)
     self.attributes_cache.delete_by_row(row)
     self.dataChanged.emit(self.index(row, 0), self.index(row, self.columnCount() - 1))
Esempio n. 26
0
    def set_admin( self, admin ):
        """Switch to a different subclass, where admin is the admin object of the
        subclass"""
        assert object_thread( self )
        logger.debug('set_admin called')
        self.admin = admin
        if self.table:
            self.table.model().layoutChanged.disconnect( self.tableLayoutChanged )
            self.table_layout.removeWidget(self.table)
            self.table.deleteLater()
            self.table.model().deleteLater()
        splitter = self.findChild( QtGui.QWidget, 'splitter' )
        self.table = self.AdminTableWidget( self.admin, splitter )
        self.table.setObjectName('AdminTableWidget')
        new_model = self.create_table_model( admin )
        self.table.setModel( new_model )
        self.table.verticalHeader().sectionClicked.connect( self.sectionClicked )
        self.table.keyboard_selection_signal.connect(self.on_keyboard_selection_signal)
        self.table.model().layoutChanged.connect( self.tableLayoutChanged )
        self.tableLayoutChanged()
        self.table_layout.insertWidget( 1, self.table )
        self.gui_context = self.application_gui_context.copy( ListActionGuiContext )
        self.gui_context.view = self
        self.gui_context.admin = self.admin
        self.gui_context.item_view = self.table

        def get_filters_and_actions():
            return ( admin.get_filters(), admin.get_list_actions() )

        post( get_filters_and_actions,  self.set_filters_and_actions )
Esempio n. 27
0
 def headerData(self, section, orientation, role):
     """In case the columns have not been set yet, don't even try to get
     information out of them
     """
     assert object_thread(self)
     if orientation == Qt.Vertical:
         if role == Qt.SizeHintRole:
             #
             # sizehint role is requested, for every row, so we have to
             # return a fixed value
             #
             return py_to_variant(self.vertical_header_size)
         #
         # get icon from action state
         #
         action_state = self._get_row_data(section,
                                           self.action_state_cache)[0]
         if action_state not in (None, ValueLoading):
             icon = action_state.icon
             if icon is not None:
                 if role == Qt.DecorationRole:
                     return icon.getQPixmap()
             verbose_name = action_state.verbose_name
             if verbose_name is not None:
                 if role == Qt.DisplayRole:
                     return py_to_variant(six.text_type(verbose_name))
             tooltip = action_state.tooltip
             if tooltip is not None:
                 if role == Qt.ToolTipRole:
                     return py_to_variant(six.text_type(tooltip))
     return self.sourceModel().headerData(section, orientation, role)
Esempio n. 28
0
    def handle_entity_update(self, sender, entity):
        """Handles the entity signal, indicating that the model is out of
        date"""
        assert object_thread(self)
        self.logger.debug(
            "%s %s received entity update signal" % (self.__class__.__name__, self.admin.get_verbose_name())
        )
        if sender != self:
            try:
                row = self.display_cache.get_row_by_entity(entity)
            except KeyError:
                self.logger.debug("entity not in cache")
                return
            #
            # Because the entity is updated, it might no longer be in our
            # collection, therefore, make sure we don't access the collection
            # to strip data of the entity
            #
            def create_entity_update(row, entity):
                def entity_update():
                    columns = self._columns
                    self._add_data(columns, row, entity)
                    return row

                return entity_update

            post(create_entity_update(row, entity), self._emit_changes)
        else:
            self.logger.debug("duplicate update")
Esempio n. 29
0
 def startSearch( self, text ):
     """rebuilds query based on filtering text"""
     assert object_thread( self )
     from camelot.view.search import create_entity_search_query_decorator
     logger.debug( 'search %s' % text )
     self.search_filter = create_entity_search_query_decorator( self.admin, unicode(text) )
     self.rebuild_query()
Esempio n. 30
0
    def sort(self, column, order):
        """reimplementation of the :class:`QtGui.QAbstractItemModel` its sort function"""
        assert object_thread(self)

        def create_sort(column, order):
            def sort():
                unsorted_collection = [(i, o) for i, o in enumerate(self.get_collection())]
                field_name = self._columns[column][0]

                # handle the case of one of the values being None
                def compare_none(line_1, line_2):
                    key_1, key_2 = None, None
                    try:
                        key_1 = getattr(line_1[1], field_name)
                    except Exception, e:
                        logger.error("could not get attribute %s from object" % field_name, exc_info=e)
                    try:
                        key_2 = getattr(line_2[1], field_name)
                    except Exception, e:
                        logger.error("could not get attribute %s from object" % field_name, exc_info=e)
                    if key_1 == None and key_2 == None:
                        return 0
                    if key_1 == None:
                        return -1
                    if key_2 == None:
                        return 1
                    return cmp(key_1, key_2)

                unsorted_collection.sort(cmp=compare_none, reverse=order)
                for j, (i, _o) in enumerate(unsorted_collection):
                    self._sort_and_filter[j] = i
                return len(unsorted_collection)
Esempio n. 31
0
 def setRowCount(self, rows):
     """Callback method to set the number of rows
     @param rows the new number of rows
     """
     assert object_thread(self)
     self._rows = rows
     self.layoutChanged.emit()
Esempio n. 32
0
    def createNew(self):
        assert object_thread( self )

        @model_function
        def get_has_subclasses():
            return len(self.admin.get_subclass_tree())

        post(get_has_subclasses, self.show_new_view)
Esempio n. 33
0
 def handle_entity_create(self, sender, entity):
     """Handles the entity signal, indicating that the model is out of
     date"""
     assert object_thread(self)
     self.logger.debug("received entity create signal")
     # @todo : decide what to do when a new entity has been created,
     #         probably do nothing
     return
Esempio n. 34
0
 def __init__(self, parent, columns_frozen):
     super(FrozenTableWidget, self).__init__(parent)
     assert object_thread( self )
     self.setSelectionBehavior( QtGui.QAbstractItemView.SelectRows )
     self.setEditTriggers( QtGui.QAbstractItemView.SelectedClicked |
                           QtGui.QAbstractItemView.DoubleClicked |
                           QtGui.QAbstractItemView.CurrentChanged )
     self._columns_frozen = columns_frozen
 def wait_on_work(self):
     """Wait for all work to be finished, this function should only be used
     to do unit testing and such, since it will block the calling thread until
     all work is done"""
     assert object_thread( self )
     app = QtCore.QCoreApplication.instance()
     while self.busy():
         app.processEvents()
Esempio n. 36
0
 def setSubclassTree(self, subclasses):
     assert object_thread(self)
     if len(subclasses) > 0:
         from inheritance import SubclassTree
         splitter = self.findChild(QtGui.QWidget, 'splitter')
         class_tree = SubclassTree(self.admin, splitter)
         splitter.insertWidget(0, class_tree)
         class_tree.subclass_clicked_signal.connect(self.set_admin)
Esempio n. 37
0
 def handle_entity_create(self, sender, entity):
     """Handles the entity signal, indicating that the model is out of
     date"""
     assert object_thread(self)
     self.logger.debug('received entity create signal')
     # @todo : decide what to do when a new entity has been created,
     #         probably do nothing
     return
Esempio n. 38
0
 def wait_on_work(self):
     """Wait for all work to be finished, this function should only be used
     to do unit testing and such, since it will block the calling thread until
     all work is done"""
     assert object_thread(self)
     app = QtCore.QCoreApplication.instance()
     while self.busy():
         app.processEvents()
Esempio n. 39
0
 def startSearch(self, text):
     """rebuilds query based on filtering text"""
     assert object_thread(self)
     from camelot.view.search import create_entity_search_query_decorator
     logger.debug('search %s' % text)
     self.search_filter = create_entity_search_query_decorator(
         self.admin, six.text_type(text))
     self.rebuild_query()
Esempio n. 40
0
 def setSubclassTree( self, subclasses ):
     assert object_thread( self )
     if len( subclasses ) > 0:
         from inheritance import SubclassTree
         splitter = self.findChild(QtGui.QWidget, 'splitter' )
         class_tree = SubclassTree( self.admin, splitter )
         splitter.insertWidget( 0, class_tree )
         class_tree.subclass_clicked_signal.connect( self.set_admin )
Esempio n. 41
0
 def set_subclass_tree(self, subclasses):
     assert object_thread(self)
     class_tree = self.findChild(QtWidgets.QWidget, 'class_tree')
     if len(subclasses) > 0:
         class_tree.show()
         class_tree.set_subclasses(subclasses)
     else:
         class_tree.hide()
Esempio n. 42
0
 def flags(self, index):
     """Returns the item flags for the given index"""
     assert object_thread(self)
     flags = Qt.ItemIsEnabled | Qt.ItemIsSelectable
     if self._get_field_attribute_value(index, "editable"):
         flags = flags | Qt.ItemIsEditable
     if self.admin.drop_action != None:
         flags = flags | Qt.ItemIsDropEnabled
     return flags
Esempio n. 43
0
 def __init__( self, 
               gui_context, 
               admin, 
               search_text = None, 
               parent = None ):
     super(TableView, self).__init__( parent )
     assert object_thread( self )
     self.admin = admin
     self.application_gui_context = gui_context
     self.gui_context = gui_context
     post( self.get_title, self.change_title )
     widget_layout = QtGui.QVBoxLayout()
     if self.header_widget:
         self.header = self.header_widget( self, admin )
         widget_layout.addWidget( self.header )
         self.header.search.search_signal.connect( self.startSearch )
         self.header.search.cancel_signal.connect( self.cancelSearch )
         self.header.search.on_arrow_down_signal.connect(self.focusTable)
         if search_text:
             self.header.search.search( search_text )
     else:
         self.header = None
     widget_layout.setSpacing( 0 )
     widget_layout.setContentsMargins(0, 0, 0, 0)
     splitter = QtGui.QSplitter( self )
     splitter.setObjectName('splitter')
     widget_layout.addWidget( splitter )
     table_widget = QtGui.QWidget( self )
     filters_widget = QtGui.QWidget( self )
     self.table_layout = QtGui.QVBoxLayout()
     self.table_layout.setSpacing( 0 )
     self.table_layout.setContentsMargins(0, 0, 0, 0)
     self.table = None
     self.filters_layout = QtGui.QVBoxLayout()
     self.filters_layout.setSpacing( 0 )
     self.filters_layout.setContentsMargins(0, 0, 0, 0)
     self.actions = None
     table_widget.setLayout( self.table_layout )
     filters_widget.setLayout( self.filters_layout )
     #filters_widget.hide()
     self.set_admin( admin )
     splitter.addWidget( table_widget )
     splitter.addWidget( filters_widget )
     self.setLayout( widget_layout )
     self.search_filter = lambda q: q
     shortcut = QtGui.QShortcut(QtGui.QKeySequence(QtGui.QKeySequence.Find), self)
     shortcut.activated.connect( self.activate_search )
     if self.header_widget:
         self.header.filters_changed_signal.connect( self.rebuild_query )
     # give the table widget focus to prevent the header and its search control to
     # receive default focus, as this would prevent the displaying of 'Search...' in the
     # search control, but this conflicts with the MDI, resulting in the window not
     # being active and the menus not to work properly
     #table_widget.setFocus( QtCore.Qt.OtherFocusReason )
     #self.setFocusProxy(table_widget)
     #self.setFocus( QtCore.Qt.OtherFocusReason )
     post( self.admin.get_subclass_tree, self.setSubclassTree )
Esempio n. 44
0
 def expand_search_options(self):
     assert object_thread( self )
     if self._expanded_search.isHidden():
         if not self._expanded_filters_created:
             post( self._admin.get_expanded_search_fields, 
                   self._fill_expanded_search_options )
         self._expanded_search.show()
     else:
         self._expanded_search.hide()
Esempio n. 45
0
 def currentChanged(self, current, previous):
     """When the current index has changed, prevent it to jump to
     a column that is not frozen"""
     assert object_thread( self )
     if current.column() >= self._columns_frozen:
         current = self.model().index( current.row(), -1 )
     if previous.column() >= self._columns_frozen:
         previous = self.model().index( previous.row(), -1 )
     super(FrozenTableWidget, self).currentChanged(current, previous)
Esempio n. 46
0
 def set_field_attributes(self,
                          editable=True,
                          background_color=None,
                          tooltip=None,
                          **kwargs):
     assert object_thread(self)
     self.set_enabled(editable)
     self.set_background_color(background_color)
     self.layout().itemAt(0).widget().setToolTip(unicode(tooltip or ''))
Esempio n. 47
0
 def _emit_changes(self, row, from_column, thru_column):
     assert object_thread(self)
     # emit the headerDataChanged signal, to ensure the row icon is
     # updated
     self.headerDataChanged.emit(Qt.Vertical, row, row)
     if thru_column >= from_column:
         top_left = self.index(row, from_column)
         bottom_right = self.index(row, thru_column)
         self.dataChanged.emit(top_left, bottom_right)
Esempio n. 48
0
 def expand_search_options(self):
     assert object_thread(self)
     if self._expanded_search.isHidden():
         if not self._expanded_filters_created:
             post(self.gui_context.admin.get_expanded_search_filters,
                  self._fill_expanded_search_options)
         self._expanded_search.show()
     else:
         self._expanded_search.hide()
Esempio n. 49
0
 def handleRowUpdate(self, row):
     """Handles the update of a row when this row might be out of date"""
     assert object_thread(self)
     self.display_cache.delete_by_row(row)
     self.edit_cache.delete_by_row(row)
     self.attributes_cache.delete_by_row(row)
     self.dataChanged.emit(self.index(row, 0),
                           self.index(row,
                                      self.columnCount() - 1))
Esempio n. 50
0
 def index(self, row, col, parent=QtCore.QModelIndex()):
     assert object_thread(self)
     if self.hasIndex(row, col, parent):
         #
         # indexes are considered equal when their row, column and internal
         # pointer are equal.  therefor set the internal pointer always to 0.
         #
         return self.createIndex(row, col, 0)
     return QtCore.QModelIndex()
Esempio n. 51
0
 def flags(self, index):
     """Returns the item flags for the given index"""
     assert object_thread(self)
     flags = Qt.ItemIsEnabled | Qt.ItemIsSelectable
     if self._get_field_attribute_value(index, 'editable'):
         flags = flags | Qt.ItemIsEditable
     if self.admin.drop_action != None:
         flags = flags | Qt.ItemIsDropEnabled
     return flags
Esempio n. 52
0
 def index(self, row, col, parent=QtCore.QModelIndex()):
     assert object_thread(self)
     if self.hasIndex(row, col, parent):
         #
         # indexes are considered equal when their row, column and internal
         # pointer are equal.  therefor set the internal pointer always to 0.
         #
         return self.createIndex(row, col, 0)
     return QtCore.QModelIndex()
Esempio n. 53
0
    def data(self, index, role=Qt.DisplayRole):
        """:return: the data at index for the specified role
        This function will return ValueLoading when the data has not
        yet been fetched from the underlying model.  It will then send
        a request to the model thread to fetch this data.  Once the data
        is readily available, the dataChanged signal will be emitted

        Using Qt.UserRole as a role will return all the field attributes
        of the index.
        
        Using Qt.UserRole+1 will return the object of which an attribute
        is displayed in that specific cell
        
        """
        assert object_thread(self)
        if (
            not index.isValid()
            or not (0 <= index.row() <= self.rowCount(index))
            or not (0 <= index.column() <= self.columnCount())
        ):
            return QtCore.QVariant()
        if role in (Qt.EditRole, Qt.DisplayRole):
            if role == Qt.EditRole:
                cache = self.edit_cache
            else:
                cache = self.display_cache
            data = self._get_row_data(index.row(), cache)
            value = data[index.column()]
            if isinstance(value, DelayedProxy):
                value = value()
                # store the created proxy, to prevent recreation of it
                # afterwards.
                data[index.column()] = value
            if isinstance(value, datetime.datetime):
                # Putting a python datetime into a QVariant and returning
                # it to a PyObject seems to be buggy, therefore we chop the
                # microseconds
                if value:
                    value = QtCore.QDateTime(value.year, value.month, value.day, value.hour, value.minute, value.second)
            return QtCore.QVariant(value)
        elif role == Qt.ToolTipRole:
            return QtCore.QVariant(self._get_field_attribute_value(index, "tooltip"))
        elif role == Qt.BackgroundRole:
            return QtCore.QVariant(self._get_field_attribute_value(index, "background_color") or QtCore.QVariant())
        elif role == Qt.UserRole:
            field_attributes = ProxyDict(self._static_field_attributes[index.column()])
            dynamic_field_attributes = self._get_row_data(index.row(), self.attributes_cache)[index.column()]
            if dynamic_field_attributes != ValueLoading:
                field_attributes.update(dynamic_field_attributes)
            return QtCore.QVariant(field_attributes)
        elif role == Qt.UserRole + 1:
            try:
                return QtCore.QVariant(self.edit_cache.get_entity_at_row(index.row()))
            except KeyError:
                return QtCore.QVariant(ValueLoading)
        return QtCore.QVariant()
Esempio n. 54
0
 def set_list_actions(self, actions):
     """sets filters for the tableview"""
     assert object_thread(self)
     actions_widget = self.findChild(ActionsBox, 'actions')
     if actions:
         actions_widget = ActionsBox(parent=self,
                                     gui_context=self.gui_context)
         actions_widget.setObjectName('actions')
         actions_widget.set_actions(actions)
         self.filters_layout.addWidget(actions_widget)
Esempio n. 55
0
 def _set_query(self, query):
     assert object_thread(self)
     if isinstance(self.table.model(), QueryTableProxy):
         # apply the filters on the query, to activate the default filter
         filters_widget = self.findChild(ActionsBox, 'filters')
         if filters_widget is not None:
             for filter_widget in filters_widget.get_action_widgets():
                 filter_widget.run_action()
         self.table.model().set_value(query)
     self.table.clearSelection()
Esempio n. 56
0
 def activated( self, selectedIndex, previousSelectedIndex ):
     assert object_thread( self )
     option = QtGui.QStyleOptionViewItem()
     new_size = self.itemDelegate( selectedIndex ).sizeHint( option,
                                                             selectedIndex )
     row = selectedIndex.row()
     if previousSelectedIndex.row() >= 0:
         previous_row = previousSelectedIndex.row()
         self.setRowHeight( previous_row, self._minimal_row_height )
     self.setRowHeight( row, max( new_size.height(),
                                  self._minimal_row_height ) )
Esempio n. 57
0
 def _save_section_width(self, logical_index, _old_size, new_width ):
     # instead of storing the width immediately, a timer is started to store
     # the width when all event processing is done.  because at this time
     # we cannot yet determine if the section at logical_index is hidden
     # or not
     #
     # there is no need to start the timer, since this is done by the 
     # QAbstractItemView itself for doing the layout, here we only store
     # which column needs to be saved.
     assert object_thread( self )
     self._columns_changed[ logical_index ] = new_width
Esempio n. 58
0
 def tableLayoutChanged( self ):
     assert object_thread( self )
     logger.debug('tableLayoutChanged')
     model = self.table.model()
     if self.header:
         self.header.setNumberOfRows( model.rowCount() )
     item_delegate = model.getItemDelegate()
     if item_delegate:
         self.table.setItemDelegate( item_delegate )
     for i in range( model.columnCount() ):
         self.table.setColumnWidth( i, model.headerData( i, Qt.Horizontal, Qt.SizeHintRole ).toSize().width() )
Esempio n. 59
0
 def setModel(self, model):
     assert object_thread(self)
     table_widget = self.findChild(QtWidgets.QWidget, 'table_widget')
     column_groups = self.findChild(QtWidgets.QWidget, 'column_groups')
     if table_widget is not None:
         model.columnsInserted.connect(column_groups.columns_changed)
         model.columnsRemoved.connect(column_groups.columns_changed)
         model.layoutChanged.connect(column_groups.model_reset)
         model.modelReset.connect(column_groups.model_reset)
         table_widget.setModel(model)
         column_groups.model_reset()
Esempio n. 60
0
 def setModel( self, model ):
     assert object_thread( self )
     table_widget = self.findChild( QtGui.QWidget, 'table_widget' )
     column_groups = self.findChild( QtGui.QWidget, 'column_groups' )
     if table_widget != None:
         model.columnsInserted.connect( column_groups.columns_changed )
         model.columnsRemoved.connect( column_groups.columns_changed )
         model.layoutChanged.connect( column_groups.model_reset )
         model.modelReset.connect( column_groups.model_reset )
         table_widget.setModel( model )
         column_groups.model_reset()