diff options
author | Jacob Wisor <[email protected]> | 2013-10-03 14:54:25 +0200 |
---|---|---|
committer | Jacob Wisor <[email protected]> | 2013-10-03 14:54:25 +0200 |
commit | dc15299324a96ae6bb5cf601ec35ec340290fef0 (patch) | |
tree | 9f89eb36181e8d09ff254e7d20679881573fc06c | |
parent | cfae43ca6f649bfc6427b0132a9068ef6ded4e74 (diff) |
* Cache viewer update:
- Can be closed by ESC key
- Enabling and disabling of operational buttons is handled properly
- Time consuming operations are indicated by a mouse busy cursor
- "Size" and "Last Modified" columns display localized data
* netx/net/sourceforge/jnlp/controlpanel/CachePane.java:
Moved JButtons to members.
(addComponents): Modified to make use of new NonEditableTableModel.
Added ListSelectionListener to propertly handle enabling and disabling of
operational JButtons when selecting a resource from the cache table.
Moved inital populating of the cache table to CacheViewer's constructor
until after the CachePane has been instatiated.
Added a general purpose Comparator for all non-String columns in the table
model.
Added a TableCellRenderer with proper localized rendering of "Size" and
"Last Modified" columns as well as the content of "Name" and "Path"
columns.
(createButtonPanel): Moved delete operation into new method
invokeDeleteLater(), added mouse cursor busy indicator, and proper handling
of enabling and disabling of operational JButtons when pushing the delete
button.
Moved refresh operation when pushing the refresh button into new method
invokePopulateLater() and added proper handling of enabling and disabling
of operational JButtons while refreshing.
Replaced closing the cache viewer dialog via JDialog.dispose() when pushing
the delete button by a post of the WindowEvent.WINDOW_CLOSING event to
the CacheViewer dialog in order to effectively remove the newly introduced
KeyEventDispatcher.
(invokeDeleteLater): New method: Posts an event to the event queue deleting
the currently selected resource.
(invokePopulateLater): New method: Posts an event to the event queue
repopulating the cache table.
(populateTable):
Added mouse cursor busy indicator.
(generateData): Modified cache table's per row data model for proper
rendering and sorting to: DirectoryNode, File, String, String, Long, Date.
* netx/net/sourceforge/jnlp/controlpanel/CacheViewer.java:
(CacheViewer): Added null parameter check.
Added a KeyEventDispatcher to enable closing the CacheViewer dialog on a
KeyEvent.VK_ESCAPE key event.
Replaced closing the cache viewer dialog via JDialog.dispose() by a post
of the WindowEvent.WINDOW_CLOSING event to the CacheViewer dialog in order
to effectively remove the newly introduced KeyEventDispatcher.
* netx/net/sourceforge/jnlp/util/ui/NonEditableTableModel.java:
Added a new table model that in effect is a
javax.swing.table.DefaultTableModel except for no cell being editable.
* netx/net/sourceforge/jnlp/util/ui/package-info.java:
Added new package for UI common and recurrung UI tasks with documentation
-rw-r--r-- | ChangeLog | 46 | ||||
-rw-r--r-- | NEWS | 5 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/controlpanel/CachePane.java | 328 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/controlpanel/CacheViewer.java | 39 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/util/ui/NonEditableTableModel.java | 124 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/util/ui/package-info.java | 41 |
6 files changed, 478 insertions, 105 deletions
@@ -1,3 +1,49 @@ +2013-10-03 Jacob Wisor <[email protected]> + + * netx/net/sourceforge/jnlp/controlpanel/CachePane.java: + Moved JButtons to members. + (addComponents): Modified to make use of new NonEditableTableModel. + Added ListSelectionListener to propertly handle enabling and disabling of + operational JButtons when selecting a resource from the cache table. + Moved inital populating of the cache table to CacheViewer's constructor + until after the CachePane has been instatiated. + Added a general purpose Comparator for all non-String columns in the table + model. + Added a TableCellRenderer with proper localized rendering of "Size" and + "Last Modified" columns as well as the content of "Name" and "Path" + columns. + (createButtonPanel): Moved delete operation into new method + invokeDeleteLater(), added mouse cursor busy indicator, and proper handling + of enabling and disabling of operational JButtons when pushing the delete + button. + Moved refresh operation when pushing the refresh button into new method + invokePopulateLater() and added proper handling of enabling and disabling + of operational JButtons while refreshing. + Replaced closing the cache viewer dialog via JDialog.dispose() when pushing + the delete button by a post of the WindowEvent.WINDOW_CLOSING event to + the CacheViewer dialog in order to effectively remove the newly introduced + KeyEventDispatcher. + (invokeDeleteLater): New method: Posts an event to the event queue deleting + the currently selected resource. + (invokePopulateLater): New method: Posts an event to the event queue + repopulating the cache table. + (populateTable): + Added mouse cursor busy indicator. + (generateData): Modified cache table's per row data model for proper + rendering and sorting to: DirectoryNode, File, String, String, Long, Date. + * netx/net/sourceforge/jnlp/controlpanel/CacheViewer.java: + (CacheViewer): Added null parameter check. + Added a KeyEventDispatcher to enable closing the CacheViewer dialog on a + KeyEvent.VK_ESCAPE key event. + Replaced closing the cache viewer dialog via JDialog.dispose() by a post + of the WindowEvent.WINDOW_CLOSING event to the CacheViewer dialog in order + to effectively remove the newly introduced KeyEventDispatcher. + * netx/net/sourceforge/jnlp/util/ui/NonEditableTableModel.java: + Added a new table model that in effect is a + javax.swing.table.DefaultTableModel except for no cell being editable. + * netx/net/sourceforge/jnlp/util/ui/package-info.java: + Added new package for UI common and recurrung UI tasks with documentation + 2013-10-01 Omair Majid <[email protected]> * netx/net/sourceforge/jnlp/browser/BrowserAwareProxySelector.java @@ -12,6 +12,11 @@ New in release 1.5 (2013-XX-XX): * IcedTea-Web now using tagsoup as default (tagsoup dependence) sanitizer for input * JDK older then 1.5 no longer supported * IcedTea-Web is now following XDG .config and .cache specification(RH947647) +* Cache Viewer + - Can be closed by ESC key + - Enabling and disabling of operational buttons is handled properly + - Time consuming operations are indicated by a mouse busy cursor + - "Size" and "Last Modified" columns display localized data * NetX - PR1465 - java.io.FileNotFoundException while trying to download a JAR file - Netx can now parse malformed jnlp files using tagsoup diff --git a/netx/net/sourceforge/jnlp/controlpanel/CachePane.java b/netx/net/sourceforge/jnlp/controlpanel/CachePane.java index 502cf8a..d5bb267 100644 --- a/netx/net/sourceforge/jnlp/controlpanel/CachePane.java +++ b/netx/net/sourceforge/jnlp/controlpanel/CachePane.java @@ -1,5 +1,5 @@ /* CachePane.java -- Displays the specified folder and allows modification to its content. -Copyright (C) 2010 Red Hat +Copyright (C) 2013 Red Hat This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,22 +19,27 @@ package net.sourceforge.jnlp.controlpanel; import java.awt.BorderLayout; import java.awt.Component; +import java.awt.Cursor; import java.awt.Dimension; +import java.awt.EventQueue; import java.awt.FlowLayout; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.GridLayout; +import java.awt.SystemColor; +import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.WindowEvent; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.nio.channels.FileLock; import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; +import java.text.NumberFormat; import java.util.ArrayList; import java.util.Comparator; +import java.util.Date; import java.util.Enumeration; import java.util.List; @@ -45,7 +50,10 @@ import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.ListSelectionModel; -import javax.swing.table.DefaultTableModel; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.TableModel; import javax.swing.table.TableRowSorter; import net.sourceforge.jnlp.cache.CacheDirectory; @@ -54,23 +62,25 @@ import net.sourceforge.jnlp.cache.DirectoryNode; import net.sourceforge.jnlp.config.DeploymentConfiguration; import net.sourceforge.jnlp.runtime.Translator; import net.sourceforge.jnlp.util.FileUtils; -import net.sourceforge.jnlp.util.logging.OutputController; import net.sourceforge.jnlp.util.PropertiesFile; +import net.sourceforge.jnlp.util.logging.OutputController; +import net.sourceforge.jnlp.util.ui.NonEditableTableModel; public class CachePane extends JPanel { - JDialog parent; DeploymentConfiguration config; private String location; private JComponent defaultFocusComponent; DirectoryNode root; - String[] columns = { Translator.R("CVCPColName"), + String[] columns = { + Translator.R("CVCPColName"), Translator.R("CVCPColPath"), Translator.R("CVCPColType"), Translator.R("CVCPColDomain"), Translator.R("CVCPColSize"), Translator.R("CVCPColLastModified") }; JTable cacheTable; + private JButton deleteButton, refreshButton, doneButton; /** * Creates a new instance of the CachePane. @@ -95,42 +105,64 @@ public class CachePane extends JPanel { GridBagConstraints c = new GridBagConstraints(); c.fill = GridBagConstraints.BOTH; - DefaultTableModel model = new DefaultTableModel(columns, 0) { - public boolean isCellEditable(int row, int column) { - return false; - } - }; + TableModel model = new NonEditableTableModel(columns, 0); cacheTable = new JTable(model); cacheTable.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + cacheTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + final public void valueChanged(ListSelectionEvent listSelectionEvent) { + // If no row has been selected, disable the delete button, else enable it + if (cacheTable.getSelectionModel().isSelectionEmpty()) + // Disable delete button, since nothing selected + deleteButton.setEnabled(false); + else + // Enable delete button, since something selected + deleteButton.setEnabled(true); + } + }); cacheTable.setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN); cacheTable.setPreferredScrollableViewportSize(new Dimension(600, 200)); cacheTable.setFillsViewportHeight(true); JScrollPane scrollPane = new JScrollPane(cacheTable); - populateTable(); - - TableRowSorter<DefaultTableModel> tableSorter = new TableRowSorter<DefaultTableModel>(model); - tableSorter.setComparator(4, new Comparator<Long>() { // Comparator for size column. - @Override - public int compare(Long o1, Long o2) { - return o1.compareTo(o2); + TableRowSorter<TableModel> tableSorter = new TableRowSorter<TableModel>(model); + final Comparator comparator = new Comparator<Comparable>() { // General purpose Comparator + public final int compare(final Comparable a, final Comparable b) { + return a.compareTo(b); } - }); - tableSorter.setComparator(5, new Comparator<String>() { // Comparator for date column. + }; + tableSorter.setComparator(1, comparator); // Comparator for path column. + tableSorter.setComparator(4, comparator); // Comparator for size column. + tableSorter.setComparator(5, comparator); // Comparator for modified column. + cacheTable.setRowSorter(tableSorter); + final DefaultTableCellRenderer tableCellRenderer = new DefaultTableCellRenderer() { @Override - public int compare(String o1, String o2) { - DateFormat format = new SimpleDateFormat("MM/dd/yyyy"); - try { - Long time1 = format.parse(o1).getTime(); - Long time2 = format.parse(o2).getTime(); - return time1.compareTo(time2); - } catch (ParseException e) { - return 0; + public final Component getTableCellRendererComponent(final JTable table, final Object value, final boolean isSelected, final boolean hasFocus, final int row, final int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + + switch (column) { + case 1: // Path column + // Render absolute path + super.setText(((File)value).getAbsolutePath()); + break; + case 4: // Size column + // Render size formatted to default locale's number format + super.setText(NumberFormat.getInstance().format(value)); + break; + case 5: // last modified column + // Render modify date formatted to default locale's date format + super.setText(DateFormat.getDateInstance().format(value)); } + + return this; } - }); - cacheTable.setRowSorter(tableSorter); + }; + // TableCellRenderer for path column + cacheTable.getColumn(this.columns[1]).setCellRenderer(tableCellRenderer); + // TableCellRenderer for size column + cacheTable.getColumn(this.columns[4]).setCellRenderer(tableCellRenderer); + // TableCellRenderer for last modified column + cacheTable.getColumn(this.columns[5]).setCellRenderer(tableCellRenderer); c.weightx = 1; c.weighty = 1; @@ -139,7 +171,6 @@ public class CachePane extends JPanel { topPanel.add(scrollPane, c); this.add(topPanel, BorderLayout.CENTER); this.add(createButtonPanel(), BorderLayout.SOUTH); - } /** @@ -154,85 +185,45 @@ public class CachePane extends JPanel { List<JButton> buttons = new ArrayList<JButton>(); - JButton deleteButton = new JButton(Translator.R("CVCPButDelete")); + this.deleteButton = new JButton(Translator.R("CVCPButDelete")); deleteButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - FileLock fl = null; - File netxRunningFile = new File(config.getProperty(DeploymentConfiguration.KEY_USER_NETX_RUNNING_FILE)); - if (!netxRunningFile.exists()) { - try { - FileUtils.createParentDir(netxRunningFile); - FileUtils.createRestrictedFile(netxRunningFile, true); - } catch (IOException e1) { - OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e1); - } - } - - try { - fl = FileUtils.getFileLock(netxRunningFile.getPath(), false, false); - } catch (FileNotFoundException e1) { - } - - int row = cacheTable.getSelectedRow(); - try { - if (fl == null) return; - if (row == -1 || row > cacheTable.getRowCount() - 1) - return; - int modelRow = cacheTable.convertRowIndexToModel(row); - DirectoryNode fileNode = ((DirectoryNode) cacheTable.getModel().getValueAt(modelRow, 0)); - if (fileNode.getFile().delete()) { - updateRecentlyUsed(fileNode.getFile()); - fileNode.getParent().removeChild(fileNode); - FileUtils.deleteWithErrMesg(fileNode.getInfoFile()); - ((DefaultTableModel) cacheTable.getModel()).removeRow(modelRow); - cacheTable.getSelectionModel().setSelectionInterval(row, row); - CacheDirectory.cleanParent(fileNode); - } - } catch (Exception exception) { - //ignore - } - - if (fl != null) { - try { - fl.release(); - fl.channel().close(); - } catch (IOException e1) { - OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e1); - } - } - } - - private void updateRecentlyUsed(File f) { - File recentlyUsedFile = new File(location + File.separator + CacheLRUWrapper.CACHE_INDEX_FILE_NAME); - PropertiesFile pf = new PropertiesFile(recentlyUsedFile); - pf.load(); - Enumeration<Object> en = pf.keys(); - while (en.hasMoreElements()) { - String key = (String) en.nextElement(); - if (pf.get(key).equals(f.getAbsolutePath())) { - pf.remove(key); - } - } - pf.store(); + // Deleting may take a while, so indicate busy by cursor + parent.getContentPane().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + // Disable dialog and buttons while deleting + deleteButton.setEnabled(false); + refreshButton.setEnabled(false); + doneButton.setEnabled(false); + // Delete on AWT thread after this action has been performed + // in order to allow the cache viewer to update itself + invokeLaterDelete(); } }); + deleteButton.setEnabled(false); buttons.add(deleteButton); - JButton refreshButton = new JButton(Translator.R("CVCPButRefresh")); + this.refreshButton = new JButton(Translator.R("CVCPButRefresh")); refreshButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - populateTable(); + // Disable all its controls when performing cacheTable refresh (populating) + deleteButton.setEnabled(false); + refreshButton.setEnabled(false); + doneButton.setEnabled(false); + // Populate cacheTable on AWT thread after this action event has been performed + invokeLaterPopulateTable(); } }); + refreshButton.setEnabled(false); buttons.add(refreshButton); - JButton doneButton = new JButton(Translator.R("ButDone")); + this.doneButton = new JButton(Translator.R("ButDone")); doneButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - parent.dispose(); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent( + new WindowEvent(parent, WindowEvent.WINDOW_CLOSING)); } }); @@ -251,6 +242,7 @@ public class CachePane extends JPanel { } doneButton.setPreferredSize(new Dimension(wantedWidth, wantedHeight)); + doneButton.setEnabled(false); rightPanel.add(doneButton); buttonPanel.add(leftPanel); buttonPanel.add(rightPanel); @@ -259,13 +251,140 @@ public class CachePane extends JPanel { } /** + * Posts an event to the event queue to delete the currently selected + * resource in {@link CachePane#cacheTable} after the {@code CachePane} and + * {@link CacheViewer} have been instantiated and painted. + * @see CachePane#cacheTable + */ + private final void invokeLaterDelete() { + EventQueue.invokeLater(new Runnable() { + public void run() { + try { + FileLock fl = null; + File netxRunningFile = new File(config.getProperty(DeploymentConfiguration.KEY_USER_NETX_RUNNING_FILE)); + if (!netxRunningFile.exists()) { + try { + FileUtils.createParentDir(netxRunningFile); + FileUtils.createRestrictedFile(netxRunningFile, true); + } catch (IOException e1) { + OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e1); + } + } + + try { + fl = FileUtils.getFileLock(netxRunningFile.getPath(), false, false); + } catch (FileNotFoundException e1) { + } + + int row = cacheTable.getSelectedRow(); + try { + if (fl == null) return; + int modelRow = cacheTable.convertRowIndexToModel(row); + DirectoryNode fileNode = ((DirectoryNode) cacheTable.getModel().getValueAt(modelRow, 0)); + if (fileNode.getFile().delete()) { + updateRecentlyUsed(fileNode.getFile()); + fileNode.getParent().removeChild(fileNode); + FileUtils.deleteWithErrMesg(fileNode.getInfoFile()); + ((NonEditableTableModel) cacheTable.getModel()).removeRow(modelRow); + cacheTable.getSelectionModel().clearSelection(); + CacheDirectory.cleanParent(fileNode); + } + } catch (Exception exception) { + // ignore + } + + if (fl != null) { + try { + fl.release(); + fl.channel().close(); + } catch (IOException e1) { + OutputController.getLogger().log(OutputController.Level.ERROR_ALL, e1); + } + } + } catch (Exception exception) { + OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, exception); + } finally { + // If nothing selected then keep deleteButton disabled + if (!cacheTable.getSelectionModel().isSelectionEmpty()) deleteButton.setEnabled(true); + // Enable buttons + refreshButton.setEnabled(true); + doneButton.setEnabled(true); + // If cacheTable is empty disable it and set background + // color to indicate being disabled + if (cacheTable.getModel().getRowCount() == 0) { + cacheTable.setEnabled(false); + cacheTable.setBackground(SystemColor.control); + } + // Reset cursor + parent.getContentPane().setCursor(Cursor.getDefaultCursor()); + } + } + + private void updateRecentlyUsed(File f) { + File recentlyUsedFile = new File(location + File.separator + CacheLRUWrapper.CACHE_INDEX_FILE_NAME); + PropertiesFile pf = new PropertiesFile(recentlyUsedFile); + pf.load(); + Enumeration<Object> en = pf.keys(); + while (en.hasMoreElements()) { + String key = (String) en.nextElement(); + if (pf.get(key).equals(f.getAbsolutePath())) { + pf.remove(key); + } + } + pf.store(); + } + }); + } + + /** + * Posts an event to the event queue to populate the + * {@link CachePane#cacheTable} after the {@code CachePane} and + * {@link CacheViewer} have been instantiated and painted. + * @see CachePane#populateTable + */ + final void invokeLaterPopulateTable() { + EventQueue.invokeLater(new Runnable() { + public void run() { + try { + populateTable(); + // Disable cacheTable when no data to display, so no events are generated + if (cacheTable.getModel().getRowCount() == 0) { + cacheTable.setEnabled(false); + cacheTable.setBackground(SystemColor.control); + // No data in cacheTable, so nothing to delete + deleteButton.setEnabled(false); + } else { + cacheTable.setEnabled(true); + cacheTable.setBackground(SystemColor.text); + } + } catch (Exception exception) { + OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, exception); + } finally { + refreshButton.setEnabled(true); + doneButton.setEnabled(true); + } + } + }); + } + + /** * Populate the table with fresh data. Any manual updates to the cache * directory will be updated in the table. */ private void populateTable() { - ((DefaultTableModel) cacheTable.getModel()).setRowCount(0); //Clears the table - for (Object[] v : generateData(root)) - ((DefaultTableModel) cacheTable.getModel()).addRow(v); + try { + // Populating the cacheTable may take a while, so indicate busy by cursor + parent.getContentPane().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + + NonEditableTableModel tableModel; + (tableModel = (NonEditableTableModel)cacheTable.getModel()).setRowCount(0); //Clears the table + for (Object[] v : generateData(root)) tableModel.addRow(v); + } catch (Exception exception) { + OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, exception); + } finally { + // Reset cursor + parent.getContentPane().setCursor(Cursor.getDefaultCursor()); + } } /** @@ -283,12 +402,15 @@ public class CachePane extends JPanel { for (DirectoryNode type : identifier.getChildren()) { for (DirectoryNode domain : type.getChildren()) { for (DirectoryNode leaf : CacheDirectory.getLeafData(domain)) { - Object[] o = { leaf, - leaf.getFile().getAbsolutePath(), - type, - domain, - leaf.getFile().length(), - new SimpleDateFormat("MM/dd/yyyy").format(leaf.getFile().lastModified()) }; + final File f = leaf.getFile(); + Object[] o = { + leaf, + f.getParentFile(), + type, + domain, + f.length(), + new Date(f.lastModified()) + }; data.add(o); } } diff --git a/netx/net/sourceforge/jnlp/controlpanel/CacheViewer.java b/netx/net/sourceforge/jnlp/controlpanel/CacheViewer.java index fc63b60..bbdcad4 100644 --- a/netx/net/sourceforge/jnlp/controlpanel/CacheViewer.java +++ b/netx/net/sourceforge/jnlp/controlpanel/CacheViewer.java @@ -1,5 +1,5 @@ /* CacheViewer.java -- Display the GUI for viewing and deleting cache files. -Copyright (C) 2010 Red Hat +Copyright (C) 2013 Red Hat This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,7 +22,10 @@ import java.awt.Dimension; import java.awt.Frame; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; +import java.awt.KeyEventDispatcher; +import java.awt.KeyboardFocusManager; import java.awt.Toolkit; +import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; @@ -53,8 +56,11 @@ public class CacheViewer extends JDialog { */ public CacheViewer(DeploymentConfiguration config) { super((Frame) null, dialogTitle, true); // Don't need a parent. - setIconImages(ImageResources.INSTANCE.getApplicationImages()); this.config = config; + if (config == null) { + throw new IllegalArgumentException("config: " + config); + } + setIconImages(ImageResources.INSTANCE.getApplicationImages()); /* Prepare for adding components to dialog box */ Container contentPane = getContentPane(); @@ -70,11 +76,13 @@ public class CacheViewer extends JDialog { contentPane.add(topPanel, c); pack(); + this.topPanel.invokeLaterPopulateTable(); /* Set focus to default button when first activated */ WindowAdapter adapter = new WindowAdapter() { private boolean gotFocus = false; + @Override public void windowGainedFocus(WindowEvent we) { // Once window gets focus, set initial focus if (!gotFocus) { @@ -85,6 +93,33 @@ public class CacheViewer extends JDialog { }; addWindowFocusListener(adapter); + // Add a KeyEventDispatcher to dispatch events when this CacheViewer has focus + final CacheViewer cacheViewer = this; + KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(new KeyEventDispatcher() { + /** + * Dispatches mainly the <code>VK_ESCAPE</code> key event to close + * the <code>CacheViewer</code> dialog. + * @return {@code true} after an {@link KeyEvent#VK_ESCAPE + * VK_ESCAPE} has been processed, otherwise {@code false} + * @see KeyEventDispatcher + */ + public boolean dispatchKeyEvent(final KeyEvent keyEvent) { + // Check if Esc key has been pressed + if (keyEvent.getKeyCode() == KeyEvent.VK_ESCAPE && + keyEvent.getID() == KeyEvent.KEY_PRESSED) { + // Exclude this key event from further processing + keyEvent.consume(); + // Remove this low-level KeyEventDispatcher + KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(this); + // Post close event to CacheViewer dialog + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent( + new WindowEvent(cacheViewer, WindowEvent.WINDOW_CLOSING)); + return true; + } + return false; + } + }); + initialized = true; } diff --git a/netx/net/sourceforge/jnlp/util/ui/NonEditableTableModel.java b/netx/net/sourceforge/jnlp/util/ui/NonEditableTableModel.java new file mode 100644 index 0000000..4f2c409 --- /dev/null +++ b/netx/net/sourceforge/jnlp/util/ui/NonEditableTableModel.java @@ -0,0 +1,124 @@ +/* NonEditableTableModel.java + Copyright (C) 2013 Red Hat, Inc. + +This file is part of IcedTea. + +IcedTea is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, version 2. + +IcedTea is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +IcedTea; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is making a +combined work based on this library. Thus, the terms and conditions of the GNU +General Public License cover the whole combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, and +to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms and +conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. +*/ +package net.sourceforge.jnlp.util.ui; + +import java.util.Vector; +import javax.swing.table.DefaultTableModel; + +/** + * A table model that in effect is a {@link DefaultTableModel} except for no + * cell being editable. + * @see DefaultTableModel + * @since IcedTea-Web 1.5 + */ +public class NonEditableTableModel extends DefaultTableModel { + /** + * Constructs a {@link javax.swing.table.TableModel} that serves only one + * purpose: make cells of certificate tables not editable. + * @see DefaultTableModel#DefaultTableModel() + */ + public NonEditableTableModel() { + super(); + } + + /** + * Constructs a {@link javax.swing.table.TableModel} that serves only one + * purpose: make cells of certificate tables not editable. + * @param rowCount the number of rows the table holds + * @param columnCount the number of columns the table holds + * @see DefaultTableModel#DefaultTableModel(int,int) + */ + public NonEditableTableModel(final int rowCount, final int columnCount) { + super(rowCount, columnCount); + } + + /** + * Constructs a {@link javax.swing.table.TableModel} that serves only one + * purpose: make cells of certificate tables not editable. + * @param data the data of the table + * @param columnNames the names of the columns + * @see DefaultTableModel#DefaultTableModel(Object[][],Object[]) + */ + public NonEditableTableModel(final Object[][] data, final Object[] columnNames) { + super(data, columnNames); + } + + /** + * Constructs a {@link javax.swing.table.TableModel} that serves only one + * purpose: make cells of certificate tables not editable. + * @param columnNames {@code array} containing the names of the new columns; + * if this is {@code null} then the model has no columns + * @param rowCount the number of rows the table holds + * @see DefaultTableModel#DefaultTableModel(Object[],int) + */ + public NonEditableTableModel(final Object[] columnNames, final int rowCount) { + super(columnNames, rowCount); + } + + /** + * Constructs a {@link javax.swing.table.TableModel} that serves only one + * purpose: make cells of certificate tables not editable. + * @param columnNames {@code vector} containing the names of the new columns; + * if this is {@code null} then the model has no columns + * @param rowCount the number of rows the table holds + * @see DefaultTableModel#DefaultTableModel(Vector,int) + */ + public NonEditableTableModel(final Vector columnNames, final int rowCount) { + super(columnNames, rowCount); + } + + /** + * Constructs a {@link javax.swing.table.TableModel} that serves only one + * purpose: make cells of certificate tables not editable. + * @param data the data of the table, a {@code Vector} of {@code Vector}s + * of {@code Object} values + * @param columnNames {@code vector} containing the names of the new columns + * @see DefaultTableModel#DefaultTableModel(Vector,Vector) + */ + public NonEditableTableModel(final Vector data, final Vector columnNames) { + super(data, columnNames); + } + + /** + * This method always returns {@code false} to make the table's cells not + * editable. + * @param row the row whose value to be queried + * @param column the column whose value to be queried + * @return always {@code false} + */ + @Override + public boolean isCellEditable(final int row, final int column) { + return false; + } +} diff --git a/netx/net/sourceforge/jnlp/util/ui/package-info.java b/netx/net/sourceforge/jnlp/util/ui/package-info.java new file mode 100644 index 0000000..ddb2621 --- /dev/null +++ b/netx/net/sourceforge/jnlp/util/ui/package-info.java @@ -0,0 +1,41 @@ +/* package-info.java + Copyright (C) 2013 Red Hat, Inc. + +This file is part of IcedTea. + +IcedTea is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, version 2. + +IcedTea is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +IcedTea; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is making a +combined work based on this library. Thus, the terms and conditions of the GNU +General Public License cover the whole combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, and +to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms and +conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. +*/ +/** + * Contains classes that deal with common and recurring UI tasks. + * <p> + * <b>NOTE:</b> Before adding new self-sufficient {@code public static} methods + * to this package please evaluate thier suitability for {@link UI} first.</p> + * @since IcedTea-Web 1.5 + */ +package net.sourceforge.jnlp.util.ui; |