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

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

AEI2 0.99k:

  • Added mod string filter
  • Made jump-to-mod by key-press cycle through mods if pressed multiple times
File size: 13.5 KB
RevLine 
[631]1package net.oni2.aeinstaller.gui.modtable;
2
3import java.awt.Desktop;
[639]4import java.awt.Rectangle;
[631]5import java.awt.event.ActionEvent;
6import java.awt.event.ActionListener;
[639]7import java.awt.event.KeyAdapter;
8import java.awt.event.KeyEvent;
[631]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;
[659]18import java.util.Vector;
[631]19
[659]20import javax.swing.JCheckBoxMenuItem;
[631]21import javax.swing.JComponent;
22import javax.swing.JMenuItem;
[657]23import javax.swing.JOptionPane;
[631]24import javax.swing.JPopupMenu;
25import javax.swing.JTable;
[639]26import javax.swing.JViewport;
[631]27import javax.swing.ListSelectionModel;
28import javax.swing.RowSorter;
29import javax.swing.SortOrder;
30import javax.swing.event.ListSelectionEvent;
[645]31import javax.swing.event.RowSorterEvent;
[659]32import javax.swing.table.JTableHeader;
33import javax.swing.table.TableColumn;
34import javax.swing.table.TableColumnModel;
[631]35import javax.swing.table.TableRowSorter;
36
[645]37import net.oni2.aeinstaller.backend.Settings;
[648]38import net.oni2.aeinstaller.backend.packages.Package;
39import net.oni2.aeinstaller.backend.packages.Type;
[631]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
[657]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
[631]68 private HashSet<ModSelectionListener> modSelListeners = new HashSet<ModSelectionListener>();
69
70 private ModTableModel model;
71 private TableRowSorter<ModTableModel> sorter;
72
[657]73 private ETableContentType contentType = ETableContentType.MODS;
74
[631]75 /**
76 * Create a new ModTable
[658]77 *
78 * @param contentType
79 * Content to show
[631]80 */
[658]81 public ModTable(ETableContentType contentType) {
[631]82 super();
83
[658]84 this.contentType = contentType;
85
[631]86 setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
[639]87 getSelectionModel().addListSelectionListener(this);
88 addMouseListener(new MouseEventHandler());
89 addKeyListener(new KeyEventHandler());
[631]90 // To get checkbox-cells with background of row
91 ((JComponent) getDefaultRenderer(Boolean.class)).setOpaque(true);
92
[658]93 model = new ModTableModel(contentType);
[631]94
95 setModel(model);
96
97 sorter = new TableRowSorter<ModTableModel>(model);
98 setRowSorter(sorter);
99
[660]100 setFilter(null, 0, null, EApplyFilterTo.ALL);
[631]101
102 List<RowSorter.SortKey> sortKeys = new ArrayList<RowSorter.SortKey>();
[645]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));
[631]109 sorter.setSortKeys(sortKeys);
110
111 for (int i = 0; i < model.getColumnCount(); i++) {
112 model.setColumnConstraints(i, getColumnModel().getColumn(i));
113 }
[658]114
[659]115 getTableHeader().addMouseListener(new HeaderMouseEventHandler());
116
[658]117 if (contentType != ETableContentType.MODS) {
118 getColumnModel().removeColumn(getColumnModel().getColumn(0));
119 }
[631]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) {
[648]129 final Package mod = (Package) getValueAt(r, -1);
[631]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
[648]165 private void notifyModSelectionListeners(Package m) {
[631]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 */
[648]214 public TreeSet<Package> getSelectedMods() {
[631]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
[660]223 * @param filterString
224 * String to filter on
225 * @param filterTo
226 * Fields to use string filter on
[631]227 */
[660]228 public void setFilter(Type type, int downloadState, String filterString,
229 EApplyFilterTo filterTo) {
[657]230 sorter.setRowFilter(new ModTableFilter(type, downloadState,
[660]231 filterString, filterTo, contentType == ETableContentType.CORE,
232 false));
[631]233 }
[639]234
235 @Override
[645]236 public void sorterChanged(RowSorterEvent evt) {
237 super.sorterChanged(evt);
238 if (evt.getType() == RowSorterEvent.Type.SORT_ORDER_CHANGED) {
239 @SuppressWarnings("unchecked")
240 RowSorter<ModTableModel> rs = (RowSorter<ModTableModel>) getRowSorter();
241 List<? extends RowSorter.SortKey> keys = rs.getSortKeys();
242 if (keys.size() > 0) {
243 int col = keys.get(0).getColumn();
244 SortOrder so = keys.get(0).getSortOrder();
245 Settings.getInstance().put("modSortColumn", col);
246 Settings.getInstance().put("modSortOrder", so.toString());
247 }
248 }
249 }
250
[657]251 /**
252 * Select/Unselect all currently visible items depending on the current
253 * state of selection
254 */
255 public void unSelectAll() {
256 boolean isAll = true;
257 for (int i = 0; i < getRowCount(); i++) {
258 int modRow = convertRowIndexToModel(i);
259 boolean inst = (Boolean) model.getValueAt(modRow, 0);
260 if (!inst) {
261 isAll = false;
262 break;
263 }
264 }
265
266 for (int i = 0; i < getRowCount(); i++) {
267 int modRow = convertRowIndexToModel(i);
268 model.setValueAt(!isAll, modRow, 0);
269 }
270 invalidate();
271 repaint();
272 }
273
[645]274 @Override
[639]275 public void valueChanged(ListSelectionEvent e) {
276 super.valueChanged(e);
277 int viewRow = getSelectedRow();
278 if (viewRow < 0) {
279 notifyModSelectionListeners(null);
280 } else {
[648]281 Package mod = (Package) getValueAt(viewRow, -1);
[639]282 notifyModSelectionListeners(mod);
283 }
284 }
285
286 private class MouseEventHandler extends MouseAdapter {
287 private void mouseEventProcessing(MouseEvent e) {
288 int r = rowAtPoint(e.getPoint());
289 if (r >= 0 && r < getRowCount())
290 setRowSelectionInterval(r, r);
291 else
292 clearSelection();
293
294 int rowindex = getSelectedRow();
295 if (rowindex >= 0) {
296 if (e.isPopupTrigger() && e.getComponent() instanceof JTable) {
[648]297 final Package mod = (Package) getValueAt(rowindex, -1);
[639]298
299 JPopupMenu popup = new JPopupMenu();
300
301 if (mod.isLocalAvailable()) {
302 // Open package folder item
303 JMenuItem openModFolder = new JMenuItem(
304 bundle.getString("openModFolder.text"));
305 openModFolder.addActionListener(new ActionListener() {
306 @Override
307 public void actionPerformed(ActionEvent arg0) {
308 try {
309 Desktop.getDesktop().open(
310 mod.getLocalPath());
311 } catch (IOException e) {
312 e.printStackTrace();
313 }
314 }
315 });
316 popup.add(openModFolder);
317 }
318
319 if (mod.getUrl() != null) {
320 // Open Depot page item
321 JMenuItem openDepotPage = new JMenuItem(
322 bundle.getString("openDepotPage.text"));
323 openDepotPage.addActionListener(new ActionListener() {
324 @Override
325 public void actionPerformed(ActionEvent arg0) {
326 try {
327 Desktop.getDesktop().browse(mod.getUrl());
328 } catch (IOException e) {
329 e.printStackTrace();
330 }
331 }
332 });
333 popup.add(openDepotPage);
334 }
335
[657]336 if (mod.isLocalAvailable()
337 && contentType != ETableContentType.CORE) {
338 // Delete package folder item
339 JMenuItem deleteModFolder = new JMenuItem(
340 bundle.getString("deletePackage.text"));
341 deleteModFolder.addActionListener(new ActionListener() {
342 @Override
343 public void actionPerformed(ActionEvent arg0) {
344 if (mod.getNode() == null) {
345 JOptionPane.showMessageDialog(
346 null,
347 bundle.getString("deletePackageLocalOnly.text"),
348 bundle.getString("deletePackageLocalOnly.title"),
349 JOptionPane.INFORMATION_MESSAGE);
350 } else {
351 int res = JOptionPane.showConfirmDialog(
352 null,
353 bundle.getString("deletePackageConfirm.text"),
354 bundle.getString("deletePackageConfirm.title"),
355 JOptionPane.YES_NO_OPTION,
356 JOptionPane.WARNING_MESSAGE);
357 if (res == JOptionPane.YES_OPTION) {
358 mod.deleteLocalPackage();
359 invalidate();
360 repaint();
361 }
362 }
363 }
364 });
365 popup.add(deleteModFolder);
366 }
367
[639]368 if (popup.getSubElements().length > 0)
369 popup.show(e.getComponent(), e.getX(), e.getY());
370 }
371 }
372 }
373
374 @Override
375 public void mousePressed(MouseEvent e) {
376 mouseEventProcessing(e);
377 }
378
379 @Override
380 public void mouseReleased(MouseEvent e) {
381 mouseEventProcessing(e);
382 }
383 }
384
385 private class KeyEventHandler extends KeyAdapter {
[660]386 private void goToRow(int row) {
387 setRowSelectionInterval(row, row);
388 JViewport viewport = (JViewport) getParent();
389 Rectangle rect = getCellRect(row, 0, true);
390 Rectangle r2 = viewport.getVisibleRect();
391 scrollRectToVisible(new Rectangle(rect.x, rect.y,
392 (int) r2.getWidth(), (int) r2.getHeight()));
393 }
394
[639]395 @Override
396 public void keyTyped(KeyEvent e) {
397 super.keyTyped(e);
398
399 if (e.getModifiers() == 0) {
400 String key = String.valueOf(e.getKeyChar()).toLowerCase();
[660]401 int row = getSelectedRow();
402 if (row == (getRowCount() - 1))
403 row = -1;
404 for (int i = row + 1; i < getRowCount(); i++) {
[648]405 Package m = (Package) getValueAt(i, -1);
[639]406 if (m.getName().toLowerCase().startsWith(key)) {
[660]407 goToRow(i);
408 return;
[639]409 }
410 }
[660]411 if (row > 0) {
412 for (int i = 0; i < row; i++) {
413 Package m = (Package) getValueAt(i, -1);
414 if (m.getName().toLowerCase().startsWith(key)) {
415 goToRow(i);
416 return;
417 }
418 }
419 }
[639]420 }
421 }
422 }
[659]423
424 private class HeaderMouseEventHandler extends MouseAdapter {
425 private Vector<TableColumn> columns = new Vector<TableColumn>();
426 private TableColumnModel tcm = getColumnModel();
427
428 public HeaderMouseEventHandler() {
429 super();
430
431 for (int i = 1; i < tcm.getColumnCount(); i++) {
432 columns.add(tcm.getColumn(i));
433 }
434
435 for (int i = 1; i < columns.size(); i++) {
436 TableColumn tc = columns.get(i);
437 if (!Settings.getInstance().get(
438 String.format("modShowColumn%02d", tc.getModelIndex()),
439 true))
440 tcm.removeColumn(tc);
441 }
442 }
443
444 private TableColumn getColumn(String name) {
445 for (TableColumn tc : columns) {
446 if (tc.getHeaderValue().equals(name)) {
447 return tc;
448 }
449 }
450 return null;
451 }
452
453 private int headerContains(TableColumn tc) {
454 for (int col = 0; col < tcm.getColumnCount(); col++) {
455 if (tcm.getColumn(col).equals(tc))
456 return col;
457 }
458 return -1;
459 }
460
461 private void mouseEventProcessing(MouseEvent e) {
462 if (e.isPopupTrigger() && e.getComponent() instanceof JTableHeader) {
463 JPopupMenu popup = new JPopupMenu();
464
465 ActionListener al = new ActionListener() {
466 @Override
467 public void actionPerformed(ActionEvent e) {
468 JCheckBoxMenuItem itm = (JCheckBoxMenuItem) e
469 .getSource();
470 TableColumn col = getColumn(itm.getText());
471 if (itm.isSelected()) {
472 tcm.addColumn(col);
473 for (int i = columns.indexOf(col) - 1; i >= 0; i--) {
474 int pos = headerContains(columns.get(i));
475 if (pos >= 0) {
476 tcm.moveColumn(tcm.getColumnCount() - 1,
477 pos + 1);
478 break;
479 }
480 }
481 } else {
482 tcm.removeColumn(col);
483 }
484 Settings.getInstance().put(
485 String.format("modShowColumn%02d",
486 col.getModelIndex()), itm.isSelected());
487 }
488 };
489
490 for (int i = 1; i < columns.size(); i++) {
491 JCheckBoxMenuItem itm = new JCheckBoxMenuItem(
492 (String) columns.get(i).getHeaderValue());
493 itm.setSelected(headerContains(columns.get(i)) >= 0);
494
495 itm.addActionListener(al);
496 popup.add(itm);
497 }
498
499 if (popup.getSubElements().length > 0)
500 popup.show(e.getComponent(), e.getX(), e.getY());
501 }
502 }
503
504 @Override
505 public void mousePressed(MouseEvent e) {
506 mouseEventProcessing(e);
507 }
508
509 @Override
510 public void mouseReleased(MouseEvent e) {
511 mouseEventProcessing(e);
512 }
513 }
514
[631]515}
Note: See TracBrowser for help on using the repository browser.