mirror of
https://github.com/arsenetar/dupeguru.git
synced 2025-03-10 05:34:36 +00:00
Improved hscommon doc
* Completed hscommon.gui.table's doc * Use sphinx.ext.autosummary. * Moved attribute docstrings directly into properties.
This commit is contained in:
parent
31395d8794
commit
5a275db67d
@ -31,6 +31,8 @@ def fix_nulljob_in_sig(app, what, name, obj, options, signature, return_annotati
|
|||||||
def setup(app):
|
def setup(app):
|
||||||
app.connect('autodoc-process-signature', fix_nulljob_in_sig)
|
app.connect('autodoc-process-signature', fix_nulljob_in_sig)
|
||||||
|
|
||||||
|
autodoc_member_order = 'groupwise'
|
||||||
|
|
||||||
# -- General configuration -----------------------------------------------------
|
# -- General configuration -----------------------------------------------------
|
||||||
|
|
||||||
# If your documentation needs a minimal Sphinx version, state it here.
|
# If your documentation needs a minimal Sphinx version, state it here.
|
||||||
@ -38,7 +40,7 @@ def setup(app):
|
|||||||
|
|
||||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||||
extensions = ['sphinx.ext.todo', 'sphinx.ext.autodoc']
|
extensions = ['sphinx.ext.todo', 'sphinx.ext.autodoc', 'sphinx.ext.autosummary']
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
templates_path = ['_templates']
|
templates_path = ['_templates']
|
||||||
|
@ -3,6 +3,10 @@ hscommon.gui.base
|
|||||||
|
|
||||||
.. automodule:: hscommon.gui.base
|
.. automodule:: hscommon.gui.base
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
|
||||||
|
GUIObject
|
||||||
|
|
||||||
.. autoclass:: GUIObject
|
.. autoclass:: GUIObject
|
||||||
:members:
|
:members:
|
||||||
:private-members:
|
:private-members:
|
||||||
|
@ -3,6 +3,13 @@ hscommon.gui.selectable_list
|
|||||||
|
|
||||||
.. automodule:: hscommon.gui.selectable_list
|
.. automodule:: hscommon.gui.selectable_list
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
|
||||||
|
Selectable
|
||||||
|
SelectableList
|
||||||
|
GUISelectableList
|
||||||
|
GUISelectableListView
|
||||||
|
|
||||||
.. autoclass:: Selectable
|
.. autoclass:: Selectable
|
||||||
:members:
|
:members:
|
||||||
:private-members:
|
:private-members:
|
||||||
|
@ -3,6 +3,13 @@ hscommon.gui.table
|
|||||||
|
|
||||||
.. automodule:: hscommon.gui.table
|
.. automodule:: hscommon.gui.table
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
|
||||||
|
Table
|
||||||
|
Row
|
||||||
|
GUITable
|
||||||
|
GUITableView
|
||||||
|
|
||||||
.. autoclass:: Table
|
.. autoclass:: Table
|
||||||
:members:
|
:members:
|
||||||
:private-members:
|
:private-members:
|
||||||
@ -11,3 +18,9 @@ hscommon.gui.table
|
|||||||
:members:
|
:members:
|
||||||
:private-members:
|
:private-members:
|
||||||
|
|
||||||
|
.. autoclass:: GUITable
|
||||||
|
:members:
|
||||||
|
:private-members:
|
||||||
|
|
||||||
|
.. autoclass:: GUITableView
|
||||||
|
:members:
|
||||||
|
@ -3,6 +3,11 @@ hscommon.gui.text_field
|
|||||||
|
|
||||||
.. automodule:: hscommon.gui.text_field
|
.. automodule:: hscommon.gui.text_field
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
|
||||||
|
TextField
|
||||||
|
TextFieldView
|
||||||
|
|
||||||
.. autoclass:: TextField
|
.. autoclass:: TextField
|
||||||
:members:
|
:members:
|
||||||
:private-members:
|
:private-members:
|
||||||
|
@ -28,16 +28,6 @@ class GUIObject:
|
|||||||
When you subclass ``GUIObject``, you will likely want to update its view on instantiation. That
|
When you subclass ``GUIObject``, you will likely want to update its view on instantiation. That
|
||||||
is why we call ``self.view.refresh()`` in :meth:`_view_updated`. If you need another type of
|
is why we call ``self.view.refresh()`` in :meth:`_view_updated`. If you need another type of
|
||||||
action on view instantiation, just override the method.
|
action on view instantiation, just override the method.
|
||||||
|
|
||||||
.. attribute:: view
|
|
||||||
|
|
||||||
A reference to our toolkit-specific view controller. This view starts as ``None`` and has to
|
|
||||||
be set "manually". There's two times at which we set the view property: On initialization,
|
|
||||||
where we set the view that we'll use for our lifetime, and just before the view is
|
|
||||||
deallocated. We need to unset our view at that time to avoid calls to a deallocated instance
|
|
||||||
(which means a crash).
|
|
||||||
|
|
||||||
To unset our view, we simple assign it to ``None``.
|
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._view = None
|
self._view = None
|
||||||
@ -55,6 +45,17 @@ class GUIObject:
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def view(self):
|
def view(self):
|
||||||
|
"""A reference to our toolkit-specific view controller.
|
||||||
|
|
||||||
|
*view answering to GUIObject sublass's view protocol*. *get/set*
|
||||||
|
|
||||||
|
This view starts as ``None`` and has to be set "manually". There's two times at which we set
|
||||||
|
the view property: On initialization, where we set the view that we'll use for our lifetime,
|
||||||
|
and just before the view is deallocated. We need to unset our view at that time to avoid
|
||||||
|
calls to a deallocated instance (which means a crash).
|
||||||
|
|
||||||
|
To unset our view, we simple assign it to ``None``.
|
||||||
|
"""
|
||||||
return self._view
|
return self._view
|
||||||
|
|
||||||
@view.setter
|
@view.setter
|
||||||
|
@ -15,17 +15,6 @@ class Selectable(Sequence):
|
|||||||
|
|
||||||
When mixed in with a ``Sequence``, we enable it to manage its selection status. The selection
|
When mixed in with a ``Sequence``, we enable it to manage its selection status. The selection
|
||||||
is held as a list of ``int`` indexes. Multiple selection is supported.
|
is held as a list of ``int`` indexes. Multiple selection is supported.
|
||||||
|
|
||||||
.. attribute:: selected_index
|
|
||||||
|
|
||||||
*int*. *get/set*. Thin wrapper around :attr:`selected_indexes`. Points to the first selected
|
|
||||||
index or ``None`` if it's empty. Using this property only makes sense if your selectable
|
|
||||||
sequence supports single selection only.
|
|
||||||
|
|
||||||
.. attribute:: selected_indexes
|
|
||||||
|
|
||||||
*list*. *get/set*. List of selected indexes. When setting the value, automatically removes
|
|
||||||
out-of-bounds indexes. The list is kept sorted.
|
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._selected_indexes = []
|
self._selected_indexes = []
|
||||||
@ -74,6 +63,13 @@ class Selectable(Sequence):
|
|||||||
#--- Properties
|
#--- Properties
|
||||||
@property
|
@property
|
||||||
def selected_index(self):
|
def selected_index(self):
|
||||||
|
"""Points to the first selected index.
|
||||||
|
|
||||||
|
*int*. *get/set*.
|
||||||
|
|
||||||
|
Thin wrapper around :attr:`selected_indexes`. ``None`` if selection is empty. Using this
|
||||||
|
property only makes sense if your selectable sequence supports single selection only.
|
||||||
|
"""
|
||||||
return self._selected_indexes[0] if self._selected_indexes else None
|
return self._selected_indexes[0] if self._selected_indexes else None
|
||||||
|
|
||||||
@selected_index.setter
|
@selected_index.setter
|
||||||
@ -82,6 +78,13 @@ class Selectable(Sequence):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def selected_indexes(self):
|
def selected_indexes(self):
|
||||||
|
"""List of selected indexes.
|
||||||
|
|
||||||
|
*list of int*. *get/set*.
|
||||||
|
|
||||||
|
When setting the value, automatically removes out-of-bounds indexes. The list is kept
|
||||||
|
sorted.
|
||||||
|
"""
|
||||||
return self._selected_indexes
|
return self._selected_indexes
|
||||||
|
|
||||||
@selected_indexes.setter
|
@selected_indexes.setter
|
||||||
@ -170,7 +173,7 @@ class GUISelectableListView:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
class GUISelectableList(SelectableList, GUIObject):
|
class GUISelectableList(SelectableList, GUIObject):
|
||||||
"""Cross-toolkit list view.
|
"""Cross-toolkit GUI-enabled list view.
|
||||||
|
|
||||||
Represents a UI element presenting the user with a selectable list of items.
|
Represents a UI element presenting the user with a selectable list of items.
|
||||||
|
|
||||||
|
@ -11,7 +11,6 @@ from collections import MutableSequence, namedtuple
|
|||||||
from .base import GUIObject
|
from .base import GUIObject
|
||||||
from .selectable_list import Selectable
|
from .selectable_list import Selectable
|
||||||
|
|
||||||
|
|
||||||
# We used to directly subclass list, but it caused problems at some point with deepcopy
|
# We used to directly subclass list, but it caused problems at some point with deepcopy
|
||||||
class Table(MutableSequence, Selectable):
|
class Table(MutableSequence, Selectable):
|
||||||
"""Sortable and selectable sequence of :class:`Row`.
|
"""Sortable and selectable sequence of :class:`Row`.
|
||||||
@ -24,43 +23,6 @@ class Table(MutableSequence, Selectable):
|
|||||||
Usually used with :class:`~hscommon.gui.column.Column`.
|
Usually used with :class:`~hscommon.gui.column.Column`.
|
||||||
|
|
||||||
Subclasses :class:`~hscommon.gui.selectable_list.Selectable`.
|
Subclasses :class:`~hscommon.gui.selectable_list.Selectable`.
|
||||||
|
|
||||||
.. attribute:: header
|
|
||||||
.. attribute:: footer
|
|
||||||
|
|
||||||
When set to something else than ``None``, represent rows that will always be kept in first
|
|
||||||
and/or last position, regardless of sorting. ``len()`` and indexing will include them, which
|
|
||||||
means that if there's a header, ``table[0]`` returns it and if there's a footer,
|
|
||||||
``table[-1]`` returns it. To make things short, all list-like functions work with header and
|
|
||||||
footer "on". But things get fuzzy for ``append()`` and ``insert()`` because these will
|
|
||||||
ensure that no "normal" row gets inserted before the header or after the footer.
|
|
||||||
|
|
||||||
Adding and removing footer here and there might seem (and is) hackish, but it's much simpler
|
|
||||||
than the alternative (when, of course, you need such a feature), which is to override magic
|
|
||||||
methods and adjust the results. When we do that, there the slice stuff that we have to
|
|
||||||
implement and it gets quite complex. Moreover, the most frequent operation on a table is
|
|
||||||
``__getitem__``, and making checks to know whether the key is a header or footer at each
|
|
||||||
call would make that operation, which is the most used, slower.
|
|
||||||
|
|
||||||
.. attribute:: row_count
|
|
||||||
|
|
||||||
Number or rows in the table (without counting header and footer).
|
|
||||||
|
|
||||||
.. attribute:: rows
|
|
||||||
|
|
||||||
List of rows in the table, excluding header and footer.
|
|
||||||
|
|
||||||
.. attribute:: selected_row
|
|
||||||
|
|
||||||
:class:`Row`. *get/set*. Selected row, based on
|
|
||||||
:attr:`~hscommon.gui.selectable_list.Selectable.selected_index`. When setting this
|
|
||||||
attribute, we look up the index of the row and set the selected index from there. If the
|
|
||||||
row isn't in the list, selection isn't changed.
|
|
||||||
|
|
||||||
.. attribute:: selected_rows
|
|
||||||
|
|
||||||
List of :class:`Row`. *read-only*. List of selected rows based on
|
|
||||||
:attr:`~hscommon.gui.selectable_list.Selectable.selected_indexes`.
|
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
Selectable.__init__(self)
|
Selectable.__init__(self)
|
||||||
@ -142,6 +104,25 @@ class Table(MutableSequence, Selectable):
|
|||||||
#--- Properties
|
#--- Properties
|
||||||
@property
|
@property
|
||||||
def footer(self):
|
def footer(self):
|
||||||
|
"""If set, a row that always stay at the bottom of the table.
|
||||||
|
|
||||||
|
:class:`Row`. *get/set*.
|
||||||
|
|
||||||
|
When set to something else than ``None``, ``header`` and ``footer`` represent rows that will
|
||||||
|
always be kept in first and/or last position, regardless of sorting. ``len()`` and indexing
|
||||||
|
will include them, which means that if there's a header, ``table[0]`` returns it and if
|
||||||
|
there's a footer, ``table[-1]`` returns it. To make things short, all list-like functions
|
||||||
|
work with header and footer "on". But things get fuzzy for ``append()`` and ``insert()``
|
||||||
|
because these will ensure that no "normal" row gets inserted before the header or after the
|
||||||
|
footer.
|
||||||
|
|
||||||
|
Adding and removing footer here and there might seem (and is) hackish, but it's much simpler
|
||||||
|
than the alternative (when, of course, you need such a feature), which is to override magic
|
||||||
|
methods and adjust the results. When we do that, there the slice stuff that we have to
|
||||||
|
implement and it gets quite complex. Moreover, the most frequent operation on a table is
|
||||||
|
``__getitem__``, and making checks to know whether the key is a header or footer at each
|
||||||
|
call would make that operation, which is the most used, slower.
|
||||||
|
"""
|
||||||
return self._footer
|
return self._footer
|
||||||
|
|
||||||
@footer.setter
|
@footer.setter
|
||||||
@ -154,6 +135,10 @@ class Table(MutableSequence, Selectable):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def header(self):
|
def header(self):
|
||||||
|
"""If set, a row that always stay at the bottom of the table.
|
||||||
|
|
||||||
|
See :attr:`footer` for details.
|
||||||
|
"""
|
||||||
return self._header
|
return self._header
|
||||||
|
|
||||||
@header.setter
|
@header.setter
|
||||||
@ -166,6 +151,10 @@ class Table(MutableSequence, Selectable):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def row_count(self):
|
def row_count(self):
|
||||||
|
"""Number or rows in the table (without counting header and footer).
|
||||||
|
|
||||||
|
*int*. *read-only*.
|
||||||
|
"""
|
||||||
result = len(self)
|
result = len(self)
|
||||||
if self._footer is not None:
|
if self._footer is not None:
|
||||||
result -= 1
|
result -= 1
|
||||||
@ -175,6 +164,10 @@ class Table(MutableSequence, Selectable):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def rows(self):
|
def rows(self):
|
||||||
|
"""List of rows in the table, excluding header and footer.
|
||||||
|
|
||||||
|
List of :class:`Row`. *read-only*.
|
||||||
|
"""
|
||||||
start = None
|
start = None
|
||||||
end = None
|
end = None
|
||||||
if self._footer is not None:
|
if self._footer is not None:
|
||||||
@ -185,6 +178,13 @@ class Table(MutableSequence, Selectable):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def selected_row(self):
|
def selected_row(self):
|
||||||
|
"""Selected row according to :attr:`~hscommon.gui.selectable_list.Selectable.selected_index`.
|
||||||
|
|
||||||
|
:class:`Row`. *get/set*.
|
||||||
|
|
||||||
|
When setting this attribute, we look up the index of the row and set the selected index from
|
||||||
|
there. If the row isn't in the list, selection isn't changed.
|
||||||
|
"""
|
||||||
return self[self.selected_index] if self.selected_index is not None else None
|
return self[self.selected_index] if self.selected_index is not None else None
|
||||||
|
|
||||||
@selected_row.setter
|
@selected_row.setter
|
||||||
@ -196,35 +196,114 @@ class Table(MutableSequence, Selectable):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def selected_rows(self):
|
def selected_rows(self):
|
||||||
|
"""List of selected rows based on :attr:`~hscommon.gui.selectable_list.Selectable.selected_indexes`.
|
||||||
|
|
||||||
|
List of :class:`Row`. *read-only*.
|
||||||
|
"""
|
||||||
return [self[index] for index in self.selected_indexes]
|
return [self[index] for index in self.selected_indexes]
|
||||||
|
|
||||||
|
|
||||||
|
class GUITableView:
|
||||||
|
"""Expected interface for :class:`GUITable`'s view.
|
||||||
|
|
||||||
|
*Not actually used in the code. For documentation purposes only.*
|
||||||
|
|
||||||
|
Our view, some kind of table view, is expected to sync with the table's contents by
|
||||||
|
appropriately behave to all callbacks in this interface.
|
||||||
|
|
||||||
|
When in edit mode, the content types by the user is expected to be sent as soon as possible
|
||||||
|
to the :class:`Row`.
|
||||||
|
|
||||||
|
Whenever the user changes the selection, we expect the view to call :meth:`Table.select`.
|
||||||
|
"""
|
||||||
|
def refresh(self):
|
||||||
|
"""Refreshes the contents of the table widget.
|
||||||
|
|
||||||
|
Ensures that the contents of the table widget is synced with the model. This includes
|
||||||
|
selection.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def start_editing(self):
|
||||||
|
"""Start editing the currently selected row.
|
||||||
|
|
||||||
|
Begin whatever inline editing support that the view supports.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def stop_editing(self):
|
||||||
|
"""Stop editing if there's an inline editing in effect.
|
||||||
|
|
||||||
|
There's no "aborting" implied in this call, so it's appropriate to send whatever the user
|
||||||
|
has typed and might not have been sent down to the :class:`Row` yet. After you've done that,
|
||||||
|
stop the editing mechanism.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
SortDescriptor = namedtuple('SortDescriptor', 'column desc')
|
SortDescriptor = namedtuple('SortDescriptor', 'column desc')
|
||||||
class GUITable(Table, GUIObject):
|
class GUITable(Table, GUIObject):
|
||||||
|
"""Cross-toolkit GUI-enabled table view.
|
||||||
|
|
||||||
|
Represents a UI element presenting the user with a sortable, selectable, possibly editable,
|
||||||
|
table view.
|
||||||
|
|
||||||
|
Behaves like the :class:`Table` which it subclasses, but is more focused on being the presenter
|
||||||
|
of some model data to its :attr:`~hscommon.gui.base.GUIObject.view`. There's a :meth:`refresh`
|
||||||
|
mechanism which ensures fresh data while preserving sorting order and selection. There's also an
|
||||||
|
editing mechanism which tracks whether (and which) row is being edited (or added) and
|
||||||
|
save/cancel edits when appropriate.
|
||||||
|
|
||||||
|
Subclasses :class:`Table` and :class:`~hscommon.gui.base.GUIObject`. Expected view:
|
||||||
|
:class:`GUITableView`.
|
||||||
|
"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
GUIObject.__init__(self)
|
GUIObject.__init__(self)
|
||||||
Table.__init__(self)
|
Table.__init__(self)
|
||||||
|
#: The row being currently edited by the user. ``None`` if no edit is taking place.
|
||||||
self.edited = None
|
self.edited = None
|
||||||
self._sort_descriptor = None
|
self._sort_descriptor = None
|
||||||
|
|
||||||
#--- Virtual
|
#--- Virtual
|
||||||
def _do_add(self):
|
def _do_add(self):
|
||||||
# Creates a new row, adds it in the table and returns (row, insert_index)
|
"""(Virtual) Creates a new row, adds it in the table.
|
||||||
|
|
||||||
|
Returns ``(row, insert_index)``.
|
||||||
|
"""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def _do_delete(self):
|
def _do_delete(self):
|
||||||
# Delete the selected rows
|
"""(Virtual) Delete the selected rows.
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _fill(self):
|
def _fill(self):
|
||||||
# Called by refresh()
|
"""(Virtual/Required) Fills the table with all the rows that this table is supposed to have.
|
||||||
# Fills the table with all the rows that this table is supposed to have.
|
|
||||||
|
Called by :meth:`refresh`. Does nothing by default.
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _is_edited_new(self):
|
def _is_edited_new(self):
|
||||||
|
"""(Virtual) Returns whether the currently edited row should be considered "new".
|
||||||
|
|
||||||
|
This is used in :meth:`cancel_edits` to know whether the cancellation of the edit means a
|
||||||
|
revert of the row's value or the removal of the row.
|
||||||
|
|
||||||
|
By default, always false.
|
||||||
|
"""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _restore_selection(self, previous_selection):
|
def _restore_selection(self, previous_selection):
|
||||||
|
"""(Virtual) Restores row selection after a contents-changing operation.
|
||||||
|
|
||||||
|
Before each contents changing operation, we store our previously selected indexes because in
|
||||||
|
many cases, such as in :meth:`refresh`, our selection will be lost. After the operation is
|
||||||
|
over, we call this method with our previously selected indexes (in ``previous_selection``).
|
||||||
|
|
||||||
|
The default behavior is (if we indeed have an empty
|
||||||
|
:attr:`~hscommon.gui.selectable_list.Selectable.selected_indexes`) to re-select
|
||||||
|
``previous_selection``. If it was empty, we select the last row of the table.
|
||||||
|
|
||||||
|
This behavior can, of course, be overriden.
|
||||||
|
"""
|
||||||
if not self.selected_indexes:
|
if not self.selected_indexes:
|
||||||
if previous_selection:
|
if previous_selection:
|
||||||
self.select(previous_selection)
|
self.select(previous_selection)
|
||||||
@ -233,6 +312,11 @@ class GUITable(Table, GUIObject):
|
|||||||
|
|
||||||
#--- Public
|
#--- Public
|
||||||
def add(self):
|
def add(self):
|
||||||
|
"""Add a new row in edit mode.
|
||||||
|
|
||||||
|
Requires :meth:`do_add` to be implemented. The newly added row will be selected and in edit
|
||||||
|
mode.
|
||||||
|
"""
|
||||||
self.view.stop_editing()
|
self.view.stop_editing()
|
||||||
if self.edited is not None:
|
if self.edited is not None:
|
||||||
self.save_edits()
|
self.save_edits()
|
||||||
@ -244,13 +328,22 @@ class GUITable(Table, GUIObject):
|
|||||||
self.view.start_editing()
|
self.view.start_editing()
|
||||||
|
|
||||||
def can_edit_cell(self, column_name, row_index):
|
def can_edit_cell(self, column_name, row_index):
|
||||||
# A row is, by default, editable as soon as it has an attr with the same name as `column`.
|
"""Returns whether the cell at ``row_index`` and ``column_name`` can be edited.
|
||||||
# If can_edit() returns False, the row is not editable at all. You can set editability of
|
|
||||||
# rows at the attribute level with can_edit_* properties
|
A row is, by default, editable as soon as it has an attr with the same name as `column`.
|
||||||
|
If :meth:`Row.can_edit` returns False, the row is not editable at all. You can set
|
||||||
|
editability of rows at the attribute level with can_edit_* properties.
|
||||||
|
|
||||||
|
Mostly just a shortcut to :meth:`Row.can_edit_cell`.
|
||||||
|
"""
|
||||||
row = self[row_index]
|
row = self[row_index]
|
||||||
return row.can_edit_cell(column_name)
|
return row.can_edit_cell(column_name)
|
||||||
|
|
||||||
def cancel_edits(self):
|
def cancel_edits(self):
|
||||||
|
"""Cancels the current edit operation.
|
||||||
|
|
||||||
|
If there's an :attr:`edited` row, it will be re-initialized (with :meth:`Row.load`).
|
||||||
|
"""
|
||||||
if self.edited is None:
|
if self.edited is None:
|
||||||
return
|
return
|
||||||
self.view.stop_editing()
|
self.view.stop_editing()
|
||||||
@ -265,6 +358,11 @@ class GUITable(Table, GUIObject):
|
|||||||
self.view.refresh()
|
self.view.refresh()
|
||||||
|
|
||||||
def delete(self):
|
def delete(self):
|
||||||
|
"""Delete the currently selected rows.
|
||||||
|
|
||||||
|
Requires :meth:`_do_delete` for this to have any effect on the model. Cancels editing if
|
||||||
|
relevant.
|
||||||
|
"""
|
||||||
self.view.stop_editing()
|
self.view.stop_editing()
|
||||||
if self.edited is not None:
|
if self.edited is not None:
|
||||||
self.cancel_edits()
|
self.cancel_edits()
|
||||||
@ -273,6 +371,16 @@ class GUITable(Table, GUIObject):
|
|||||||
self._do_delete()
|
self._do_delete()
|
||||||
|
|
||||||
def refresh(self, refresh_view=True):
|
def refresh(self, refresh_view=True):
|
||||||
|
"""Empty the table and re-create its rows.
|
||||||
|
|
||||||
|
:meth:`_fill` is called after we emptied the table to create our rows. Previous sort order
|
||||||
|
will be preserved, regardless of the order in which the rows were filled. If there was any
|
||||||
|
edit operation taking place, it's cancelled.
|
||||||
|
|
||||||
|
:param bool refresh_view: Whether we tell our view to refresh after our refill operation.
|
||||||
|
Most of the time, it's what we want, but there's some cases where
|
||||||
|
we don't.
|
||||||
|
"""
|
||||||
self.cancel_edits()
|
self.cancel_edits()
|
||||||
previous_selection = self.selected_indexes
|
previous_selection = self.selected_indexes
|
||||||
del self[:]
|
del self[:]
|
||||||
@ -285,6 +393,10 @@ class GUITable(Table, GUIObject):
|
|||||||
self.view.refresh()
|
self.view.refresh()
|
||||||
|
|
||||||
def save_edits(self):
|
def save_edits(self):
|
||||||
|
"""Commit user edits to the model.
|
||||||
|
|
||||||
|
This is done by calling :meth:`Row.save`.
|
||||||
|
"""
|
||||||
if self.edited is None:
|
if self.edited is None:
|
||||||
return
|
return
|
||||||
row = self.edited
|
row = self.edited
|
||||||
@ -292,6 +404,15 @@ class GUITable(Table, GUIObject):
|
|||||||
row.save()
|
row.save()
|
||||||
|
|
||||||
def sort_by(self, column_name, desc=False):
|
def sort_by(self, column_name, desc=False):
|
||||||
|
"""Sort table by ``column_name``.
|
||||||
|
|
||||||
|
Overrides :meth:`Table.sort_by`. After having performed sorting, calls
|
||||||
|
:meth:`~hscommon.gui.selectable_list.Selectable._update_selection` to give you the chance,
|
||||||
|
if appropriate, to update your selected indexes according to, maybe, the selection that you
|
||||||
|
have in your model.
|
||||||
|
|
||||||
|
Then, we refresh our view.
|
||||||
|
"""
|
||||||
Table.sort_by(self, column_name=column_name, desc=desc)
|
Table.sort_by(self, column_name=column_name, desc=desc)
|
||||||
self._sort_descriptor = SortDescriptor(column_name, desc)
|
self._sort_descriptor = SortDescriptor(column_name, desc)
|
||||||
self._update_selection()
|
self._update_selection()
|
||||||
|
@ -33,18 +33,6 @@ class TextField(GUIObject):
|
|||||||
us to directly retrieve/set our non-string value through :attr:`value`.
|
us to directly retrieve/set our non-string value through :attr:`value`.
|
||||||
|
|
||||||
Subclasses :class:`hscommon.gui.base.GUIObject`. Expected view: :class:`TextFieldView`.
|
Subclasses :class:`hscommon.gui.base.GUIObject`. Expected view: :class:`TextFieldView`.
|
||||||
|
|
||||||
.. attribute:: text
|
|
||||||
|
|
||||||
*str*. The text that is currently displayed in the widget. This property can be set. When it
|
|
||||||
is, :meth:`refresh` is called and the view is synced with our value. Always in sync with
|
|
||||||
:attr:`value`.
|
|
||||||
|
|
||||||
.. attribute:: value
|
|
||||||
|
|
||||||
The "parsed" representation of :attr:`text`. By default, it's a mirror of :attr:`text`, but
|
|
||||||
a subclass can override :meth:`_parse` and :meth:`_format` to have anything else. Always in
|
|
||||||
sync with :attr:`text`.
|
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
GUIObject.__init__(self)
|
GUIObject.__init__(self)
|
||||||
@ -85,6 +73,13 @@ class TextField(GUIObject):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def text(self):
|
def text(self):
|
||||||
|
"""The text that is currently displayed in the widget.
|
||||||
|
|
||||||
|
*str*. *get/set*.
|
||||||
|
|
||||||
|
This property can be set. When it is, :meth:`refresh` is called and the view is synced with
|
||||||
|
our value. Always in sync with :attr:`value`.
|
||||||
|
"""
|
||||||
return self._text
|
return self._text
|
||||||
|
|
||||||
@text.setter
|
@text.setter
|
||||||
@ -93,6 +88,13 @@ class TextField(GUIObject):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def value(self):
|
def value(self):
|
||||||
|
"""The "parsed" representation of :attr:`text`.
|
||||||
|
|
||||||
|
*arbitrary type*. *get/set*.
|
||||||
|
|
||||||
|
By default, it's a mirror of :attr:`text`, but a subclass can override :meth:`_parse` and
|
||||||
|
:meth:`_format` to have anything else. Always in sync with :attr:`text`.
|
||||||
|
"""
|
||||||
return self._value
|
return self._value
|
||||||
|
|
||||||
@value.setter
|
@value.setter
|
||||||
|
Loading…
x
Reference in New Issue
Block a user