class TabularEditor(Editor): """ A traits UI editor for editing tabular data (arrays, list of tuples, lists of objects, etc). """ #-- Trait Definitions ------------------------------------------------------ # The event fired when a table update is needed: update = Event # The event fired when a simple repaint is needed: refresh = Event # The current set of selected items (which one is used depends upon the # initial state of the editor factory 'multi_select' trait): selected = Any multi_selected = List # The current set of selected item indices (which one is used depends upon # the initial state of the editor factory 'multi_select' trait): selected_row = Int(-1) multi_selected_rows = List(Int) # The most recently actived item and its index: activated = Any(comparison_mode=NO_COMPARE) activated_row = Int(comparison_mode=NO_COMPARE) # The most recent left click data: clicked = Instance('TabularEditorEvent') # The most recent left double click data: dclicked = Instance('TabularEditorEvent') # The most recent right click data: right_clicked = Instance('TabularEditorEvent') # The most recent right double click data: right_dclicked = Instance('TabularEditorEvent') # The most recent column click data: column_clicked = Instance('TabularEditorEvent') # The most recent column click data: column_right_clicked = Instance('TabularEditorEvent') # The event triggering scrolling. scroll_to_row = Event(Int) # Is the tabular editor scrollable? This value overrides the default. scrollable = True # Row index of item to select after rebuilding editor list: row = Any # Should the selected item be edited after rebuilding the editor list: edit = Bool(False) # The adapter from trait values to editor values: adapter = Instance(TabularAdapter) # The table model associated with the editor: model = Instance(TabularModel) # Dictionary mapping image names to QIcons images = Any({}) # Dictionary mapping ImageResource objects to QIcons image_resources = Any({}) # An image being converted: image = Image header_event_filter = Any() widget_factory = Callable(lambda *args, **kwds: _TableView(*args, **kwds)) #--------------------------------------------------------------------------- # Editor interface: #--------------------------------------------------------------------------- def init(self, parent): """ Finishes initializing the editor by creating the underlying toolkit widget. """ factory = self.factory adapter = self.adapter = factory.adapter self.model = TabularModel(editor=self) # Create the control control = self.control = self.widget_factory(self) # Set up the selection listener if factory.multi_select: self.sync_value(factory.selected, 'multi_selected', 'both', is_list=True) self.sync_value(factory.selected_row, 'multi_selected_rows', 'both', is_list=True) else: self.sync_value(factory.selected, 'selected', 'both') self.sync_value(factory.selected_row, 'selected_row', 'both') # Connect to the mode specific selection handler if factory.multi_select: slot = self._on_rows_selection else: slot = self._on_row_selection signal = 'selectionChanged(QItemSelection,QItemSelection)' QtCore.QObject.connect(self.control.selectionModel(), QtCore.SIGNAL(signal), slot) # Synchronize other interesting traits as necessary: self.sync_value(factory.update, 'update', 'from') self.sync_value(factory.refresh, 'refresh', 'from') self.sync_value(factory.activated, 'activated', 'to') self.sync_value(factory.activated_row, 'activated_row', 'to') self.sync_value(factory.clicked, 'clicked', 'to') self.sync_value(factory.dclicked, 'dclicked', 'to') self.sync_value(factory.right_clicked, 'right_clicked', 'to') self.sync_value(factory.right_dclicked, 'right_dclicked', 'to') self.sync_value(factory.column_clicked, 'column_clicked', 'to') self.sync_value(factory.column_right_clicked, 'column_right_clicked', 'to') self.sync_value(factory.scroll_to_row, 'scroll_to_row', 'from') # Connect other signals as necessary signal = QtCore.SIGNAL('activated(QModelIndex)') QtCore.QObject.connect(control, signal, self._on_activate) signal = QtCore.SIGNAL('clicked(QModelIndex)') QtCore.QObject.connect(control, signal, self._on_click) signal = QtCore.SIGNAL('clicked(QModelIndex)') QtCore.QObject.connect(control, signal, self._on_right_click) signal = QtCore.SIGNAL('doubleClicked(QModelIndex)') QtCore.QObject.connect(control, signal, self._on_dclick) signal = QtCore.SIGNAL('sectionClicked(int)') QtCore.QObject.connect(control.horizontalHeader(), signal, self._on_column_click) control.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) signal = QtCore.SIGNAL('customContextMenuRequested(QPoint)') QtCore.QObject.connect(control, signal, self._on_context_menu) self.header_event_filter = HeaderEventFilter(self) control.horizontalHeader().installEventFilter(self.header_event_filter) # Make sure we listen for 'items' changes as well as complete list # replacements: try: self.context_object.on_trait_change(self.update_editor, self.extended_name + '_items', dispatch='ui') except: pass # If the user has requested automatic update, attempt to set up the # appropriate listeners: if factory.auto_update: self.context_object.on_trait_change(self.refresh_editor, self.extended_name + '.-', dispatch='ui') # Create the mapping from user supplied images to QImages: for image_resource in factory.images: self._add_image(image_resource) # Refresh the editor whenever the adapter changes: self.on_trait_change(self.refresh_editor, 'adapter.+update', dispatch='ui') # Rebuild the editor columns and headers whenever the adapter's # 'columns' changes: self.on_trait_change(self.update_editor, 'adapter.columns', dispatch='ui') def dispose(self): """ Disposes of the contents of an editor. """ self.context_object.on_trait_change(self.update_editor, self.extended_name + '_items', remove=True) if self.factory.auto_update: self.context_object.on_trait_change(self.refresh_editor, self.extended_name + '.-', remove=True) self.on_trait_change(self.refresh_editor, 'adapter.+update', remove=True) self.on_trait_change(self.update_editor, 'adapter.columns', remove=True) self.adapter.cleanup() super(TabularEditor, self).dispose() def update_editor(self): """ Updates the editor when the object trait changes externally to the editor. """ if not self._no_update: self.model.reset() if self.factory.multi_select: self._multi_selected_changed(self.multi_selected) else: self._selected_changed(self.selected) #--------------------------------------------------------------------------- # TabularEditor interface: #--------------------------------------------------------------------------- def refresh_editor(self): """ Requests the table view to redraw itself. """ self.control.viewport().update() def callx(self, func, *args, **kw): """ Call a function without allowing the editor to update. """ old = self._no_update self._no_update = True try: func(*args, **kw) finally: self._no_update = old def setx(self, **keywords): """ Set one or more attributes without allowing the editor to update. """ old = self._no_notify self._no_notify = True try: for name, value in keywords.items(): setattr(self, name, value) finally: self._no_notify = old #--------------------------------------------------------------------------- # UI preference save/restore interface: #--------------------------------------------------------------------------- def restore_prefs(self, prefs): """ Restores any saved user preference information associated with the editor. """ cws = prefs.get('cached_widths') num_columns = len(self.adapter.columns) if cws is not None and num_columns == len(cws): for column in xrange(num_columns): self.control.setColumnWidth(column, cws[column]) def save_prefs(self): """ Returns any user preference information associated with the editor. """ widths = [ self.control.columnWidth(column) for column in xrange(len(self.adapter.columns)) ] return {'cached_widths': widths} #--------------------------------------------------------------------------- # Private methods: #--------------------------------------------------------------------------- def _add_image(self, image_resource): """ Adds a new image to the image map. """ image = image_resource.create_icon() self.image_resources[image_resource] = image self.images[image_resource.name] = image return image def _get_image(self, image): """ Converts a user specified image to a QIcon. """ if isinstance(image, basestring): self.image = image image = self.image if isinstance(image, ImageResource): result = self.image_resources.get(image) if result is not None: return result return self._add_image(image) return self.images.get(image) def _mouse_click(self, index, trait): """ Generate a TabularEditorEvent event for a specified model index and editor trait name. """ event = TabularEditorEvent(editor=self, row=index.row(), column=index.column()) setattr(self, trait, event) #-- Trait Event Handlers --------------------------------------------------- def _update_changed(self): self.update_editor() def _refresh_changed(self): self.refresh_editor() def _selected_changed(self, new): if not self._no_update: try: selected_row = self.value.index(new) except: pass else: self._selected_row_changed(selected_row) def _selected_row_changed(self, selected_row): if not self._no_update: smodel = self.control.selectionModel() if selected_row == -1: smodel.clearSelection() else: smodel.select( self.model.index(selected_row, 0), QtGui.QItemSelectionModel.ClearAndSelect | QtGui.QItemSelectionModel.Rows) def _multi_selected_changed(self, new): if not self._no_update: values = self.value try: rows = [values.index(i) for i in new] except: pass else: self._multi_selected_rows_changed(rows) def _multi_selected_items_changed(self, event): values = self.value try: added = [values.index(item) for item in event.added] removed = [values.index(item) for item in event.removed] except: pass else: list_event = TraitListEvent(0, added, removed) self._multi_selected_rows_items_changed(list_event) def _multi_selected_rows_changed(self, selected_rows): if not self._no_update: smodel = self.control.selectionModel() selection = QtGui.QItemSelection() for row in selected_rows: selection.select(self.model.index(row, 0), self.model.index(row, 0)) smodel.clearSelection() smodel.select( selection, QtGui.QItemSelectionModel.Select | QtGui.QItemSelectionModel.Rows) def _multi_selected_rows_items_changed(self, event): smodel = self.control.selectionModel() for row in event.removed: smodel.select( self.model.index(row, 0), QtGui.QItemSelectionModel.Deselect | QtGui.QItemSelectionModel.Rows) for row in event.added: smodel.select( self.model.index(row, 0), QtGui.QItemSelectionModel.Select | QtGui.QItemSelectionModel.Rows) scroll_to_row_hint_map = { 'center': QtGui.QTableView.PositionAtCenter, 'top': QtGui.QTableView.PositionAtTop, 'bottom': QtGui.QTableView.PositionAtBottom, 'visible': QtGui.QTableView.EnsureVisible, } def _scroll_to_row_changed(self, row): """ Scroll to the given row. """ scroll_hint = self.scroll_to_row_hint_map.get( self.factory.scroll_to_row_hint, self.control.PositionAtCenter) self.control.scrollTo(self.model.index(row, 0), scroll_hint) #-- Table Control Event Handlers ------------------------------------------- def _on_activate(self, index): """ Handle a cell being activated. """ self.activated_row = row = index.row() self.activated = self.adapter.get_item(self.object, self.name, row) def _on_click(self, index): """ Handle a cell being clicked. """ self._mouse_click(index, 'clicked') def _on_dclick(self, index): """ Handle a cell being double clicked. """ self._mouse_click(index, 'dclicked') def _on_column_click(self, column): event = TabularEditorEvent(editor=self, row=0, column=column) setattr(self, 'column_clicked', event) def _on_right_click(self, column): event = TabularEditorEvent(editor=self, row=0, column=column) setattr(self, 'right_clicked', event) def _on_column_right_click(self, column): event = TabularEditorEvent(editor=self, row=0, column=column) setattr(self, 'column_right_clicked', event) def _on_row_selection(self, added, removed): """ Handle the row selection being changed. """ self._no_update = True try: indexes = self.control.selectionModel().selectedRows() if len(indexes): self.selected_row = indexes[0].row() self.selected = self.adapter.get_item(self.object, self.name, self.selected_row) else: self.selected_row = -1 self.selected = None finally: self._no_update = False def _on_rows_selection(self, added, removed): """ Handle the rows selection being changed. """ self._no_update = True try: indexes = self.control.selectionModel().selectedRows() selected_rows = [] selected = [] for index in indexes: row = index.row() selected_rows.append(row) selected.append( self.adapter.get_item(self.object, self.name, row)) self.multi_selected_rows = selected_rows self.multi_selected = selected finally: self._no_update = False def _on_context_menu(self, pos): column, row = self.control.columnAt(pos.x()), self.control.rowAt( pos.y()) menu = self.adapter.get_menu(self.object, self.name, row, column) if menu: self._menu_context = { 'selection': self.object, 'object': self.object, 'editor': self, 'column': column, 'row': row, 'item': self.adapter.get_item(self.object, self.name, row), 'info': self.ui.info, 'handler': self.ui.handler } qmenu = menu.create_menu(self.control, self) qmenu.exec_(self.control.mapToGlobal(pos)) self._menu_context = None def _on_column_context_menu(self, pos): column = self.control.columnAt(pos.x()) menu = self.adapter.get_column_menu(self.object, self.name, -1, column) if menu: self._menu_context = { 'selection': self.object, 'object': self.object, 'editor': self, 'column': column, 'info': self.ui.info, 'handler': self.ui.handler } qmenu = menu.create_menu(self.control, self) qmenu.exec_(self.control.mapToGlobal(pos)) self._menu_context = None else: #If no menu is defined on the adapter, just trigger a click event. self._on_column_right_click(column)
def init(self, parent): """ Finishes initializing the editor by creating the underlying toolkit widget. """ factory = self.factory adapter = self.adapter = factory.adapter self.model = TabularModel(editor=self) # Create the control control = self.control = self.widget_factory(self) # Set up the selection listener if factory.multi_select: self.sync_value(factory.selected, 'multi_selected', 'both', is_list=True) self.sync_value(factory.selected_row, 'multi_selected_rows', 'both', is_list=True) else: self.sync_value(factory.selected, 'selected', 'both') self.sync_value(factory.selected_row, 'selected_row', 'both') # Connect to the mode specific selection handler if factory.multi_select: slot = self._on_rows_selection else: slot = self._on_row_selection signal = 'selectionChanged(QItemSelection,QItemSelection)' QtCore.QObject.connect(self.control.selectionModel(), QtCore.SIGNAL(signal), slot) # Synchronize other interesting traits as necessary: self.sync_value(factory.update, 'update', 'from') self.sync_value(factory.refresh, 'refresh', 'from') self.sync_value(factory.activated, 'activated', 'to') self.sync_value(factory.activated_row, 'activated_row', 'to') self.sync_value(factory.clicked, 'clicked', 'to') self.sync_value(factory.dclicked, 'dclicked', 'to') self.sync_value(factory.right_clicked, 'right_clicked', 'to') self.sync_value(factory.right_dclicked, 'right_dclicked', 'to') self.sync_value(factory.column_clicked, 'column_clicked', 'to') self.sync_value(factory.column_right_clicked, 'column_right_clicked', 'to') self.sync_value(factory.scroll_to_row, 'scroll_to_row', 'from') # Connect other signals as necessary signal = QtCore.SIGNAL('activated(QModelIndex)') QtCore.QObject.connect(control, signal, self._on_activate) signal = QtCore.SIGNAL('clicked(QModelIndex)') QtCore.QObject.connect(control, signal, self._on_click) signal = QtCore.SIGNAL('clicked(QModelIndex)') QtCore.QObject.connect(control, signal, self._on_right_click) signal = QtCore.SIGNAL('doubleClicked(QModelIndex)') QtCore.QObject.connect(control, signal, self._on_dclick) signal = QtCore.SIGNAL('sectionClicked(int)') QtCore.QObject.connect(control.horizontalHeader(), signal, self._on_column_click) control.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) signal = QtCore.SIGNAL('customContextMenuRequested(QPoint)') QtCore.QObject.connect(control, signal, self._on_context_menu) self.header_event_filter = HeaderEventFilter(self) control.horizontalHeader().installEventFilter(self.header_event_filter) # Make sure we listen for 'items' changes as well as complete list # replacements: try: self.context_object.on_trait_change(self.update_editor, self.extended_name + '_items', dispatch='ui') except: pass # If the user has requested automatic update, attempt to set up the # appropriate listeners: if factory.auto_update: self.context_object.on_trait_change(self.refresh_editor, self.extended_name + '.-', dispatch='ui') # Create the mapping from user supplied images to QImages: for image_resource in factory.images: self._add_image(image_resource) # Refresh the editor whenever the adapter changes: self.on_trait_change(self.refresh_editor, 'adapter.+update', dispatch='ui') # Rebuild the editor columns and headers whenever the adapter's # 'columns' changes: self.on_trait_change(self.update_editor, 'adapter.columns', dispatch='ui')
def init (self, parent): """ Finishes initializing the editor by creating the underlying toolkit widget. """ factory = self.factory adapter = self.adapter = factory.adapter self.model = TabularModel(editor=self) # Create the control control = self.control = self.widget_factory(self) # Set up the selection listener if factory.multi_select: self.sync_value(factory.selected, 'multi_selected', 'both', is_list=True) self.sync_value(factory.selected_row, 'multi_selected_rows','both', is_list=True) else: self.sync_value(factory.selected, 'selected', 'both') self.sync_value(factory.selected_row, 'selected_row', 'both') # Connect to the mode specific selection handler if factory.multi_select: slot = self._on_rows_selection else: slot = self._on_row_selection signal = 'selectionChanged(QItemSelection,QItemSelection)' QtCore.QObject.connect(self.control.selectionModel(), QtCore.SIGNAL(signal), slot) # Synchronize other interesting traits as necessary: self.sync_value(factory.update, 'update', 'from') self.sync_value(factory.refresh, 'refresh', 'from') self.sync_value(factory.activated, 'activated', 'to') self.sync_value(factory.activated_row, 'activated_row', 'to') self.sync_value(factory.clicked, 'clicked', 'to') self.sync_value(factory.dclicked, 'dclicked', 'to') self.sync_value(factory.right_clicked, 'right_clicked', 'to') self.sync_value(factory.right_dclicked, 'right_dclicked', 'to') self.sync_value(factory.column_clicked, 'column_clicked', 'to') self.sync_value(factory.column_right_clicked, 'column_right_clicked', 'to') self.sync_value(factory.scroll_to_row, 'scroll_to_row', 'from') # Connect other signals as necessary signal = QtCore.SIGNAL('activated(QModelIndex)') QtCore.QObject.connect(control, signal, self._on_activate) signal = QtCore.SIGNAL('clicked(QModelIndex)') QtCore.QObject.connect(control, signal, self._on_click) signal = QtCore.SIGNAL('clicked(QModelIndex)') QtCore.QObject.connect(control, signal, self._on_right_click) signal = QtCore.SIGNAL('doubleClicked(QModelIndex)') QtCore.QObject.connect(control, signal, self._on_dclick) signal = QtCore.SIGNAL('sectionClicked(int)') QtCore.QObject.connect(control.horizontalHeader(), signal, self._on_column_click) control.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) signal = QtCore.SIGNAL('customContextMenuRequested(QPoint)') QtCore.QObject.connect(control, signal, self._on_context_menu) self.header_event_filter = HeaderEventFilter(self) control.horizontalHeader().installEventFilter(self.header_event_filter) # Make sure we listen for 'items' changes as well as complete list # replacements: try: self.context_object.on_trait_change( self.update_editor, self.extended_name+'_items', dispatch='ui') except: pass # If the user has requested automatic update, attempt to set up the # appropriate listeners: if factory.auto_update: self.context_object.on_trait_change( self.refresh_editor, self.extended_name + '.-', dispatch='ui') # Create the mapping from user supplied images to QImages: for image_resource in factory.images: self._add_image(image_resource) # Refresh the editor whenever the adapter changes: self.on_trait_change(self.refresh_editor, 'adapter.+update', dispatch='ui') # Rebuild the editor columns and headers whenever the adapter's # 'columns' changes: self.on_trait_change(self.update_editor, 'adapter.columns', dispatch='ui')
class TabularEditor(Editor): """ A traits UI editor for editing tabular data (arrays, list of tuples, lists of objects, etc). """ #-- Trait Definitions ------------------------------------------------------ # The event fired when a table update is needed: update = Event # The event fired when a simple repaint is needed: refresh = Event # The current set of selected items (which one is used depends upon the # initial state of the editor factory 'multi_select' trait): selected = Any multi_selected = List # The current set of selected item indices (which one is used depends upon # the initial state of the editor factory 'multi_select' trait): selected_row = Int(-1) multi_selected_rows = List(Int) # The most recently actived item and its index: activated = Any(comparison_mode=NO_COMPARE) activated_row = Int(comparison_mode=NO_COMPARE) # The most recent left click data: clicked = Instance('TabularEditorEvent') # The most recent left double click data: dclicked = Instance('TabularEditorEvent') # The most recent right click data: right_clicked = Instance('TabularEditorEvent') # The most recent right double click data: right_dclicked = Instance('TabularEditorEvent') # The most recent column click data: column_clicked = Instance('TabularEditorEvent') # The most recent column click data: column_right_clicked = Instance('TabularEditorEvent') # The event triggering scrolling. scroll_to_row = Event(Int) # Is the tabular editor scrollable? This value overrides the default. scrollable = True # Row index of item to select after rebuilding editor list: row = Any # Should the selected item be edited after rebuilding the editor list: edit = Bool(False) # The adapter from trait values to editor values: adapter = Instance(TabularAdapter) # The table model associated with the editor: model = Instance(TabularModel) # Dictionary mapping image names to QIcons images = Any({}) # Dictionary mapping ImageResource objects to QIcons image_resources = Any({}) # An image being converted: image = Image header_event_filter = Any() widget_factory = Callable(lambda *args, **kwds: _TableView(*args, **kwds)) #--------------------------------------------------------------------------- # Editor interface: #--------------------------------------------------------------------------- def init (self, parent): """ Finishes initializing the editor by creating the underlying toolkit widget. """ factory = self.factory adapter = self.adapter = factory.adapter self.model = TabularModel(editor=self) # Create the control control = self.control = self.widget_factory(self) # Set up the selection listener if factory.multi_select: self.sync_value(factory.selected, 'multi_selected', 'both', is_list=True) self.sync_value(factory.selected_row, 'multi_selected_rows','both', is_list=True) else: self.sync_value(factory.selected, 'selected', 'both') self.sync_value(factory.selected_row, 'selected_row', 'both') # Connect to the mode specific selection handler if factory.multi_select: slot = self._on_rows_selection else: slot = self._on_row_selection signal = 'selectionChanged(QItemSelection,QItemSelection)' QtCore.QObject.connect(self.control.selectionModel(), QtCore.SIGNAL(signal), slot) # Synchronize other interesting traits as necessary: self.sync_value(factory.update, 'update', 'from') self.sync_value(factory.refresh, 'refresh', 'from') self.sync_value(factory.activated, 'activated', 'to') self.sync_value(factory.activated_row, 'activated_row', 'to') self.sync_value(factory.clicked, 'clicked', 'to') self.sync_value(factory.dclicked, 'dclicked', 'to') self.sync_value(factory.right_clicked, 'right_clicked', 'to') self.sync_value(factory.right_dclicked, 'right_dclicked', 'to') self.sync_value(factory.column_clicked, 'column_clicked', 'to') self.sync_value(factory.column_right_clicked, 'column_right_clicked', 'to') self.sync_value(factory.scroll_to_row, 'scroll_to_row', 'from') # Connect other signals as necessary signal = QtCore.SIGNAL('activated(QModelIndex)') QtCore.QObject.connect(control, signal, self._on_activate) signal = QtCore.SIGNAL('clicked(QModelIndex)') QtCore.QObject.connect(control, signal, self._on_click) signal = QtCore.SIGNAL('clicked(QModelIndex)') QtCore.QObject.connect(control, signal, self._on_right_click) signal = QtCore.SIGNAL('doubleClicked(QModelIndex)') QtCore.QObject.connect(control, signal, self._on_dclick) signal = QtCore.SIGNAL('sectionClicked(int)') QtCore.QObject.connect(control.horizontalHeader(), signal, self._on_column_click) control.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) signal = QtCore.SIGNAL('customContextMenuRequested(QPoint)') QtCore.QObject.connect(control, signal, self._on_context_menu) self.header_event_filter = HeaderEventFilter(self) control.horizontalHeader().installEventFilter(self.header_event_filter) # Make sure we listen for 'items' changes as well as complete list # replacements: try: self.context_object.on_trait_change( self.update_editor, self.extended_name+'_items', dispatch='ui') except: pass # If the user has requested automatic update, attempt to set up the # appropriate listeners: if factory.auto_update: self.context_object.on_trait_change( self.refresh_editor, self.extended_name + '.-', dispatch='ui') # Create the mapping from user supplied images to QImages: for image_resource in factory.images: self._add_image(image_resource) # Refresh the editor whenever the adapter changes: self.on_trait_change(self.refresh_editor, 'adapter.+update', dispatch='ui') # Rebuild the editor columns and headers whenever the adapter's # 'columns' changes: self.on_trait_change(self.update_editor, 'adapter.columns', dispatch='ui') def dispose (self): """ Disposes of the contents of an editor. """ self.context_object.on_trait_change( self.update_editor, self.extended_name + '_items', remove=True) if self.factory.auto_update: self.context_object.on_trait_change( self.refresh_editor, self.extended_name + '.-', remove=True) self.on_trait_change(self.refresh_editor, 'adapter.+update', remove=True) self.on_trait_change(self.update_editor, 'adapter.columns', remove=True) self.adapter.cleanup() super(TabularEditor, self).dispose() def update_editor(self): """ Updates the editor when the object trait changes externally to the editor. """ if not self._no_update: self.model.reset() if self.factory.multi_select: self._multi_selected_changed(self.multi_selected) else : self._selected_changed(self.selected) #--------------------------------------------------------------------------- # TabularEditor interface: #--------------------------------------------------------------------------- def refresh_editor(self): """ Requests the table view to redraw itself. """ self.control.viewport().update() def callx(self, func, *args, **kw): """ Call a function without allowing the editor to update. """ old = self._no_update self._no_update = True try: func(*args, **kw) finally: self._no_update = old def setx(self, **keywords): """ Set one or more attributes without allowing the editor to update. """ old = self._no_notify self._no_notify = True try: for name, value in keywords.items(): setattr(self, name, value) finally: self._no_notify = old #--------------------------------------------------------------------------- # UI preference save/restore interface: #--------------------------------------------------------------------------- def restore_prefs(self, prefs): """ Restores any saved user preference information associated with the editor. """ cws = prefs.get('cached_widths') num_columns = len(self.adapter.columns) if cws is not None and num_columns == len(cws): for column in xrange(num_columns): self.control.setColumnWidth(column, cws[column]) def save_prefs(self): """ Returns any user preference information associated with the editor. """ widths = [ self.control.columnWidth(column) for column in xrange(len(self.adapter.columns)) ] return { 'cached_widths': widths } #--------------------------------------------------------------------------- # Private methods: #--------------------------------------------------------------------------- def _add_image(self, image_resource): """ Adds a new image to the image map. """ image = image_resource.create_icon() self.image_resources[image_resource] = image self.images[image_resource.name] = image return image def _get_image(self, image): """ Converts a user specified image to a QIcon. """ if isinstance(image, basestring): self.image = image image = self.image if isinstance(image, ImageResource): result = self.image_resources.get(image) if result is not None: return result return self._add_image(image) return self.images.get(image) def _mouse_click(self, index, trait): """ Generate a TabularEditorEvent event for a specified model index and editor trait name. """ event = TabularEditorEvent(editor=self, row=index.row(), column=index.column()) setattr(self, trait, event) #-- Trait Event Handlers --------------------------------------------------- def _update_changed(self): self.update_editor() def _refresh_changed(self): self.refresh_editor() def _selected_changed(self, new): if not self._no_update: try: selected_row = self.value.index(new) except: pass else: self._selected_row_changed(selected_row) def _selected_row_changed(self, selected_row): if not self._no_update: smodel = self.control.selectionModel() if selected_row == -1: smodel.clearSelection() else: smodel.select(self.model.index(selected_row, 0), QtGui.QItemSelectionModel.ClearAndSelect | QtGui.QItemSelectionModel.Rows) def _multi_selected_changed(self, new): if not self._no_update: values = self.value try: rows = [ values.index(i) for i in new] except: pass else: self._multi_selected_rows_changed(rows) def _multi_selected_items_changed(self, event): values = self.value try: added = [ values.index(item) for item in event.added ] removed = [ values.index(item) for item in event.removed ] except: pass else: list_event = TraitListEvent(0, added, removed) self._multi_selected_rows_items_changed(list_event) def _multi_selected_rows_changed(self, selected_rows): if not self._no_update: smodel = self.control.selectionModel() selection = QtGui.QItemSelection() for row in selected_rows: selection.select(self.model.index(row, 0), self.model.index(row, 0)) smodel.clearSelection() smodel.select(selection, QtGui.QItemSelectionModel.Select | QtGui.QItemSelectionModel.Rows) def _multi_selected_rows_items_changed(self, event): smodel = self.control.selectionModel() for row in event.removed: smodel.select(self.model.index(row, 0), QtGui.QItemSelectionModel.Deselect | QtGui.QItemSelectionModel.Rows) for row in event.added: smodel.select(self.model.index(row, 0), QtGui.QItemSelectionModel.Select | QtGui.QItemSelectionModel.Rows) scroll_to_row_hint_map = { 'center' : QtGui.QTableView.PositionAtCenter, 'top' : QtGui.QTableView.PositionAtTop, 'bottom' : QtGui.QTableView.PositionAtBottom, 'visible' : QtGui.QTableView.EnsureVisible, } def _scroll_to_row_changed(self, row): """ Scroll to the given row. """ scroll_hint = self.scroll_to_row_hint_map.get(self.factory.scroll_to_row_hint, self.control.PositionAtCenter) self.control.scrollTo(self.model.index(row, 0), scroll_hint) #-- Table Control Event Handlers ------------------------------------------- def _on_activate(self, index): """ Handle a cell being activated. """ self.activated_row = row = index.row() self.activated = self.adapter.get_item(self.object, self.name, row) def _on_click(self, index): """ Handle a cell being clicked. """ self._mouse_click(index, 'clicked') def _on_dclick(self, index): """ Handle a cell being double clicked. """ self._mouse_click(index, 'dclicked') def _on_column_click(self, column): event = TabularEditorEvent(editor=self, row=0, column=column) setattr(self, 'column_clicked', event) def _on_right_click(self, column): event = TabularEditorEvent(editor=self, row=0, column=column) setattr(self, 'right_clicked', event) def _on_column_right_click(self, column): event = TabularEditorEvent(editor=self, row=0, column=column) setattr(self, 'column_right_clicked', event) def _on_row_selection(self, added, removed): """ Handle the row selection being changed. """ self._no_update = True try: indexes = self.control.selectionModel().selectedRows() if len(indexes): self.selected_row = indexes[0].row() self.selected = self.adapter.get_item(self.object, self.name, self.selected_row) else: self.selected_row = -1 self.selected = None finally: self._no_update = False def _on_rows_selection(self, added, removed): """ Handle the rows selection being changed. """ self._no_update = True try: indexes = self.control.selectionModel().selectedRows() selected_rows = [] selected = [] for index in indexes: row = index.row() selected_rows.append(row) selected.append(self.adapter.get_item(self.object, self.name, row)) self.multi_selected_rows = selected_rows self.multi_selected = selected finally: self._no_update = False def _on_context_menu(self, pos) : column, row = self.control.columnAt(pos.x()), self.control.rowAt(pos.y()) menu = self.adapter.get_menu(self.object, self.name, row, column) if menu : self._menu_context = {'selection' : self.object, 'object': self.object, 'editor': self, 'column': column, 'row': row, 'item': self.adapter.get_item(self.object, self.name, row), 'info': self.ui.info, 'handler': self.ui.handler } qmenu = menu.create_menu( self.control, self ) qmenu.exec_(self.control.mapToGlobal(pos)) self._menu_context = None def _on_column_context_menu(self, pos) : column = self.control.columnAt(pos.x()) menu = self.adapter.get_column_menu(self.object, self.name, -1, column) if menu : self._menu_context = {'selection' : self.object, 'object': self.object, 'editor': self, 'column': column, 'info': self.ui.info, 'handler': self.ui.handler } qmenu = menu.create_menu( self.control, self ) qmenu.exec_(self.control.mapToGlobal(pos)) self._menu_context = None else: #If no menu is defined on the adapter, just trigger a click event. self._on_column_right_click(column)
# separate data into training and test data batch_size = 60000 test_size = int(batch_size * 0.2) cat_train = cats[:batch_size - test_size] cat_test = cats[batch_size - test_size:batch_size] con_train = conts[:batch_size - test_size] con_test = conts[batch_size - test_size:batch_size] y_train = y[:batch_size - test_size] y_test = y[batch_size - test_size:batch_size] # Neural Networky stuff selfembeds = nn.ModuleList([nn.Embedding(ni, nf) for ni, nf in emb_szs]) torch.manual_seed(33) model = TabularModel(emb_szs, conts.shape[1], 1, [200, 100], p=0.4) criterion = nn.MSELoss() # we'll convert this to RMSE later optimizer = torch.optim.Adam(model.parameters(), lr=0.001) start_time = time.time() epochs = 300 losses = [] for i in range(epochs): i += 1 y_pred = model(cat_train, con_train) loss = torch.sqrt(criterion(y_pred, y_train)) # RMSE losses.append(loss)