1 | package com.jsql.view.swing.table; | |
2 | ||
3 | import javax.swing.*; | |
4 | import javax.swing.event.TableModelEvent; | |
5 | import javax.swing.event.TableModelListener; | |
6 | import javax.swing.table.TableCellRenderer; | |
7 | import javax.swing.table.TableColumn; | |
8 | import javax.swing.table.TableColumnModel; | |
9 | import javax.swing.table.TableModel; | |
10 | import java.awt.*; | |
11 | import java.awt.event.ActionEvent; | |
12 | import java.beans.PropertyChangeEvent; | |
13 | import java.beans.PropertyChangeListener; | |
14 | import java.util.HashMap; | |
15 | import java.util.Map; | |
16 | ||
17 | /** | |
18 | * Class to manage the widths of columns in a table. | |
19 | * | |
20 | * Various properties control how the width of the column is calculated. | |
21 | * Another property controls whether column width calculation should be dynamic. | |
22 | * Finally, various Actions will be added to the table to allow the user | |
23 | * to customize the functionality. | |
24 | * | |
25 | * This class was designed to be used with tables that use an auto resize mode | |
26 | * of AUTO_RESIZE_OFF. With all other modes you are constrained as the width | |
27 | * of the columns must fit inside the table. So if you increase one column, one | |
28 | * or more of the other columns must decrease. Because of this the resize mode | |
29 | * of RESIZE_ALL_COLUMNS will work the best. | |
30 | */ | |
31 | public class AdjusterTableColumn implements PropertyChangeListener, TableModelListener { | |
32 | | |
33 | private final JTable tableAdjust; | |
34 | private final int spacing; | |
35 | private boolean isColumnHeaderIncluded; | |
36 | private boolean isColumnDataIncluded; | |
37 | private boolean isOnlyAdjustLarger; | |
38 | private boolean isDynamicAdjustment; | |
39 | private final Map<TableColumn, Integer> columnSizes = new HashMap<>(); | |
40 | ||
41 | /** | |
42 | * Specify the table and use default spacing | |
43 | */ | |
44 | public AdjusterTableColumn(JTable table) { | |
45 | this(table, 6); | |
46 | } | |
47 | ||
48 | /** | |
49 | * Specify the table and spacing | |
50 | */ | |
51 | public AdjusterTableColumn(JTable tableAdjust, int spacing) { | |
52 | this.tableAdjust = tableAdjust; | |
53 | this.spacing = spacing; | |
54 |
1
1. <init> : removed call to com/jsql/view/swing/table/AdjusterTableColumn::setColumnHeaderIncluded → NO_COVERAGE |
this.setColumnHeaderIncluded(true); |
55 |
1
1. <init> : removed call to com/jsql/view/swing/table/AdjusterTableColumn::setColumnDataIncluded → NO_COVERAGE |
this.setColumnDataIncluded(true); |
56 |
1
1. <init> : removed call to com/jsql/view/swing/table/AdjusterTableColumn::setOnlyAdjustLarger → NO_COVERAGE |
this.setOnlyAdjustLarger(true); |
57 |
1
1. <init> : removed call to com/jsql/view/swing/table/AdjusterTableColumn::setDynamicAdjustment → NO_COVERAGE |
this.setDynamicAdjustment(false); |
58 |
1
1. <init> : removed call to com/jsql/view/swing/table/AdjusterTableColumn::installActions → NO_COVERAGE |
this.installActions(); |
59 | } | |
60 | ||
61 | /** | |
62 | * Adjust the widths of all the columns in the table | |
63 | */ | |
64 | public void adjustColumns() { | |
65 | TableColumnModel tcm = this.tableAdjust.getColumnModel(); | |
66 |
2
1. adjustColumns : changed conditional boundary → NO_COVERAGE 2. adjustColumns : negated conditional → NO_COVERAGE |
for (var i = 0 ; i < tcm.getColumnCount() ; i++) { |
67 |
1
1. adjustColumns : removed call to com/jsql/view/swing/table/AdjusterTableColumn::adjustColumn → NO_COVERAGE |
this.adjustColumn(i); |
68 | } | |
69 | } | |
70 | ||
71 | /** | |
72 | * Adjust the width of the specified column in the table | |
73 | */ | |
74 | public void adjustColumn(final int column) { | |
75 | var tableColumn = this.tableAdjust.getColumnModel().getColumn(column); | |
76 |
1
1. adjustColumn : negated conditional → NO_COVERAGE |
if (!tableColumn.getResizable()) { |
77 | return; | |
78 | } | |
79 | ||
80 | int columnHeaderWidth = this.getColumnHeaderWidth(column); | |
81 | int columnDataWidth = this.getColumnDataWidth(column); | |
82 | int preferredWidth = Math.max(columnHeaderWidth, columnDataWidth); | |
83 |
1
1. adjustColumn : removed call to com/jsql/view/swing/table/AdjusterTableColumn::updateTableColumn → NO_COVERAGE |
this.updateTableColumn(column, preferredWidth); |
84 | } | |
85 | ||
86 | /** | |
87 | * Calculated the width based on the column name | |
88 | */ | |
89 | private int getColumnHeaderWidth(int column) { | |
90 |
1
1. getColumnHeaderWidth : negated conditional → NO_COVERAGE |
if (!this.isColumnHeaderIncluded) { |
91 | return 0; | |
92 | } | |
93 | ||
94 | var tableColumn = this.tableAdjust.getColumnModel().getColumn(column); | |
95 | Object value = tableColumn.getHeaderValue(); | |
96 | TableCellRenderer renderer = tableColumn.getHeaderRenderer(); | |
97 |
1
1. getColumnHeaderWidth : negated conditional → NO_COVERAGE |
if (renderer == null) { |
98 | renderer = this.tableAdjust.getTableHeader().getDefaultRenderer(); | |
99 | } | |
100 | ||
101 | var c = renderer.getTableCellRendererComponent(this.tableAdjust, value, false, false, -1, column); | |
102 |
1
1. getColumnHeaderWidth : replaced int return with 0 for com/jsql/view/swing/table/AdjusterTableColumn::getColumnHeaderWidth → NO_COVERAGE |
return c.getPreferredSize().width; |
103 | } | |
104 | ||
105 | /** | |
106 | * Calculate the width based on the widest cell renderer for the | |
107 | * given column. | |
108 | */ | |
109 | private int getColumnDataWidth(int column) { | |
110 |
1
1. getColumnDataWidth : negated conditional → NO_COVERAGE |
if (!this.isColumnDataIncluded) { |
111 | return 0; | |
112 | } | |
113 | ||
114 | var preferredWidth = 0; | |
115 | int maxWidth = this.tableAdjust.getColumnModel().getColumn(column).getMaxWidth(); | |
116 | ||
117 |
2
1. getColumnDataWidth : changed conditional boundary → NO_COVERAGE 2. getColumnDataWidth : negated conditional → NO_COVERAGE |
for (var row = 0 ; row < this.tableAdjust.getRowCount() ; row++) { |
118 | preferredWidth = Math.max(preferredWidth, this.getCellDataWidth(row, column)); | |
119 | // We've exceeded the maximum width, no need to check other rows | |
120 |
2
1. getColumnDataWidth : changed conditional boundary → NO_COVERAGE 2. getColumnDataWidth : negated conditional → NO_COVERAGE |
if (preferredWidth >= maxWidth) { |
121 | break; | |
122 | } | |
123 | } | |
124 |
1
1. getColumnDataWidth : replaced int return with 0 for com/jsql/view/swing/table/AdjusterTableColumn::getColumnDataWidth → NO_COVERAGE |
return preferredWidth; |
125 | } | |
126 | ||
127 | /** | |
128 | * Get the preferred width for the specified cell | |
129 | */ | |
130 | private int getCellDataWidth(int row, int column) { | |
131 | // Invoke the renderer for the cell to calculate the preferred width | |
132 | TableCellRenderer cellRenderer = this.tableAdjust.getCellRenderer(row, column); | |
133 | Component c = this.tableAdjust.prepareRenderer(cellRenderer, row, column); | |
134 |
2
1. getCellDataWidth : Replaced integer addition with subtraction → NO_COVERAGE 2. getCellDataWidth : replaced int return with 0 for com/jsql/view/swing/table/AdjusterTableColumn::getCellDataWidth → NO_COVERAGE |
return c.getPreferredSize().width + this.tableAdjust.getIntercellSpacing().width; |
135 | } | |
136 | ||
137 | /** | |
138 | * Update the TableColumn with the newly calculated width | |
139 | */ | |
140 | private void updateTableColumn(int column, int width) { | |
141 | final var tableColumn = this.tableAdjust.getColumnModel().getColumn(column); | |
142 |
1
1. updateTableColumn : negated conditional → NO_COVERAGE |
if (!tableColumn.getResizable()) { |
143 | return; | |
144 | } | |
145 | ||
146 | int calculatedWidth = width; | |
147 |
1
1. updateTableColumn : Replaced integer addition with subtraction → NO_COVERAGE |
calculatedWidth += this.spacing; |
148 | // Don't shrink the column width | |
149 |
1
1. updateTableColumn : negated conditional → NO_COVERAGE |
if (this.isOnlyAdjustLarger) { |
150 | calculatedWidth = Math.max(calculatedWidth, tableColumn.getPreferredWidth()); | |
151 | } | |
152 | ||
153 | this.columnSizes.put(tableColumn, tableColumn.getWidth()); | |
154 |
1
1. updateTableColumn : removed call to javax/swing/table/JTableHeader::setResizingColumn → NO_COVERAGE |
this.tableAdjust.getTableHeader().setResizingColumn(tableColumn); |
155 |
1
1. updateTableColumn : removed call to javax/swing/table/TableColumn::setWidth → NO_COVERAGE |
tableColumn.setWidth(calculatedWidth); |
156 | } | |
157 | ||
158 | /** | |
159 | * Restore the widths of the columns in the table to its previous width | |
160 | */ | |
161 | public void restoreColumns() { | |
162 | TableColumnModel tableColumnModel = this.tableAdjust.getColumnModel(); | |
163 |
2
1. restoreColumns : changed conditional boundary → NO_COVERAGE 2. restoreColumns : negated conditional → NO_COVERAGE |
for (var i = 0 ; i < tableColumnModel.getColumnCount() ; i++) { |
164 |
1
1. restoreColumns : removed call to com/jsql/view/swing/table/AdjusterTableColumn::restoreColumn → NO_COVERAGE |
this.restoreColumn(i); |
165 | } | |
166 | } | |
167 | ||
168 | /** | |
169 | * Restore the width of the specified column to its previous width | |
170 | */ | |
171 | private void restoreColumn(int column) { | |
172 | var tableColumn = this.tableAdjust.getColumnModel().getColumn(column); | |
173 | Integer width = this.columnSizes.get(tableColumn); | |
174 |
1
1. restoreColumn : negated conditional → NO_COVERAGE |
if (width != null) { |
175 |
1
1. restoreColumn : removed call to javax/swing/table/JTableHeader::setResizingColumn → NO_COVERAGE |
this.tableAdjust.getTableHeader().setResizingColumn(tableColumn); |
176 |
1
1. restoreColumn : removed call to javax/swing/table/TableColumn::setWidth → NO_COVERAGE |
tableColumn.setWidth(width); |
177 | } | |
178 | } | |
179 | ||
180 | /** | |
181 | * Indicates whether to include the header in the width calculation | |
182 | */ | |
183 | public void setColumnHeaderIncluded(boolean isColumnHeaderIncluded) { | |
184 | this.isColumnHeaderIncluded = isColumnHeaderIncluded; | |
185 | } | |
186 | ||
187 | /** | |
188 | * Indicates whether to include the model data in the width calculation | |
189 | */ | |
190 | public void setColumnDataIncluded(boolean isColumnDataIncluded) { | |
191 | this.isColumnDataIncluded = isColumnDataIncluded; | |
192 | } | |
193 | ||
194 | /** | |
195 | * Indicates whether columns can only be increased in size | |
196 | */ | |
197 | public void setOnlyAdjustLarger(boolean isOnlyAdjustLarger) { | |
198 | this.isOnlyAdjustLarger = isOnlyAdjustLarger; | |
199 | } | |
200 | ||
201 | /** | |
202 | * Indicate whether changes to the model should cause the width to be | |
203 | * dynamically recalculated. | |
204 | */ | |
205 | public void setDynamicAdjustment(boolean isDynamicAdjustment) { | |
206 | // May need to add or remove the TableModelListener when changed | |
207 |
1
1. setDynamicAdjustment : negated conditional → NO_COVERAGE |
if (this.isDynamicAdjustment != isDynamicAdjustment) { |
208 |
1
1. setDynamicAdjustment : negated conditional → NO_COVERAGE |
if (isDynamicAdjustment) { |
209 |
1
1. setDynamicAdjustment : removed call to javax/swing/JTable::addPropertyChangeListener → NO_COVERAGE |
this.tableAdjust.addPropertyChangeListener(this); |
210 |
1
1. setDynamicAdjustment : removed call to javax/swing/table/TableModel::addTableModelListener → NO_COVERAGE |
this.tableAdjust.getModel().addTableModelListener(this); |
211 | } else { | |
212 |
1
1. setDynamicAdjustment : removed call to javax/swing/JTable::removePropertyChangeListener → NO_COVERAGE |
this.tableAdjust.removePropertyChangeListener(this); |
213 |
1
1. setDynamicAdjustment : removed call to javax/swing/table/TableModel::removeTableModelListener → NO_COVERAGE |
this.tableAdjust.getModel().removeTableModelListener(this); |
214 | } | |
215 | } | |
216 | this.isDynamicAdjustment = isDynamicAdjustment; | |
217 | } | |
218 | | |
219 | /** | |
220 | * Implement the PropertyChangeListener | |
221 | */ | |
222 | @Override | |
223 | public void propertyChange(PropertyChangeEvent e) { | |
224 | // When the TableModel changes we need to update the listeners | |
225 | // and column widths | |
226 |
1
1. propertyChange : negated conditional → NO_COVERAGE |
if ("model".equals(e.getPropertyName())) { |
227 | TableModel model = (TableModel) e.getOldValue(); | |
228 |
1
1. propertyChange : removed call to javax/swing/table/TableModel::removeTableModelListener → NO_COVERAGE |
model.removeTableModelListener(this); |
229 | ||
230 | model = (TableModel) e.getNewValue(); | |
231 |
1
1. propertyChange : removed call to javax/swing/table/TableModel::addTableModelListener → NO_COVERAGE |
model.addTableModelListener(this); |
232 |
1
1. propertyChange : removed call to com/jsql/view/swing/table/AdjusterTableColumn::adjustColumns → NO_COVERAGE |
this.adjustColumns(); |
233 | } | |
234 | } | |
235 | | |
236 | /** | |
237 | * Implement the TableModelListener | |
238 | */ | |
239 | @Override | |
240 | public void tableChanged(TableModelEvent e) { | |
241 |
1
1. tableChanged : negated conditional → NO_COVERAGE |
if (!this.isColumnDataIncluded) { |
242 | return; | |
243 | } | |
244 | ||
245 | // A cell has been updated | |
246 |
1
1. tableChanged : negated conditional → NO_COVERAGE |
if (e.getType() == TableModelEvent.UPDATE) { |
247 | int column = this.tableAdjust.convertColumnIndexToView(e.getColumn()); | |
248 | ||
249 | // Only need to worry about an increase in width for this cell | |
250 |
1
1. tableChanged : negated conditional → NO_COVERAGE |
if (this.isOnlyAdjustLarger) { |
251 | int row = e.getFirstRow(); | |
252 | var tableColumn = this.tableAdjust.getColumnModel().getColumn(column); | |
253 |
1
1. tableChanged : negated conditional → NO_COVERAGE |
if (tableColumn.getResizable()) { |
254 | int width = this.getCellDataWidth(row, column); | |
255 |
1
1. tableChanged : removed call to com/jsql/view/swing/table/AdjusterTableColumn::updateTableColumn → NO_COVERAGE |
this.updateTableColumn(column, width); |
256 | } | |
257 | } else { | |
258 |
1
1. tableChanged : removed call to com/jsql/view/swing/table/AdjusterTableColumn::adjustColumn → NO_COVERAGE |
this.adjustColumn(column); // Could be an increase of decrease so check all rows |
259 | } | |
260 | } else { | |
261 |
1
1. tableChanged : removed call to com/jsql/view/swing/table/AdjusterTableColumn::adjustColumns → NO_COVERAGE |
this.adjustColumns(); // The update affected more than one column so adjust all columns |
262 | } | |
263 | } | |
264 | ||
265 | /** | |
266 | * Install Actions to give user control of certain functionality. | |
267 | */ | |
268 | private void installActions() { | |
269 |
1
1. installActions : removed call to com/jsql/view/swing/table/AdjusterTableColumn::installColumnAction → NO_COVERAGE |
this.installColumnAction(true, true, "adjustColumn", "control ADD"); |
270 |
1
1. installActions : removed call to com/jsql/view/swing/table/AdjusterTableColumn::installColumnAction → NO_COVERAGE |
this.installColumnAction(false, true, "adjustColumns", "control shift ADD"); |
271 |
1
1. installActions : removed call to com/jsql/view/swing/table/AdjusterTableColumn::installColumnAction → NO_COVERAGE |
this.installColumnAction(true, false, "restoreColumn", "control SUBTRACT"); |
272 |
1
1. installActions : removed call to com/jsql/view/swing/table/AdjusterTableColumn::installColumnAction → NO_COVERAGE |
this.installColumnAction(false, false, "restoreColumns", "control shift SUBTRACT"); |
273 | ||
274 |
1
1. installActions : removed call to com/jsql/view/swing/table/AdjusterTableColumn::installToggleAction → NO_COVERAGE |
this.installToggleAction(true, false, "toggleDynamic", "control MULTIPLY"); |
275 |
1
1. installActions : removed call to com/jsql/view/swing/table/AdjusterTableColumn::installToggleAction → NO_COVERAGE |
this.installToggleAction(false, true, "toggleLarger", "control DIVIDE"); |
276 | } | |
277 | ||
278 | /** | |
279 | * Update the input and action maps with a new ColumnAction | |
280 | */ | |
281 | private void installColumnAction(boolean isSelectedColumn, boolean isAdjust, String key, String keyStroke) { | |
282 | Action action = new ColumnAction(isSelectedColumn, isAdjust); | |
283 | var ks = KeyStroke.getKeyStroke(keyStroke); | |
284 | | |
285 |
1
1. installColumnAction : removed call to javax/swing/InputMap::put → NO_COVERAGE |
this.tableAdjust.getInputMap().put(ks, key); |
286 |
1
1. installColumnAction : removed call to javax/swing/ActionMap::put → NO_COVERAGE |
this.tableAdjust.getActionMap().put(key, action); |
287 | } | |
288 | ||
289 | /** | |
290 | * Update the input and action maps with new ToggleAction | |
291 | */ | |
292 | private void installToggleAction(boolean isToggleDynamic, boolean isToggleLarger, String key, String keyStroke) { | |
293 | Action action = new ToggleAction(isToggleDynamic, isToggleLarger); | |
294 | var ks = KeyStroke.getKeyStroke(keyStroke); | |
295 | | |
296 |
1
1. installToggleAction : removed call to javax/swing/InputMap::put → NO_COVERAGE |
this.tableAdjust.getInputMap().put(ks, key); |
297 |
1
1. installToggleAction : removed call to javax/swing/ActionMap::put → NO_COVERAGE |
this.tableAdjust.getActionMap().put(key, action); |
298 | } | |
299 | ||
300 | /** | |
301 | * Action to adjust or restore the width of a single column or all columns | |
302 | */ | |
303 | class ColumnAction extends AbstractAction { | |
304 | | |
305 | private final boolean isSelectedColumn; | |
306 | private final boolean isAdjust; | |
307 | ||
308 | public ColumnAction(boolean isSelectedColumn, boolean isAdjust) { | |
309 | this.isSelectedColumn = isSelectedColumn; | |
310 | this.isAdjust = isAdjust; | |
311 | } | |
312 | ||
313 | @Override | |
314 | public void actionPerformed(ActionEvent e) { | |
315 | // Handle selected column(s) width change actions | |
316 |
1
1. actionPerformed : negated conditional → NO_COVERAGE |
if (this.isSelectedColumn) { |
317 | int[] columns = AdjusterTableColumn.this.tableAdjust.getSelectedColumns(); | |
318 | ||
319 | for (int column: columns) { | |
320 |
1
1. actionPerformed : negated conditional → NO_COVERAGE |
if (this.isAdjust) { |
321 |
1
1. actionPerformed : removed call to com/jsql/view/swing/table/AdjusterTableColumn::adjustColumn → NO_COVERAGE |
AdjusterTableColumn.this.adjustColumn(column); |
322 | } else { | |
323 |
1
1. actionPerformed : removed call to com/jsql/view/swing/table/AdjusterTableColumn::restoreColumn → NO_COVERAGE |
AdjusterTableColumn.this.restoreColumn(column); |
324 | } | |
325 | } | |
326 | } else { | |
327 |
1
1. actionPerformed : negated conditional → NO_COVERAGE |
if (this.isAdjust) { |
328 |
1
1. actionPerformed : removed call to com/jsql/view/swing/table/AdjusterTableColumn::adjustColumns → NO_COVERAGE |
AdjusterTableColumn.this.adjustColumns(); |
329 | } else { | |
330 |
1
1. actionPerformed : removed call to com/jsql/view/swing/table/AdjusterTableColumn::restoreColumns → NO_COVERAGE |
AdjusterTableColumn.this.restoreColumns(); |
331 | } | |
332 | } | |
333 | } | |
334 | } | |
335 | ||
336 | /** | |
337 | * Toggle properties of the TableColumnAdjuster so the user can | |
338 | * customize the functionality to their preferences | |
339 | */ | |
340 | class ToggleAction extends AbstractAction { | |
341 | | |
342 | private final boolean isToggleDynamic; | |
343 | private final boolean isToggleLarger; | |
344 | ||
345 | public ToggleAction(boolean isToggleDynamic, boolean isToggleLarger) { | |
346 | this.isToggleDynamic = isToggleDynamic; | |
347 | this.isToggleLarger = isToggleLarger; | |
348 | } | |
349 | ||
350 | @Override | |
351 | public void actionPerformed(ActionEvent e) { | |
352 |
1
1. actionPerformed : negated conditional → NO_COVERAGE |
if (this.isToggleDynamic) { |
353 |
2
1. actionPerformed : removed call to com/jsql/view/swing/table/AdjusterTableColumn::setDynamicAdjustment → NO_COVERAGE 2. actionPerformed : negated conditional → NO_COVERAGE |
AdjusterTableColumn.this.setDynamicAdjustment(!AdjusterTableColumn.this.isDynamicAdjustment); |
354 |
1
1. actionPerformed : negated conditional → NO_COVERAGE |
} else if (this.isToggleLarger) { |
355 |
2
1. actionPerformed : negated conditional → NO_COVERAGE 2. actionPerformed : removed call to com/jsql/view/swing/table/AdjusterTableColumn::setOnlyAdjustLarger → NO_COVERAGE |
AdjusterTableColumn.this.setOnlyAdjustLarger(!AdjusterTableColumn.this.isOnlyAdjustLarger); |
356 | } | |
357 | } | |
358 | } | |
359 | } | |
Mutations | ||
54 |
1.1 |
|
55 |
1.1 |
|
56 |
1.1 |
|
57 |
1.1 |
|
58 |
1.1 |
|
66 |
1.1 2.2 |
|
67 |
1.1 |
|
76 |
1.1 |
|
83 |
1.1 |
|
90 |
1.1 |
|
97 |
1.1 |
|
102 |
1.1 |
|
110 |
1.1 |
|
117 |
1.1 2.2 |
|
120 |
1.1 2.2 |
|
124 |
1.1 |
|
134 |
1.1 2.2 |
|
142 |
1.1 |
|
147 |
1.1 |
|
149 |
1.1 |
|
154 |
1.1 |
|
155 |
1.1 |
|
163 |
1.1 2.2 |
|
164 |
1.1 |
|
174 |
1.1 |
|
175 |
1.1 |
|
176 |
1.1 |
|
207 |
1.1 |
|
208 |
1.1 |
|
209 |
1.1 |
|
210 |
1.1 |
|
212 |
1.1 |
|
213 |
1.1 |
|
226 |
1.1 |
|
228 |
1.1 |
|
231 |
1.1 |
|
232 |
1.1 |
|
241 |
1.1 |
|
246 |
1.1 |
|
250 |
1.1 |
|
253 |
1.1 |
|
255 |
1.1 |
|
258 |
1.1 |
|
261 |
1.1 |
|
269 |
1.1 |
|
270 |
1.1 |
|
271 |
1.1 |
|
272 |
1.1 |
|
274 |
1.1 |
|
275 |
1.1 |
|
285 |
1.1 |
|
286 |
1.1 |
|
296 |
1.1 |
|
297 |
1.1 |
|
316 |
1.1 |
|
320 |
1.1 |
|
321 |
1.1 |
|
323 |
1.1 |
|
327 |
1.1 |
|
328 |
1.1 |
|
330 |
1.1 |
|
352 |
1.1 |
|
353 |
1.1 2.2 |
|
354 |
1.1 |
|
355 |
1.1 2.2 |