source: AE/installer2/src/net/oni2/aeinstaller/gui/modtable/ModTable.java@ 659

Last change on this file since 659 was 659, checked in by alloc, 12 years ago

AEI2 0.99j:

  • Added table column hiding
File size: 12.9 KB
Line 
1package net.oni2.aeinstaller.gui.modtable;
2
3import java.awt.Desktop;
4import java.awt.Rectangle;
5import java.awt.event.ActionEvent;
6import java.awt.event.ActionListener;
7import java.awt.event.KeyAdapter;
8import java.awt.event.KeyEvent;
9import java.awt.event.MouseAdapter;
10import java.awt.event.MouseEvent;
11import java.io.File;
12import java.io.IOException;
13import java.util.ArrayList;
14import java.util.HashSet;
15import java.util.List;
16import java.util.ResourceBundle;
17import java.util.TreeSet;
18import java.util.Vector;
19
20import javax.swing.JCheckBoxMenuItem;
21import javax.swing.JComponent;
22import javax.swing.JMenuItem;
23import javax.swing.JOptionPane;
24import javax.swing.JPopupMenu;
25import javax.swing.JTable;
26import javax.swing.JViewport;
27import javax.swing.ListSelectionModel;
28import javax.swing.RowSorter;
29import javax.swing.SortOrder;
30import javax.swing.event.ListSelectionEvent;
31import javax.swing.event.RowSorterEvent;
32import javax.swing.table.JTableHeader;
33import javax.swing.table.TableColumn;
34import javax.swing.table.TableColumnModel;
35import javax.swing.table.TableRowSorter;
36
37import net.oni2.aeinstaller.backend.Settings;
38import net.oni2.aeinstaller.backend.packages.Package;
39import net.oni2.aeinstaller.backend.packages.Type;
40
41/**
42 * @author Christian Illy
43 */
44public class ModTable extends JTable {
45 private static final long serialVersionUID = 1L;
46
47 private ResourceBundle bundle = ResourceBundle
48 .getBundle("net.oni2.aeinstaller.localization.ModTable");
49
50 /**
51 * @author Christian Illy
52 */
53 public enum ETableContentType {
54 /**
55 * Table showing mods
56 */
57 MODS,
58 /**
59 * Table showing tools
60 */
61 TOOLS,
62 /**
63 * Table showing core packages
64 */
65 CORE
66 };
67
68 private HashSet<ModSelectionListener> modSelListeners = new HashSet<ModSelectionListener>();
69
70 private ModTableModel model;
71 private TableRowSorter<ModTableModel> sorter;
72
73 private ETableContentType contentType = ETableContentType.MODS;
74
75 /**
76 * Create a new ModTable
77 *
78 * @param contentType
79 * Content to show
80 */
81 public ModTable(ETableContentType contentType) {
82 super();
83
84 this.contentType = contentType;
85
86 setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
87 getSelectionModel().addListSelectionListener(this);
88 addMouseListener(new MouseEventHandler());
89 addKeyListener(new KeyEventHandler());
90 // To get checkbox-cells with background of row
91 ((JComponent) getDefaultRenderer(Boolean.class)).setOpaque(true);
92
93 model = new ModTableModel(contentType);
94
95 setModel(model);
96
97 sorter = new TableRowSorter<ModTableModel>(model);
98 setRowSorter(sorter);
99
100 setFilter(null, 0);
101
102 List<RowSorter.SortKey> sortKeys = new ArrayList<RowSorter.SortKey>();
103
104 int sortCol = Settings.getInstance().get("modSortColumn", 1);
105 SortOrder sortOrder = SortOrder.valueOf(Settings.getInstance().get(
106 "modSortOrder", "ASCENDING"));
107
108 sortKeys.add(new RowSorter.SortKey(sortCol, sortOrder));
109 sorter.setSortKeys(sortKeys);
110
111 for (int i = 0; i < model.getColumnCount(); i++) {
112 model.setColumnConstraints(i, getColumnModel().getColumn(i));
113 }
114
115 getTableHeader().addMouseListener(new HeaderMouseEventHandler());
116
117 if (contentType != ETableContentType.MODS) {
118 getColumnModel().removeColumn(getColumnModel().getColumn(0));
119 }
120 }
121
122 @Override
123 public String getToolTipText(MouseEvent e) {
124 int r = rowAtPoint(e.getPoint());
125 int c = columnAtPoint(e.getPoint());
126 if (r >= 0 && r < getRowCount()) {
127 int modelCol = convertColumnIndexToModel(c);
128 if (modelCol == 4) {
129 final Package mod = (Package) getValueAt(r, -1);
130
131 String tt = "<html>";
132 tt += String.format("%s: %s<br>",
133 bundle.getString("state.installed"),
134 bundle.getString((mod.isInstalled() ? "yes" : "no")));
135 tt += String.format(
136 "%s: %s<br>",
137 bundle.getString("state.updatable"),
138 bundle.getString((mod.isLocalAvailable()
139 && mod.isNewerAvailable() ? "yes" : "no")));
140 tt += String.format("%s: %s</html>", bundle
141 .getString("state.downloaded"), bundle.getString((mod
142 .isLocalAvailable() ? "yes" : "no")));
143 return tt;
144 }
145 }
146 return super.getToolTipText(e);
147 }
148
149 /**
150 * @param listener
151 * Listener to add
152 */
153 public void addModSelectionListener(ModSelectionListener listener) {
154 modSelListeners.add(listener);
155 }
156
157 /**
158 * @param listener
159 * Listener to remove
160 */
161 public void removeModSelectionListener(ModSelectionListener listener) {
162 modSelListeners.remove(listener);
163 }
164
165 private void notifyModSelectionListeners(Package m) {
166 for (ModSelectionListener l : modSelListeners) {
167 l.modSelectionChanged(this, m);
168 }
169 }
170
171 /**
172 * @param listener
173 * Listener to add
174 */
175 public void addDownloadSizeListener(DownloadSizeListener listener) {
176 model.addDownloadSizeListener(listener);
177 }
178
179 /**
180 * @param listener
181 * Listener to remove
182 */
183 public void removeDownloadSizeListener(DownloadSizeListener listener) {
184 model.removeDownloadSizeListener(listener);
185 }
186
187 /**
188 * Reload the nodes data after an update to the cache
189 */
190 public void reloadData() {
191 model.reloadData();
192 }
193
194 /**
195 * Revert the selection to the mods that are currently installed
196 */
197 public void revertSelection() {
198 model.revertSelection();
199 }
200
201 /**
202 * Reload the selection after a config was loaded
203 *
204 * @param config
205 * Config to load
206 */
207 public void reloadSelection(File config) {
208 model.reloadSelection(config);
209 }
210
211 /**
212 * @return Mods selected for installation
213 */
214 public TreeSet<Package> getSelectedMods() {
215 return model.getSelectedMods();
216 }
217
218 /**
219 * @param type
220 * Type of mods to show (null for all)
221 * @param downloadState
222 * Show only: 0 = all, 1 = online, 2 = downloaded
223 */
224 public void setFilter(Type type, int downloadState) {
225 sorter.setRowFilter(new ModTableFilter(type, downloadState,
226 contentType == ETableContentType.CORE, false));
227 }
228
229 @Override
230 public void sorterChanged(RowSorterEvent evt) {
231 super.sorterChanged(evt);
232 if (evt.getType() == RowSorterEvent.Type.SORT_ORDER_CHANGED) {
233 @SuppressWarnings("unchecked")
234 RowSorter<ModTableModel> rs = (RowSorter<ModTableModel>) getRowSorter();
235 List<? extends RowSorter.SortKey> keys = rs.getSortKeys();
236 if (keys.size() > 0) {
237 int col = keys.get(0).getColumn();
238 SortOrder so = keys.get(0).getSortOrder();
239 Settings.getInstance().put("modSortColumn", col);
240 Settings.getInstance().put("modSortOrder", so.toString());
241 }
242 }
243 }
244
245 /**
246 * Select/Unselect all currently visible items depending on the current
247 * state of selection
248 */
249 public void unSelectAll() {
250 boolean isAll = true;
251 for (int i = 0; i < getRowCount(); i++) {
252 int modRow = convertRowIndexToModel(i);
253 boolean inst = (Boolean) model.getValueAt(modRow, 0);
254 if (!inst) {
255 isAll = false;
256 break;
257 }
258 }
259
260 for (int i = 0; i < getRowCount(); i++) {
261 int modRow = convertRowIndexToModel(i);
262 model.setValueAt(!isAll, modRow, 0);
263 }
264 invalidate();
265 repaint();
266 }
267
268 @Override
269 public void valueChanged(ListSelectionEvent e) {
270 super.valueChanged(e);
271 int viewRow = getSelectedRow();
272 if (viewRow < 0) {
273 notifyModSelectionListeners(null);
274 } else {
275 Package mod = (Package) getValueAt(viewRow, -1);
276 notifyModSelectionListeners(mod);
277 }
278 }
279
280 private class MouseEventHandler extends MouseAdapter {
281 private void mouseEventProcessing(MouseEvent e) {
282 int r = rowAtPoint(e.getPoint());
283 if (r >= 0 && r < getRowCount())
284 setRowSelectionInterval(r, r);
285 else
286 clearSelection();
287
288 int rowindex = getSelectedRow();
289 if (rowindex >= 0) {
290 if (e.isPopupTrigger() && e.getComponent() instanceof JTable) {
291 final Package mod = (Package) getValueAt(rowindex, -1);
292
293 JPopupMenu popup = new JPopupMenu();
294
295 if (mod.isLocalAvailable()) {
296 // Open package folder item
297 JMenuItem openModFolder = new JMenuItem(
298 bundle.getString("openModFolder.text"));
299 openModFolder.addActionListener(new ActionListener() {
300 @Override
301 public void actionPerformed(ActionEvent arg0) {
302 try {
303 Desktop.getDesktop().open(
304 mod.getLocalPath());
305 } catch (IOException e) {
306 e.printStackTrace();
307 }
308 }
309 });
310 popup.add(openModFolder);
311 }
312
313 if (mod.getUrl() != null) {
314 // Open Depot page item
315 JMenuItem openDepotPage = new JMenuItem(
316 bundle.getString("openDepotPage.text"));
317 openDepotPage.addActionListener(new ActionListener() {
318 @Override
319 public void actionPerformed(ActionEvent arg0) {
320 try {
321 Desktop.getDesktop().browse(mod.getUrl());
322 } catch (IOException e) {
323 e.printStackTrace();
324 }
325 }
326 });
327 popup.add(openDepotPage);
328 }
329
330 if (mod.isLocalAvailable()
331 && contentType != ETableContentType.CORE) {
332 // Delete package folder item
333 JMenuItem deleteModFolder = new JMenuItem(
334 bundle.getString("deletePackage.text"));
335 deleteModFolder.addActionListener(new ActionListener() {
336 @Override
337 public void actionPerformed(ActionEvent arg0) {
338 if (mod.getNode() == null) {
339 JOptionPane.showMessageDialog(
340 null,
341 bundle.getString("deletePackageLocalOnly.text"),
342 bundle.getString("deletePackageLocalOnly.title"),
343 JOptionPane.INFORMATION_MESSAGE);
344 } else {
345 int res = JOptionPane.showConfirmDialog(
346 null,
347 bundle.getString("deletePackageConfirm.text"),
348 bundle.getString("deletePackageConfirm.title"),
349 JOptionPane.YES_NO_OPTION,
350 JOptionPane.WARNING_MESSAGE);
351 if (res == JOptionPane.YES_OPTION) {
352 mod.deleteLocalPackage();
353 invalidate();
354 repaint();
355 }
356 }
357 }
358 });
359 popup.add(deleteModFolder);
360 }
361
362 if (popup.getSubElements().length > 0)
363 popup.show(e.getComponent(), e.getX(), e.getY());
364 }
365 }
366 }
367
368 @Override
369 public void mousePressed(MouseEvent e) {
370 mouseEventProcessing(e);
371 }
372
373 @Override
374 public void mouseReleased(MouseEvent e) {
375 mouseEventProcessing(e);
376 }
377 }
378
379 private class KeyEventHandler extends KeyAdapter {
380 @Override
381 public void keyTyped(KeyEvent e) {
382 super.keyTyped(e);
383
384 if (e.getModifiers() == 0) {
385 String key = String.valueOf(e.getKeyChar()).toLowerCase();
386 for (int i = 0; i < getRowCount(); i++) {
387 Package m = (Package) getValueAt(i, -1);
388 if (m.getName().toLowerCase().startsWith(key)) {
389 setRowSelectionInterval(i, i);
390 JViewport viewport = (JViewport) getParent();
391 Rectangle rect = getCellRect(i, 0, true);
392 Rectangle r2 = viewport.getVisibleRect();
393 scrollRectToVisible(new Rectangle(rect.x, rect.y,
394 (int) r2.getWidth(), (int) r2.getHeight()));
395 break;
396 }
397 }
398 }
399 }
400 }
401
402 private class HeaderMouseEventHandler extends MouseAdapter {
403 private Vector<TableColumn> columns = new Vector<TableColumn>();
404 private TableColumnModel tcm = getColumnModel();
405
406 public HeaderMouseEventHandler() {
407 super();
408
409 for (int i = 1; i < tcm.getColumnCount(); i++) {
410 columns.add(tcm.getColumn(i));
411 }
412
413 for (int i = 1; i < columns.size(); i++) {
414 TableColumn tc = columns.get(i);
415 if (!Settings.getInstance().get(
416 String.format("modShowColumn%02d", tc.getModelIndex()),
417 true))
418 tcm.removeColumn(tc);
419 }
420 }
421
422 private TableColumn getColumn(String name) {
423 for (TableColumn tc : columns) {
424 if (tc.getHeaderValue().equals(name)) {
425 return tc;
426 }
427 }
428 return null;
429 }
430
431 private int headerContains(TableColumn tc) {
432 for (int col = 0; col < tcm.getColumnCount(); col++) {
433 if (tcm.getColumn(col).equals(tc))
434 return col;
435 }
436 return -1;
437 }
438
439 private void mouseEventProcessing(MouseEvent e) {
440 if (e.isPopupTrigger() && e.getComponent() instanceof JTableHeader) {
441 JPopupMenu popup = new JPopupMenu();
442
443 ActionListener al = new ActionListener() {
444 @Override
445 public void actionPerformed(ActionEvent e) {
446 JCheckBoxMenuItem itm = (JCheckBoxMenuItem) e
447 .getSource();
448 TableColumn col = getColumn(itm.getText());
449 if (itm.isSelected()) {
450 tcm.addColumn(col);
451 for (int i = columns.indexOf(col) - 1; i >= 0; i--) {
452 int pos = headerContains(columns.get(i));
453 if (pos >= 0) {
454 tcm.moveColumn(tcm.getColumnCount() - 1,
455 pos + 1);
456 break;
457 }
458 }
459 } else {
460 tcm.removeColumn(col);
461 }
462 Settings.getInstance().put(
463 String.format("modShowColumn%02d",
464 col.getModelIndex()), itm.isSelected());
465 }
466 };
467
468 for (int i = 1; i < columns.size(); i++) {
469 JCheckBoxMenuItem itm = new JCheckBoxMenuItem(
470 (String) columns.get(i).getHeaderValue());
471 itm.setSelected(headerContains(columns.get(i)) >= 0);
472
473 itm.addActionListener(al);
474 popup.add(itm);
475 }
476
477 if (popup.getSubElements().length > 0)
478 popup.show(e.getComponent(), e.getX(), e.getY());
479 }
480 }
481
482 @Override
483 public void mousePressed(MouseEvent e) {
484 mouseEventProcessing(e);
485 }
486
487 @Override
488 public void mouseReleased(MouseEvent e) {
489 mouseEventProcessing(e);
490 }
491 }
492
493}
Note: See TracBrowser for help on using the repository browser.