File: qt_table_view.py

package info (click to toggle)
python-enamlx 0.6.4-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 388 kB
  • sloc: python: 3,338; makefile: 18
file content (204 lines) | stat: -rw-r--r-- 6,836 bytes parent folder | download
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
# -*- coding: utf-8 -*-
"""
Copyright (c) 2015, Jairus Martin.
Distributed under the terms of the MIT License.
The full license is in the file COPYING.txt, distributed with this software.
Created on Aug 28, 2015
"""
from atom.api import Int, Typed
from enaml.application import timed_call
from qtpy.QtCore import QAbstractTableModel
from qtpy.QtWidgets import QTableView

from enamlx.qt.qt_abstract_item import (
    RESIZE_MODES,
    AbstractQtWidgetItem,
    AbstractQtWidgetItemGroup,
)
from enamlx.qt.qt_abstract_item_view import QAbstractAtomItemModel, QtAbstractItemView
from enamlx.widgets.table_view import (
    ProxyTableView,
    ProxyTableViewColumn,
    ProxyTableViewItem,
    ProxyTableViewRow,
)


class QAtomTableModel(QAbstractAtomItemModel, QAbstractTableModel):
    """Model that pulls it's data from the TableViewItems
    declaration.
    """

    def rowCount(self, parent=None):
        d = self.declaration
        return len(d.vertical_headers if d.vertical_headers else d.items)

    def columnCount(self, parent=None):
        d = self.declaration
        return len(d.horizontal_headers if d.horizontal_headers else d.items)

    def itemAt(self, index):
        if not index.isValid():
            return None
        d = self.declaration
        try:
            d.current_row = index.row()
            d.current_column = index.column()
            r = d.current_row - d.visible_row
            c = d.current_column - d.visible_column
            return d._items[r]._items[c].proxy
        except IndexError:
            return None


class QtTableView(QtAbstractItemView, ProxyTableView):
    #: Proxy widget
    widget = Typed(QTableView)

    def create_widget(self):
        self.widget = QTableView(self.parent_widget())

    def init_widget(self):
        super(QtTableView, self).init_widget()
        d = self.declaration
        self.set_show_grid(d.show_grid)

    def init_model(self):
        self.set_model(QAtomTableModel(parent=self.widget))

    # -------------------------------------------------------------------------
    # Widget settters
    # -------------------------------------------------------------------------
    def set_show_grid(self, show):
        self.widget.setShowGrid(show)

    def set_cell_padding(self, padding):
        self.widget.setStyleSheet("QTableView::item { padding: %ipx }" % padding)

    def set_vertical_minimum_section_size(self, size):
        self.widget.verticalHeader().setMinimumSectionSize(size)

    def set_horizontal_minimum_section_size(self, size):
        self.widget.horizontalHeader().setMinimumSectionSize(size)

    def set_horizontal_stretch(self, stretch):
        self.widget.horizontalHeader().setStretchLastSection(stretch)

    def set_vertical_stretch(self, stretch):
        self.widget.verticalHeader().setStretchLastSection(stretch)

    def set_resize_mode(self, mode):
        header = self.widget.horizontalHeader()
        # Custom is obsolete, use fixed instead.
        mode = "fixed" if mode == "custom" else mode
        header.setSectionResizeMode(RESIZE_MODES[mode])

    def set_show_horizontal_header(self, show):
        header = self.widget.horizontalHeader()
        header.show() if show else header.hide()

    def set_show_vertical_header(self, show):
        header = self.widget.verticalHeader()
        header.show() if show else header.hide()

    # -------------------------------------------------------------------------
    # View refresh handlers
    # -------------------------------------------------------------------------
    def _refresh_visible_column(self, value):
        self._pending_column_refreshes -= 1
        if self._pending_column_refreshes == 0:
            d = self.declaration
            cols = self.model.columnCount() - d.visible_columns
            d.visible_column = max(0, min(value, cols))

    def _refresh_visible_row(self, value):
        self._pending_row_refreshes -= 1
        if self._pending_row_refreshes == 0 and (self.declaration is not None):
            d = self.declaration
            rows = self.model.rowCount() - d.visible_rows
            d.visible_row = max(0, min(value, rows))

    def _refresh_visible_rows(self):
        return
        top = self.widget.rowAt(self.widget.rect().top())
        bottom = self.widget.rowAt(self.widget.rect().bottom())
        self.declaration.visible_rows = max(1, (bottom - top)) * 2  # 2x for safety

    def _refresh_visible_columns(self):
        return
        left = self.widget.rowAt(self.widget.rect().left())
        right = self.widget.rowAt(self.widget.rect().right())
        self.declaration.visible_columns = max(1, (right - left)) * 2


class AbstractQtTableViewItemGroup(AbstractQtWidgetItemGroup):
    def create_widget(self):
        pass

    @property
    def widget(self):
        return self.parent_widget()


class QtTableViewItem(AbstractQtWidgetItem, ProxyTableViewItem):
    #: Pending refreshes when loading widgets
    _refresh_count = Int(0)

    #: Time to wait before loading widget in ms
    _loading_interval = Int(100)

    def _default_view(self):
        return self.parent().parent()

    def set_row(self, row):
        self._update_index()

    def set_column(self, column):
        self._update_index()

    def _update_index(self):
        """Update the reference to the index within the table"""
        d = self.declaration
        self.index = self.view.model.index(d.row, d.column)
        if self.delegate:
            self._refresh_count += 1
            timed_call(self._loading_interval, self._update_delegate)

    def _update_delegate(self):
        """Update the delegate cell widget. This is deferred so it
        does not get called until the user is done scrolling.
        """
        self._refresh_count -= 1
        if self._refresh_count != 0:
            return
        try:
            delegate = self.delegate
            if not self.is_visible():
                return
            # The table destroys when it goes out of view
            # so we always have to make a new one
            delegate.create_widget()
            delegate.init_widget()

            #  Set the index widget
            self.view.widget.setIndexWidget(self.index, delegate.widget)
        except RuntimeError:
            pass  # Since this is deferred, the table could be deleted already

    def is_visible(self):
        """Check if this index is currently visible"""
        return True

    def data_changed(self, change):
        """Notify the model that data has changed in this cell!"""
        index = self.index
        if index:
            self.view.model.dataChanged.emit(index, index)


class QtTableViewRow(AbstractQtTableViewItemGroup, ProxyTableViewRow):
    pass


class QtTableViewColumn(AbstractQtTableViewItemGroup, ProxyTableViewColumn):
    pass