com.ascert.open.term.gui.EmulatorPanel Maven / Gradle / Ivy
/*
* Copyright (c) 2016, 2017 Ascert, LLC.
* www.ascert.com
*
* Based on original code from FreeHost3270, copyright for derivations from original works remain:
* Copyright (C) 1998, 2001 Art Gillespie
* Copyright (2) 2005 the http://FreeHost3270.Sourceforge.net
*
* 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 com.ascert.open.term.gui;
import com.ascert.open.term.application.OpenTermConfig;
import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.Event;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Logger;
import javax.swing.*;
import com.ascert.open.term.core.Host;
import com.ascert.open.term.i3270.Term3270;
import com.ascert.open.term.core.Terminal;
import com.ascert.open.term.core.TerminalFactoryRegistrar;
/**
* Main terminal emulator panel, which includes menu, F-key bar, and actual terminal screen.
* Created as a JPanel for ease of inclusion inside other windows and embedding within other applications.
*/
//TODO - revisit all the pack and validate calls to see if really needed.
public class EmulatorPanel extends JPanel
implements ActionListener, FocusListener
{
private static final Logger log = Logger.getLogger(EmulatorPanel.class.getName());
/**
* These font sizes will be presented to the user.
*/
public static final int[] FONT_SIZES =
{
6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 32, 36, 40
};
public static final String[] COLOR_NAMES =
{
"Black", "White", "Green", "Red", "Blue", "Orange", "Turquoise", "Dark Blue", "Light Green"
};
protected JFrame parentFrame;
private JMenuBar menubar;
private JMenu connect;
private JToolBar toolbar;
private JTerminalScreen rhp;
private Terminal term;
private List available = new ArrayList<>();
private boolean autoConnect = true;
private boolean embeddedUse = false;
private String productName;
// Allows a view-only type mode, such as when being controlled by an external program
// Although the keyboard and mouse input are disabled, characters and keys can still be injected
// by a controlling program
protected boolean interactionAllowed = true;
private boolean serverMode;
/**
* No-ops constructor. Asks users to enter the connection settings in the corresponding dialog box then proceeds as normal.
*/
public EmulatorPanel()
{
this(new ArrayList ());
}
/**
* Single host constructor, typical used for terminal server mode
*
* @param host
* @param server
*/
public EmulatorPanel(Host host, boolean serverMode)
{
super();
this.serverMode = serverMode;
this.available.add(host);
init();
}
public EmulatorPanel(List hosts)
{
super();
if (hosts != null)
{
this.available.addAll(hosts);
}
init();
}
// quick hack to allow a sort of "slave" mode that can be fed with data from outside
public EmulatorPanel(Terminal term, boolean noConnection)
{
this.term = term;
this.autoConnect = !noConnection;
init();
}
// enabling embedded use ensures we don't try and exit the VM on window close
public void setEmbeddedUse(boolean embeddedUse)
{
this.embeddedUse = embeddedUse;
}
/**
* @return the interactionAllowed
*/
public boolean isInteractionAllowed()
{
return interactionAllowed;
}
/**
* @param kbdEnabled the interactionAllowed to set
*/
public void setInteractionAllowed(boolean interactionAllowed)
{
this.interactionAllowed = interactionAllowed;
refreshInteractionHandling();
}
/**
* @return the parentFrame
*/
public JFrame getParentFrame()
{
return parentFrame;
}
/**
* @param parentFrame the parentFrame to set
*/
public void setParentFrame(JFrame parentFrame)
{
this.parentFrame = parentFrame;
}
public void actionPerformed(ActionEvent evt)
{
log.fine("dispatching action event");
}
public void disconnect()
{
if (term != null)
{
term.disconnect();
}
}
/**
* Shuts the application down.
*/
public void exit()
{
exit(!embeddedUse);
}
public void exit(boolean exitVm)
{
if (exitVm)
{
//If a disconnected option is needed in embedded cases, it can be done manually
if (term != null)
{
term.disconnect();
}
System.exit(0);
}
if (getParentFrame() != null)
{
getParentFrame().dispose();
}
}
public void focusGained(FocusEvent evt)
{
rhp.requestFocus();
}
public void focusLost(FocusEvent evt)
{
}
public void processEvent(AWTEvent evt)
{
if (evt.getID() == Event.WINDOW_DESTROY)
{
exit();
}
super.processEvent(evt);
}
/**
* Builds main menu. Constructs several menu items.
*/
private void buildMainMenu()
{
JPanel pnlTools = new JPanel();
pnlTools.setLayout(new BorderLayout());
add("North", pnlTools);
menubar = new JMenuBar();
//setJMenuBar(menubar);
pnlTools.add("North", menubar);
toolbar = new JToolBar();
toolbar.setFloatable(false);
toolbar.setVisible("true".equals(OpenTermConfig.getProp("toolbar.fkey.enabled")));
pnlTools.add("Center", toolbar);
/* Make sure that the menu does not trap F10, since we use it as PF10 */
//TODO - probably want to do this also for Alt-F4 which acts as exit?
InputMap inputMap = menubar.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
inputMap.put(KeyStroke.getKeyStroke("F10"), "none");
JMenu file = new JMenu("Terminal");
AbstractAction prtAct = new AbstractAction("Print")
{
public void actionPerformed(ActionEvent evt)
{
rhp.printScreen();
}
};
file.add(prtAct);
menubar.getActionMap().put("PRINT", prtAct);
inputMap.put(KeyStroke.getKeyStroke("alt P"), "PRINT");
file.addSeparator();
file.add(new AbstractAction("Exit")
{
public void actionPerformed(ActionEvent evt)
{
exit();
}
});
menubar.add(file);
connect = new JMenu("Connect");
initHostsMenu();
menubar.add(connect);
JMenu options = new JMenu("Options");
JMenu fonts = new JMenu("Font Size");
ButtonGroup fontsGroup = new ButtonGroup();
int currFontSize = rhp.getFontSize();
for (int i = 0; i < FONT_SIZES.length; i++)
{
int size = FONT_SIZES[i];
JRadioButtonMenuItem sizeItem = new JRadioButtonMenuItem(new AbstractAction(Integer.toString(size))
{
public void actionPerformed(ActionEvent evt)
{
int size = Integer.parseInt(evt.getActionCommand());
fontSize((float) size);
}
});
if (size == currFontSize)
{
sizeItem.setSelected(true);
}
fonts.add(sizeItem);
fontsGroup.add(sizeItem);
}
options.add(fonts);
JMenu fontcolor = new JMenu("Font Color");
JMenu dfFontColor = getColorMenu("Default Font", JTerminalScreen.getFgColor(), new AbstractAction()
{
public void actionPerformed(ActionEvent evt)
{
String name = evt.getActionCommand();
rhp.setForegroundColor(name);
}
});
fontcolor.add(dfFontColor);
JMenu bldFontColor = getColorMenu("Bold Font", JTerminalScreen.getBoldColor(), new AbstractAction()
{
public void actionPerformed(ActionEvent evt)
{
String name = evt.getActionCommand();
rhp.setBoldColor(name);
}
});
fontcolor.add(bldFontColor);
options.add(fontcolor);
options.addSeparator();
JMenu bgcolor = getColorMenu("Background Color", JTerminalScreen.getBgColor(), new AbstractAction()
{
public void actionPerformed(ActionEvent evt)
{
String name = evt.getActionCommand();
rhp.setBackgroundColor(name);
}
});
options.add(bgcolor);
options.addSeparator();
JCheckBoxMenuItem optFkeyBar = new JCheckBoxMenuItem("Show F-Key bar");
optFkeyBar.setSelected("true".equals(OpenTermConfig.getProp("toolbar.fkey.enabled")));
optFkeyBar.addItemListener(new ItemListener()
{
@Override
public void itemStateChanged(ItemEvent e)
{
OpenTermConfig.setProp("toolbar.fkey.enabled", Boolean.toString(optFkeyBar.isSelected()));
//rhp.refresh();
toolbar.setVisible(optFkeyBar.isSelected());
pack();
}
});
options.add(optFkeyBar);
options.addSeparator();
options.add(new AbstractAction("Clear Saved Preferences")
{
public void actionPerformed(ActionEvent evt)
{
int n = JOptionPane.showConfirmDialog(null,
"Are you sure you want to clear all saved preferences?",
"Clear Preferences", JOptionPane.YES_NO_OPTION);
if (n == JOptionPane.YES_OPTION)
{
OpenTermConfig.clearPrefs();
}
}
});
menubar.add(options);
JMenu about = new JMenu("Help");
menubar.add(about);
about.add(new AbstractAction("About")
{
public void actionPerformed(ActionEvent evt)
{
AboutDialog about = new AboutDialog(null, productName);
about.setVisible(true);
}
});
// Not perfect as initially it shows a blank screen, but at least it can be made of an expected type
// Could be nicer to show something more "neutral"
if (term == null)
{
try
{
term = TerminalFactoryRegistrar.createTerminal(OpenTermConfig.getProp("startup.type").trim());
}
catch (Exception ex)
{
log.warning(ex.getLocalizedMessage());
}
}
rhp = new JTerminalScreen(term != null ? term : new Term3270(), toolbar);
if (!this.interactionAllowed)
{
// Just in case RHP was null when interactions originally disabled
refreshInteractionHandling();
}
add("Center", rhp);
}
private void refreshInteractionHandling()
{
if (rhp != null)
{
rhp.setKbdEnabled(interactionAllowed);
}
setMenusEnabled(interactionAllowed);
}
// Might at a later stage want to only disable certain menus
private void setMenusEnabled(boolean enabled)
{
if (menubar != null)
{
for (int ix = 0; ix < menubar.getMenuCount(); ix ++)
{
menubar.getMenu(ix).setEnabled(enabled);
}
}
}
private JMenu getColorMenu(String menuText, String selectedItemName, Action act)
{
JMenu color = new JMenu(menuText);
ButtonGroup colorGroup = new ButtonGroup();
for (int i = 0; i < COLOR_NAMES.length; i++)
{
String name = COLOR_NAMES[i];
JRadioButtonMenuItem colorItem = new JRadioButtonMenuItem(name);
colorItem.addActionListener(act);
if (COLOR_NAMES[i].equals(selectedItemName))
{
colorItem.setSelected(true);
}
color.add(colorItem);
colorGroup.add(colorItem);
}
return color;
}
private void fontSize(float size)
{
rhp.setFontSize(size);
revalidate();
repaint();
pack();
}
public void init(String host, int port, String type, boolean encryption)
{
log.fine("** host " + host);
available.add(new Host(host, port, type, encryption));
init();
}
/**
* Performs operations neccessary to construct main application frame.
*
* @param host DOCUMENT ME!
* @param port DOCUMENT ME!
* @param available DOCUMENT ME!
* @param parentFrame DOCUMENT ME!
*/
private void init()
{
productName = OpenTermConfig.getProp("product.name", "open.term");
setTitle(productName);
setLayout(new BorderLayout());
buildMainMenu();
validate();
repaint();
pack();
// Connect to the first host in the set of available hosts in
// case if there is only one host available
if (available.size() == 1 && autoConnect)
{
connect(available.get(0));
}
else
{
setTitle(productName + " - Not Connected");
}
addFocusListener(this);
}
protected void initHostsMenu()
{
connect.removeAll();
Iterator hosts = available.iterator();
//JMenuItem mnu = new JMenuItem();
//Font boldFont = menu.getFont().deriveFont(Font.BOLD);
while (hosts.hasNext())
{
final Host hst = hosts.next();
// quick hack for now - tooltips maybe neater
String menuTxt = hst.getDisplayName();
connect.add(new AbstractAction(menuTxt)
{
public void actionPerformed(ActionEvent evt)
{
disconnect();
try
{
connect(hst);
}
catch (Exception e)
{
showConnectionError(e.getMessage());
}
}
});
}
connect.add(new AbstractAction("New ...")
{
public void actionPerformed(ActionEvent evt)
{
NewHostDialog cfgDialog = new NewHostDialog();
cfgDialog.setVisible(true);
final Host newHost = cfgDialog.getHost();
if (newHost != null)
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
disconnect();
try
{
connect(newHost);
}
catch (Exception e)
{
showConnectionError(e.getMessage());
}
// Add to list regardless of connection success
if (newHost.isFavourite())
{
//TODO - could check if already present to avoid duplicates
available.add(newHost);
OpenTermConfig.setProp("favourite.hosts", Host.getFavouritesAsConfigString(available));
initHostsMenu();
}
}
});
rhp.requestFocusInWindow();
}
}
});
connect.addSeparator();
connect.add(new AbstractAction("Disconnect")
{
public void actionPerformed(ActionEvent evt)
{
disconnect();
}
});
connect.addSeparator();
connect.add(new AbstractAction("Organize Favourites")
{
public void actionPerformed(ActionEvent evt)
{
FavouriteHostsPanel pnlHost = new FavouriteHostsPanel(available);
int res = JOptionPane.showConfirmDialog(null, pnlHost, "Favourite Hosts",
JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
if (res == JOptionPane.OK_OPTION)
{
final List newHosts = pnlHost.getHosts();
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
available.clear();
available.addAll(newHosts);
OpenTermConfig.setProp("favourite.hosts", Host.getFavouritesAsConfigString(available));
initHostsMenu();
}
});
}
}
});
}
protected void connect(Host host)
{
log.fine("** connect " + host);
setTitle(productName + " - Connecting to " + host.getDisplayName());
try
{
term = TerminalFactoryRegistrar.createTerminal(host);
rhp.setTerminal(term);
repaint();
pack();
term.connect();
requestFocus();
setTitle(productName + " - Connected to " + host.getDisplayName());
}
catch (Exception e)
{
showConnectionError(e.getMessage());
}
}
private void showConnectionError(String message)
{
if (!serverMode)
{
JOptionPane.showMessageDialog(rhp, "Failed to connect to the server:\n" + message,
"Connection failure", JOptionPane.WARNING_MESSAGE);
}
else
{
log.warning("Failed establish connection to host: " + message);
}
}
//---------------------------------------
// Bit brain dead - these methods will update any parent JFrame
public void setTitle(String title)
{
if (getParentFrame() != null)
{
getParentFrame().setTitle(title);
}
}
public void pack()
{
if (getParentFrame() != null)
{
getParentFrame().pack();
}
}
public JTerminalScreen getTerminalScreen()
{
return rhp;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy