/* * ALMA - Atacama Large Millimiter Array (c) European Southern Observatory, 2007 * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library 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 Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ package alma.acsplugins.alarmsystem.gui.reduced; import java.awt.BorderLayout; import java.awt.Dialog; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTabbedPane; import javax.swing.tree.DefaultMutableTreeNode; import alma.acs.gui.util.threadsupport.EDTExecutor; import alma.acsplugins.alarmsystem.gui.CernSysPanel; import alma.acsplugins.alarmsystem.gui.table.AlarmGUIType; import alma.acsplugins.alarmsystem.gui.table.AlarmTable; import alma.acsplugins.alarmsystem.gui.table.AlarmTableEntry; import alma.acsplugins.alarmsystem.gui.table.AlarmTableModel; import alma.acsplugins.alarmsystem.gui.table.AlarmTableModel.AlarmTableColumn; import alma.acsplugins.alarmsystem.gui.tree.AlarmTree; import alma.acsplugins.alarmsystem.gui.undocumented.table.UndocAlarmTableModel; import alma.alarmsystem.clients.AlarmCategoryClient; import alma.alarmsystem.clients.CategoryClient; import cern.laser.client.data.Alarm; /** * The dialog showing all the alarms involved in a reduction. * <P> * The dialog has a table, one row for each alarm. * The alarms shown in this dialog are a snapshot of those involved in a reduction. * * @author acaproni * */ public class ReducedChainDlg extends JDialog implements ActionListener { /** * The button to close the dialog */ private final JButton closeBtn = new JButton("Close"); /** * The button to refresh the content of the table */ private final JButton refreshBtn = new JButton("Refresh"); /** * The table of alarms */ private final AlarmTable table; /** * The tree of alarms */ private final AlarmTree tree=new AlarmTree(); /** * The model */ private final AlarmTableModel model; /** * The panel showing this table */ private final CernSysPanel panel; /** * The {@link CategoryClient} to get the children of the root * alarm from the alarm service */ private final AlarmCategoryClient categoryClient; /** * The rot alarm, whose children are displayed in the table */ private volatile AlarmTableEntry alarm; /** * Constructor * * @param client The {@link CategoryClient} to get the children of the alarm * to show in the table * @param rootAlarm The root alarm whose children appear in the table * @param panel The alarm panel */ public ReducedChainDlg(AlarmCategoryClient client, AlarmTableEntry rootAlarm, CernSysPanel panel,UndocAlarmTableModel undocModel) { if (client==null) { throw new IllegalArgumentException("The category client can't be null"); } if (rootAlarm==null) { throw new IllegalArgumentException("The alarm can't be null"); } if (panel==null) { throw new IllegalArgumentException("The panel can't be null"); } categoryClient=client; alarm=rootAlarm; this.panel=panel; model = new AlarmTableModel(rootPane,false,true,undocModel); model.start(); table = new AlarmTable(model,panel,undocModel, null); EDTExecutor.instance().execute(new Runnable() { @Override public void run() { initGUI(); } }); refreshContent(); } /** * Initialize the GUI */ private void initGUI() { setIconImage(new ImageIcon(AlarmGUIType.class.getResource(AlarmGUIType.iconFolder+"arrow_in.png")).getImage()); setModalityType(Dialog.ModalityType.MODELESS); setDefaultCloseOperation(HIDE_ON_CLOSE); rootPane.setLayout(new BorderLayout()); JTabbedPane tabbedPane = new JTabbedPane(); JScrollPane tableScrollPane = new JScrollPane( JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); tableScrollPane.setViewportView(table); table.addRemoveColumn(AlarmTableColumn.ICON, false); tabbedPane.addTab("Table view", tableScrollPane); JScrollPane treeScrollPane = new JScrollPane( JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); treeScrollPane.setViewportView(tree); tabbedPane.addTab("Tree view", treeScrollPane); rootPane.add(tabbedPane,BorderLayout.CENTER); JPanel buttonPnl = new JPanel(); buttonPnl.add(refreshBtn); refreshBtn.addActionListener(this); refreshBtn.setEnabled(false); buttonPnl.add(closeBtn); closeBtn.addActionListener(this); rootPane.add(buttonPnl,BorderLayout.SOUTH); pack(); setVisible(true); } /** * Close the dialog and frees its resources */ public void close() { model.close(); EDTExecutor.instance().execute(new Runnable() { public void run() { setVisible(false); dispose(); } }); } /** * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ @Override public void actionPerformed(ActionEvent e) { if (e.getSource()==closeBtn) { EDTExecutor.instance().execute(new Runnable() { public void run() { setVisible(false); } }); } else if (e.getSource()==refreshBtn) { refreshContent(); } } /** * Refresh the content of the table and the tree by getting the * children of the root alarm from the {@link CategoryClient}. */ private void refreshContent() { System.out.println("refreshContent with rootNode "+alarm); Thread refreshThread = new Thread() { public void run() { try { EDTExecutor.instance().executeSync(new Runnable(){ public void run() { refreshBtn.setEnabled(true); model.clear(); setTitle("Reduction chain of ["+alarm.getAlarmId()+"]"); tree.clear(alarm); } }); } catch (Throwable t) { System.err.println("Error preparaing to refresh for alarm "+alarm); t.printStackTrace(); return; } getAlarmChain(alarm,null); EDTExecutor.instance().execute(new Runnable() { public void run() { tree.expandRow(0); model.fireTableDataChanged(); } }); } }; refreshThread.setDaemon(true); refreshThread.setName("ReducedchainDlg.refreshTableContent "+alarm.getAlarmId()); refreshThread.start(); } /** * Get the chain of reduction of the given alarm. * <P> * <i>Implementation notes</i>: * <UL> * <LI>this method is recursive and therefore could lead to an out of memory if the chain is very deep. * <LI><code>getAlarmChain(Alarm, DefaultMutableTreeNode)</code> uses the {@link #categoryClient} to get * the children of an alarm. This operation involves a CORBA call so it must not be executed * inside the swing EDT. * </UL> * * @param al The alarm to get reduced nodes * @param parentNode The parent node of the tree */ private void getAlarmChain(Alarm al, DefaultMutableTreeNode parentNode) { model.onAlarm(al); DefaultMutableTreeNode newNode = tree.add(al, parentNode); if (al!=null) { Alarm[] alarms = null; try { if (al.isNodeParent()) { alarms = categoryClient.getChildren(al.getAlarmId(), true); } else { alarms = categoryClient.getChildren(al.getAlarmId(), false); } } catch (Throwable error) { System.err.println("Error getting the children of "+alarm.getAlarmId()); error.printStackTrace(System.err); JOptionPane.showMessageDialog(table, "Error getting children of "+alarm.getAlarmId(), "Error getting alarms", JOptionPane.ERROR_MESSAGE); return; } if (alarms !=null) { for (Alarm child: alarms) { getAlarmChain(child,newNode); } } } } /** * Set a new alarm as root of the displayed chain of a reduction. * <P> * By setting a new root alarm, the content of the dialog is replaced * by a new chain of reduction having the passed alarm as root. * * @param rootAlarm The new alarm root of a reduction chain */ public void setRootAlarm(AlarmTableEntry rootAlarm) { if (rootAlarm==null) { throw new IllegalArgumentException("The alarm can't be null"); } alarm=rootAlarm; System.out.println("setRootAlarm: Root alarm is "+rootAlarm); refreshContent(); } }