1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
|
# (C) Copyright 2005-2023 Enthought, Inc., Austin, TX
# All rights reserved.
#
# This software is provided without warranty under the terms of the BSD
# license included in LICENSE.txt and may be redistributed only under
# the conditions described in the aforementioned license. The license
# is also available online at http://www.enthought.com/licenses/BSD.txt
#
# Thanks for using Enthought open source!
import logging
import warnings
import wx
from wx.dataview import (
DataViewCtrl, DataViewEvent, DataViewItemArray,
DataViewModel as wxDataViewModel,
DATAVIEW_CELL_EDITABLE, DATAVIEW_CELL_ACTIVATABLE,
DV_MULTIPLE, DV_NO_HEADER, EVT_DATAVIEW_SELECTION_CHANGED,
wxEVT_DATAVIEW_SELECTION_CHANGED
)
from traits.api import Enum, Instance, observe, provides
from pyface.data_view.i_data_view_widget import (
IDataViewWidget, MDataViewWidget
)
from pyface.data_view.data_view_errors import DataViewGetError
from pyface.ui.wx.layout_widget import LayoutWidget
from .data_view_model import DataViewModel
logger = logging.getLogger(__name__)
# XXX This file is scaffolding and may need to be rewritten
@provides(IDataViewWidget)
class DataViewWidget(MDataViewWidget, LayoutWidget):
""" The Wx implementation of the DataViewWidget. """
#: What can be selected.
selection_type = Enum("row")
#: How selections are modified.
selection_mode = Enum("extended", "single")
# Private traits --------------------------------------------------------
#: The QAbstractItemModel instance used by the view. This will
#: usually be a DataViewModel subclass.
_item_model = Instance(wxDataViewModel)
# ------------------------------------------------------------------------
# IDataViewWidget Interface
# ------------------------------------------------------------------------
def _create_item_model(self):
""" Create the DataViewItemModel which wraps the data model. """
self._item_model = DataViewModel(self.data_model)
def _get_control_header_visible(self):
""" Method to get the control's header visibility. """
return not self.control.GetWindowStyleFlag() & DV_NO_HEADER
def _set_control_header_visible(self, header_visible):
""" Method to set the control's header visibility. """
old_visible = self._get_control_header_visible()
if header_visible != old_visible:
self.control.ToggleWindowStyle(DV_NO_HEADER)
def _get_control_selection_type(self):
""" Toolkit specific method to get the selection type. """
return "row"
def _set_control_selection_type(self, selection_type):
""" Toolkit specific method to change the selection type. """
if selection_type != "row":
warnings.warn(
"{!r} selection_type not supported in Wx".format(
selection_type
),
RuntimeWarning,
)
def _get_control_selection_mode(self):
""" Toolkit specific method to get the selection mode. """
if self.control.GetWindowStyleFlag() & DV_MULTIPLE:
return "extended"
else:
return "single"
def _set_control_selection_mode(self, selection_mode):
""" Toolkit specific method to change the selection mode. """
if selection_mode not in {'extended', 'single'}:
warnings.warn(
"{!r} selection_mode not supported in Wx".format(
selection_mode
),
RuntimeWarning,
)
return
old_mode = self._get_control_selection_mode()
if selection_mode != old_mode:
self.control.ToggleWindowStyle(DV_MULTIPLE)
def _get_control_selection(self):
""" Toolkit specific method to get the selection. """
return [
(self._item_model._to_row_index(item), ())
for item in self.control.GetSelections()
]
def _set_control_selection(self, selection):
""" Toolkit specific method to change the selection. """
wx_selection = DataViewItemArray()
for row, column in selection:
item = self._item_model._to_item(row)
wx_selection.append(item)
self.control.SetSelections(wx_selection)
if wx.VERSION >= (4, 1):
if len(wx_selection) > 0:
item = wx_selection[-1]
else:
# a dummy item because we have nothing specific
item = self._item_model._to_item((0,))
event = DataViewEvent(
wxEVT_DATAVIEW_SELECTION_CHANGED,
self.control,
item,
)
else:
event = DataViewEvent(
wxEVT_DATAVIEW_SELECTION_CHANGED,
)
wx.PostEvent(self.control, event)
def _observe_control_selection(self, remove=False):
""" Toolkit specific method to watch for changes in the selection. """
if remove:
self.control.Unbind(
EVT_DATAVIEW_SELECTION_CHANGED,
handler=self._update_selection,
)
else:
self.control.Bind(
EVT_DATAVIEW_SELECTION_CHANGED,
self._update_selection,
)
# ------------------------------------------------------------------------
# Widget Interface
# ------------------------------------------------------------------------
def _create_control(self, parent):
""" Create the DataViewWidget's toolkit control. """
self._create_item_model()
control = DataViewCtrl(parent)
control.AssociateModel(self._item_model)
# required for wxPython refcounting system
self._item_model.DecRef()
# create columns for view
value_type = self._item_model.model.get_value_type([], [])
try:
text = value_type.get_text(self._item_model.model, [], [])
except DataViewGetError:
text = ''
except Exception:
# unexpected error, log and raise
logger.exception("get header data failed: column ()")
raise
control.AppendTextColumn(text, 0, mode=DATAVIEW_CELL_ACTIVATABLE)
for column in range(self._item_model.GetColumnCount()-1):
value_type = self._item_model.model.get_value_type([], [column])
try:
text = value_type.get_text(self._item_model.model, [], [column])
except DataViewGetError:
text = ''
except Exception:
# unexpected error, log and raise
logger.exception(
"get header data failed: column (%r,)",
column,
)
raise
control.AppendTextColumn(
text,
column+1,
mode=DATAVIEW_CELL_EDITABLE,
)
return control
def destroy(self):
""" Perform any actions required to destroy the control. """
super().destroy()
# ensure that we release the reference to the item model
self._item_model = None
# ------------------------------------------------------------------------
# Private methods
# ------------------------------------------------------------------------
# Trait observers
@observe('data_model', dispatch='ui')
def update_item_model(self, event):
if self._item_model is not None:
self._item_model.model = event.new
|