All Downloads are FREE. Search and download functionalities are using the official Maven repository.

decodes.gui.TopFrame Maven / Gradle / Ivy

Go to download

A collection of software for aggregatting and processing environmental data such as from NOAA GOES satellites.

The newest version!
/*
*  $Id$
*/
package decodes.gui;

import java.awt.Point;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Properties;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import javax.swing.border.BevelBorder;

import decodes.dbeditor.DbEditorFrame;
import decodes.platwiz.PlatformWizard;
import decodes.sql.SqlDatabaseIO;
import decodes.util.DecodesSettings;
import decodes.util.ResourceFactory;
import ilex.util.EnvExpander;
import ilex.util.Logger;
import ilex.util.AsciiUtil;

/**
* Common base class for top-level frames in DECODES GUI applications.
* Provides singleton-like access for various resources.
*/
public class TopFrame extends JFrame
{
	private static TopFrame _instance;
	
	protected boolean exitOnClose = false;
	private File changeTrackFile = null;
	private boolean trackingChanges = false;
	private Properties locSizeProps = null;
	private JPanel appContentPane = null;
	private Container jframeContentPane = null;

	private JPanel statusPanel = null;
	JLabel dbNameLabel = null, dbStatusLabel = null;
	public static String profileName = null;

	/** 
	  Constructor sets the singleton instance on first call. 
	*/
    public TopFrame()
	{
		if (_instance == null)
			_instance = this;
		ImageIcon tkIcon = new ImageIcon(
			ResourceFactory.instance().getIconPath());
		setIconImage(tkIcon.getImage());
		
		appContentPane = new JPanel(new BorderLayout());

		jframeContentPane = super.getContentPane();
		jframeContentPane.setLayout(new BorderLayout());
		jframeContentPane.add(appContentPane, BorderLayout.CENTER);
		
		statusPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 1));
		statusPanel.setBorder(new BevelBorder(BevelBorder.LOWERED));
		jframeContentPane.add(statusPanel, BorderLayout.SOUTH);
//		statusPanel.setPreferredSize(new Dimension(this.getWidth(), 16));
//		statusPanel.setLayout(new BoxLayout(statusPanel, BoxLayout.X_AXIS));
		
		statusPanel.add(dbNameLabel = new JLabel());
		statusPanel.add(dbStatusLabel = new JLabel());
		setStatusBar();
    }
    
	/**
	 * Return the pane for applications to use.
	 */
	@Override
	public Container getContentPane()
	{
		return appContentPane;
	}

	public void setStatusBar()
	{
		final String dbName = 
			(profileName != null ? ("(Profile " + profileName + ") ") : "")
			+ DecodesSettings.instance().editDatabaseType + " "
			+ DecodesSettings.instance().editDatabaseLocation;
		
		String s = "(Not initialized)";
		if (DecodesSettings.instance().editDatabaseTypeCode == DecodesSettings.DB_XML)
			s = "";
		else
		{
			decodes.db.Database db = decodes.db.Database.getDb();
			if (db != null)
			{
				decodes.db.DatabaseIO dbio = db.getDbIo();
				if (dbio == null)
					s = "(Not Open)";
				if (dbio instanceof SqlDatabaseIO)
					s = ((SqlDatabaseIO)dbio).isConnected() ? "(Connected)" : "(Not Connected)";
			}
		}

		final String statusText = s;
		SwingUtilities.invokeLater(
			new Runnable()
			{
				@Override
				public void run()
				{
					dbNameLabel.setText(dbName);
					dbStatusLabel.setText(statusText);
				}
			});
	}

	/** 
	  The constructor MUST be called prior to calling this method. Since
	  each GUI will have a different concrete subclass of TopFrame, we
	  can't construct the singleton here.
	  @return the singleton instance. 
	*/
	public static TopFrame instance()
	{
		return _instance;
	}

	/**
	 * Returns true if there is an instance. This can be used to detect whether
	 * the program running is a GUI or not.
	 * @return true if there is an instance.
	 */
	public static boolean isGUI()
	{
		return _instance != null;
	}

	/** 
	  Starts a modal error dialog with the passed message. 
	  @param msg the error message
	*/
	public void showError(String msg)
	{
		Logger.instance().log(Logger.E_FAILURE, msg);
		JOptionPane.showMessageDialog(this,
			AsciiUtil.wrapString(msg, 60), "Error!", JOptionPane.ERROR_MESSAGE);
	}
	
	public int showConfirm(String title, String msg, int option)
	{
		return JOptionPane.showConfirmDialog(this, AsciiUtil.wrapString(msg, 60),
			title, option);
	}

	/**
	  Launches the passed modal dialog at a reasonable position on the screen.
	  @param dlg the modal dialog
	*/
	public void launchDialog(JDialog dlg)
	{
		dlg.validate();
		dlg.setLocationRelativeTo(this);
		dlg.setVisible(true);
	}

	public static TopFrame getDbEditFrame()
	{
		TopFrame jf = DbEditorFrame.instance();
		if (jf == null)
		{
			PlatformWizard pw = PlatformWizard.instance();
			if (pw != null && pw.getPlatwizFrame() != null)
			{
				jf = pw.getPlatwizFrame();
			}
			else
			{
				jf = TopFrame.instance();
			}
		}
		return jf;
	}

	/** @return the tabbed pane for TS Groups */
	public JTabbedPane getTsGroupsListTabbedPane() { return null; }
	
	/** @return the panel for TS Groups */
	public JPanel getTsGroupsListPanel() { return null; }
	
	/** @return the data type standard */
//	public static String getDataTypeStandard() { return null; }
	
	public void setExitOnClose(boolean tf)
	{
		exitOnClose = tf;
	}

	public boolean getExitOnClose()
	{
		return exitOnClose;
	}

	public void trackChanges(String frameTitle)
	{
		// If already tracking changes, do nothing.
		if (trackingChanges)
			return;
		// Option in OpenDCS 6.1 to NOT remember screen positions & sizes.
		if (!DecodesSettings.instance().rememberScreenPosition)
			return;
		trackingChanges = true;
		File tmpDir = new File(EnvExpander.expand("$DCSTOOL_USERDIR/tmp"));
		if (!tmpDir.isDirectory())
			if (!tmpDir.mkdirs())
			{
				Logger.instance().warning(
					"Cannot track GUI size & location changes because '"
					+ tmpDir.getPath() + "' does not exist and cannot be created.");
			}
		String name = (TopFrame.profileName == null ? "" : (TopFrame.profileName+"-"))
			+ frameTitle + ".loc";
		changeTrackFile = new File(tmpDir, name);
		
		locSizeProps = new Properties();
		Point curLoc = getLocation();
		Dimension curSize = getSize();
		if (changeTrackFile.canRead())
		{
			FileInputStream fis;
			try
			{
				fis = new FileInputStream(changeTrackFile);
				locSizeProps.load(fis);
				fis.close();
				String s = locSizeProps.getProperty("x");
				int x = s != null ? Integer.parseInt(s) : curLoc.x;
				s = locSizeProps.getProperty("y");
				int y = s != null ? Integer.parseInt(s) : curLoc.y;
				s = locSizeProps.getProperty("h");
				int h = s != null ? Integer.parseInt(s) : curSize.height;
				s = locSizeProps.getProperty("w");
				int w = s != null ? Integer.parseInt(s) : curSize.width;
				setBounds(x,y,w,h);
			}
			catch (Exception e1)
			{
				Logger.instance().warning("Cannot read size & loc file '"
					+ changeTrackFile.getPath() + "': " + e1);
			}
		}
		else
		{
			int offsetX=0, offsetY=0;
		
			if (TopFrame.profileName != null)
			{
				offsetX = 15;
				offsetY = 15;
			}
			locSizeProps.setProperty("x", ""+(curLoc.x+offsetX));
			locSizeProps.setProperty("y", ""+(curLoc.y+offsetY));
			locSizeProps.setProperty("w", ""+curSize.width);
			locSizeProps.setProperty("h", ""+curSize.height);
		}
		addComponentListener(
			new ComponentAdapter()
			{
				public void componentResized(ComponentEvent e)
				{
					sizeChanged(e.getComponent().getSize());
				}
				public void componentMoved(ComponentEvent e)
				{
					positionChanged(e.getComponent().getLocation());
				}
			});
	}
	
	private synchronized void sizeChanged(Dimension d)
	{
		if (changeTrackFile == null)
			return;
		locSizeProps.setProperty("w", ""+d.width);
		locSizeProps.setProperty("h", ""+d.height);
		saveLocSize();
	}
	private synchronized void positionChanged(Point p)
	{
		if (changeTrackFile == null)
			return;
		locSizeProps.setProperty("x", ""+p.x);
		locSizeProps.setProperty("y", ""+p.y);
		saveLocSize();
	}
	private void saveLocSize()
	{
		try
		{
			FileOutputStream fos = new FileOutputStream(changeTrackFile);
			locSizeProps.store(fos, null);
			fos.close();
		}
		catch(Exception ex)
		{
			Logger.instance().warning("Cannot write to '" + changeTrackFile.getPath()
				+ "': " + ex);
			changeTrackFile = null;
		}
	}

	@Override
	public void setTitle(String title)
	{
		String profileName = DecodesSettings.instance().getProfileName();
		if (profileName != null)
			title = title + " (" + profileName + ")";
		super.setTitle(title);
	}
	
	/**
	 * Used by Launcher to determine if it's ok to close an app's frame.
	 * Each app should overload, check for open elements that have changes that need
	 * to be saved, and if any, bring this frame to the fore and issue a warning.
	 * Default implementation here always returns true. 
	 * @return false if there are unsaved edits, true if closing does no harm.
	 */
	public boolean canClose()
	{
		return true;
	}
	
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy