/*
* ALMA - Atacama Large Millimiter Array
* (c) European Southern Observatory, 2002
* Copyright by ESO (in the framework of the ALMA collaboration)
* and Cosylab 2002, All rights reserved
*
* 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.acs.logging.errorbrowser;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.ContainerEvent;
import java.awt.event.ContainerListener;
import java.lang.reflect.InvocationTargetException;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import com.cosylab.logging.LoggingClient;
import alma.acs.logging.table.LogEntryTableModelBase;
/**
* The dialog showing the stack trace of errors.
* <P>
* The dialog has one tab for each stack trace whose title is the stack ID.
*
* @author acaproni
*
*/
public class ErrorBrowserDlg extends JDialog implements ContainerListener {
/**
* The pane showing the error tabs
*/
private final JTabbedPane tabbedPane = new JTabbedPane();
/**
* The panel shown when the dialog is displayed with no error traces.
*/
private final JPanel notTracesPnl = new JPanel(new BorderLayout());
/**
* The logging client
*/
private final LoggingClient loggingClient;
/**
* The {@link CardLayout} shows the tabbed pane when the dialog contains
* error traces and a label when no error traces have been defined.
*/
private final CardLayout cardLayout = new CardLayout();
/**
* The panel with the variable content.
* <P>
* The components shown by the panel is defined by the card layout.
*/
private final JPanel cardsPanel = new JPanel(cardLayout);
/**
* The name of the card shown when there are no error traces
*/
private final static String NO_ERROR_TRACES = "Empty";
/**
* The name of the card shown when there are no error traces
*/
private final static String ERROR_TRACES = "ErrorTraces";
/**
* Constructor
*
* @param client A not <code>null</code> reference to the <code>LoggingClient</code>
*/
public ErrorBrowserDlg(LoggingClient client) {
super((JFrame)null, "Error browser");
if (client==null) {
throw new IllegalArgumentException("The LoggingClient can't be null");
}
loggingClient=client;
setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);
initialize();
}
/**
* Init the GUI.
* <P>
* The dialog is composed of a set of tabs, one for each stack trace.
*/
private void initialize() {
cardsPanel.add(tabbedPane,ERROR_TRACES);
JLabel notTracesLbl = new JLabel("<HTML>No error traces.<BR>Add an error trace from the table of logs.</HTML>");
notTracesPnl.add(notTracesLbl,BorderLayout.NORTH);
cardsPanel.add(notTracesPnl,NO_ERROR_TRACES);
add(cardsPanel);
ratioContent();
tabbedPane.addContainerListener(this);
setMinimumSize(new Dimension(400,200));
setPreferredSize(new Dimension(500,300));
pack();
setVisible(true);
}
/**
* Add a new error tab.
* <P>
* The tab is added by a separate thread.
*
* @param sourceModel The model used by the <code>Engine</code> to look for logs
* belonging to the error trace with the give <code>STACKID</code>
* @param stackId The <code>STACKID</code> of logs of the stack trace
*/
public synchronized void addErrorTab(final LogEntryTableModelBase sourceModel, final String stackId) {
if (stackId==null || stackId.isEmpty()) {
throw new IllegalArgumentException("The stackID can't be null nor empty");
}
if (sourceModel==null) {
throw new IllegalArgumentException("The model can't be null");
}
removeDuplicatedTabs(stackId);
// Add the new tab
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
ErrorTab newTab;
try {
newTab = new ErrorTab(sourceModel,stackId,loggingClient);
} catch (Exception e) {
System.err.println("Error creating an error tab: "+e.getMessage());
e.printStackTrace();
return;
}
tabbedPane.insertTab(stackId, null, newTab, "Stack trace for ID "+stackId, 0);
tabbedPane.setTabComponentAt(0, new TabComponent(tabbedPane));
setVisible(true);
}
});
} catch (Exception e) {
System.err.println("Error adding tab: "+e.getMessage());
e.printStackTrace(System.err);
}
}
/**
* Close the dialog
*/
public void close() {
for (int t=0; t<tabbedPane.getTabCount(); t++) {
ErrorTab tab = (ErrorTab)tabbedPane.getComponentAt(t);
if (tab!=null) {
tab.close();
}
}
setVisible(false);
dispose();
}
/**
* Remove all the tabs with the given title, if any.
* <P>
* The removal runs synchronously inside the vent dispatcher EDT.
*
* @param title The title of the tab
*/
private void removeDuplicatedTabs(final String tabTitle) {
// Check if a tab with the given name already exists
while (true) {
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
for (int t=0; t<tabbedPane.getTabCount(); t++) {
if (tabbedPane.getTitleAt(t).equals(tabTitle)) {
tabbedPane.removeTabAt(t);
break;
}
}
}
});
return;
} catch (InterruptedException e) {
// If the thread has been interrupted then retry
e.printStackTrace();
continue;
} catch (InvocationTargetException e) {
// If an error happens while executing run() then prints out a message
e.printStackTrace();
}
}
}
/**
* Override <code>setVisible()</code> to move the dialog
* over the logging client and in front of other windows
*/
@Override
public void setVisible(boolean visible) {
boolean wasVisibel=isVisible();
super.setVisible(visible);
// Move the win on top of jlog
if (visible && isShowing()) {
Point loggingPos = loggingClient.getLocationOnScreen();
if (!wasVisibel) {
setLocation(loggingPos);
}
toFront();
}
}
/**
* Shown the proper content in the dialog:
* <UL>
* <LI>the label when there are no error traces
* <LI>the tabbed pane when there is at least one error trace
* </UL>
*/
private void ratioContent() {
if (tabbedPane.getTabCount()>0) {
cardLayout.show(cardsPanel, ERROR_TRACES);
} else {
cardLayout.show(cardsPanel, NO_ERROR_TRACES);
}
}
/**
* @see ContainerListener
*/
@Override
public void componentAdded(ContainerEvent e) {
ratioContent();
}
/**
* @see ContainerListener
*/
@Override
public void componentRemoved(ContainerEvent e) {
ratioContent();
}
}