|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2010 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing a widget to select a symbol in various formats. |
|
8 """ |
|
9 |
|
10 import unicodedata |
|
11 import html.entities |
|
12 |
|
13 from PyQt4.QtCore import pyqtSlot, pyqtSignal, QAbstractTableModel, QModelIndex, Qt |
|
14 from PyQt4.QtGui import QWidget, QHeaderView, QAbstractItemView, QColor |
|
15 |
|
16 from .Ui_SymbolsWidget import Ui_SymbolsWidget |
|
17 |
|
18 class SymbolsModel(QAbstractTableModel): |
|
19 """ |
|
20 Class implementing the model for the symbols widget. |
|
21 """ |
|
22 def __init__(self, parent = None): |
|
23 """ |
|
24 Constructor |
|
25 |
|
26 @param parent reference to the parent object (QObject) |
|
27 """ |
|
28 QAbstractTableModel.__init__(self, parent) |
|
29 |
|
30 self.__headerData = [ |
|
31 self.trUtf8("Code"), |
|
32 self.trUtf8("Char"), |
|
33 self.trUtf8("Hex"), |
|
34 self.trUtf8("HTML"), |
|
35 ] |
|
36 |
|
37 self.__unicode = True |
|
38 |
|
39 def setUnicode(self, u): |
|
40 """ |
|
41 Public method to set the mode of the model. |
|
42 |
|
43 @param u flag indicating unicode mode (boolean) |
|
44 """ |
|
45 self.__unicode = u |
|
46 self.reset() |
|
47 |
|
48 def headerData(self, section, orientation, role = Qt.DisplayRole): |
|
49 """ |
|
50 Public method to get header data from the model. |
|
51 |
|
52 @param section section number (integer) |
|
53 @param orientation orientation (Qt.Orientation) |
|
54 @param role role of the data to retrieve (integer) |
|
55 @return requested data |
|
56 """ |
|
57 if orientation == Qt.Horizontal and role == Qt.DisplayRole: |
|
58 return self.__headerData[section] |
|
59 |
|
60 return QAbstractTableModel.headerData(self, section, orientation, role) |
|
61 |
|
62 def data(self, index, role = Qt.DisplayRole): |
|
63 """ |
|
64 Public method to get data from the model. |
|
65 |
|
66 @param index index to get data for (QModelIndex) |
|
67 @param role role of the data to retrieve (integer) |
|
68 @return requested data |
|
69 """ |
|
70 id = index.row() |
|
71 |
|
72 if role == Qt.DisplayRole: |
|
73 col = index.column() |
|
74 if col == 0: |
|
75 return str(id) |
|
76 elif col == 1: |
|
77 return chr(id) |
|
78 elif col == 2: |
|
79 return "0x{0:04x}".format(id) |
|
80 elif col == 3: |
|
81 if id in html.entities.codepoint2name: |
|
82 return "&{0};".format(html.entities.codepoint2name[id]) |
|
83 |
|
84 if role == Qt.BackgroundColorRole: |
|
85 if index.column() == 0: |
|
86 return QColor(Qt.lightGray) |
|
87 |
|
88 if role == Qt.TextColorRole: |
|
89 char = chr(id) |
|
90 if self.__isDigit(char): |
|
91 return QColor(Qt.darkBlue) |
|
92 elif self.__isLetter(char): |
|
93 return QColor(Qt.darkGreen) |
|
94 elif self.__isMark(char): |
|
95 return QColor(Qt.darkRed) |
|
96 elif self.__isSymbol(char): |
|
97 return QColor(Qt.black) |
|
98 elif self.__isPunct(char): |
|
99 return QColor(Qt.darkMagenta) |
|
100 else: |
|
101 return QColor(Qt.darkGray) |
|
102 |
|
103 if role == Qt.TextAlignmentRole: |
|
104 if index.column() in [0, 1, 3]: |
|
105 return Qt.AlignHCenter |
|
106 |
|
107 return None |
|
108 |
|
109 def columnCount(self, parent): |
|
110 """ |
|
111 Public method to get the number of columns of the model. |
|
112 |
|
113 @param parent parent index (QModelIndex) |
|
114 @return number of columns (integer) |
|
115 """ |
|
116 if parent.column() > 0: |
|
117 return 0 |
|
118 else: |
|
119 return len(self.__headerData) |
|
120 |
|
121 def rowCount(self, parent): |
|
122 """ |
|
123 Public method to get the number of rows of the model. |
|
124 |
|
125 @param parent parent index (QModelIndex) |
|
126 @return number of columns (integer) |
|
127 """ |
|
128 if parent.isValid(): |
|
129 return 0 |
|
130 else: |
|
131 if self.__unicode: |
|
132 return 65536 |
|
133 else: |
|
134 return 256 |
|
135 |
|
136 def __isDigit(self, char): |
|
137 """ |
|
138 Private method to check, if a character is a digit. |
|
139 |
|
140 @param char character to test (one character string) |
|
141 @return flag indicating a digit (boolean) |
|
142 """ |
|
143 return unicodedata.category(char) == "Nd" |
|
144 |
|
145 def __isLetter(self, char): |
|
146 """ |
|
147 Private method to check, if a character is a letter. |
|
148 |
|
149 @param char character to test (one character string) |
|
150 @return flag indicating a letter (boolean) |
|
151 """ |
|
152 return unicodedata.category(char) in ["Lu", "Ll", "Lt", "Lm", "Lo"] |
|
153 |
|
154 def __isMark(self, char): |
|
155 """ |
|
156 Private method to check, if a character is a mark character. |
|
157 |
|
158 @param char character to test (one character string) |
|
159 @return flag indicating a mark character (boolean) |
|
160 """ |
|
161 return unicodedata.category(char) in ["Mn", "Mc", "Me"] |
|
162 |
|
163 def __isSymbol(self, char): |
|
164 """ |
|
165 Private method to check, if a character is a symbol. |
|
166 |
|
167 @param char character to test (one character string) |
|
168 @return flag indicating a symbol (boolean) |
|
169 """ |
|
170 return unicodedata.category(char) in ["Sm", "Sc", "Sk", "So"] |
|
171 |
|
172 def __isPunct(self, char): |
|
173 """ |
|
174 Private method to check, if a character is a punctuation character. |
|
175 |
|
176 @param char character to test (one character string) |
|
177 @return flag indicating a punctuation character (boolean) |
|
178 """ |
|
179 return unicodedata.category(char) in ["Pc", "Pd", "Ps", "Pe", "Pi", "Pf", "Po"] |
|
180 |
|
181 class SymbolsWidget(QWidget, Ui_SymbolsWidget): |
|
182 """ |
|
183 Class implementing a widget to select a symbol in various formats. |
|
184 |
|
185 @signal insertSymbol(str) emitted after the user has selected a symbol |
|
186 """ |
|
187 insertSymbol = pyqtSignal(str) |
|
188 |
|
189 def __init__(self, parent = None): |
|
190 """ |
|
191 Constructor |
|
192 |
|
193 @param parent reference to the parent widget (QWidget) |
|
194 """ |
|
195 QWidget.__init__(self, parent) |
|
196 self.setupUi(self) |
|
197 |
|
198 self.__model = SymbolsModel(self) |
|
199 self.symbolsTable.setModel(self.__model) |
|
200 self.symbolsTable.horizontalHeader().setResizeMode(QHeaderView.Fixed) |
|
201 |
|
202 fm = self.fontMetrics() |
|
203 em = fm.width("M") |
|
204 self.symbolsTable.horizontalHeader().resizeSection(0, em * 5) |
|
205 self.symbolsTable.horizontalHeader().resizeSection(1, em * 5) |
|
206 self.symbolsTable.horizontalHeader().resizeSection(2, em * 6) |
|
207 self.symbolsTable.horizontalHeader().resizeSection(3, em * 8) |
|
208 self.symbolsTable.verticalHeader().setDefaultSectionSize(fm.height() + 4) |
|
209 |
|
210 @pyqtSlot(QModelIndex) |
|
211 def on_symbolsTable_activated(self, index): |
|
212 """ |
|
213 Private slot to signal the selection of a symbol. |
|
214 |
|
215 @param index index of the selected symbol (QModelIndex) |
|
216 """ |
|
217 txt = self.__model.data(index) |
|
218 if txt: |
|
219 self.insertSymbol.emit(txt) |
|
220 |
|
221 @pyqtSlot(bool) |
|
222 def on_unicodeButton_toggled(self, checked): |
|
223 """ |
|
224 Private slot to switch unicode mode. |
|
225 |
|
226 @param checked flag indicating that the button is pressed (boolean) |
|
227 """ |
|
228 self.symbolsTable.setUpdatesEnabled(False) |
|
229 self.__model.setUnicode(checked) |
|
230 self.symbolsTable.setUpdatesEnabled(True) |
|
231 |
|
232 @pyqtSlot() |
|
233 def on_symbolSpinBox_editingFinished(self): |
|
234 """ |
|
235 Private slot to move the table to the entered symbol id. |
|
236 """ |
|
237 id = self.symbolSpinBox.value() |
|
238 self.symbolsTable.selectRow(id) |
|
239 self.symbolsTable.scrollTo( |
|
240 self.__model.index(id, 0), QAbstractItemView.PositionAtCenter) |