/*
* This file is part of Alida, a Java library for
* Advanced Library for Integrated Development of Data Analysis Applications.
*
* Copyright (C) 2010 - @YEAR@
*
* 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
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*
* Fore more information on Alida, visit
*
* http://www.informatik.uni-halle.de/alida/
*
*/
package de.unihalle.informatik.Alida.gui;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.lang.ref.WeakReference;
import de.unihalle.informatik.Alida.annotations.*;
import de.unihalle.informatik.Alida.annotations.ALDAOperator.Level;
import de.unihalle.informatik.Alida.gui.ALDOperatorChooserTreeNode;
import de.unihalle.informatik.Alida.helpers.ALDClassInfo;
import de.unihalle.informatik.Alida.helpers.ALDIcon;
import de.unihalle.informatik.Alida.operator.ALDOperatorLocation;
import de.unihalle.informatik.Alida.version.ALDVersionProviderFactory;
import de.unihalle.informatik.Alida.workflows.ALDWorkflowHelper;
/**
* Main window for selecting Alida annotated operators for running.
* For a selected operator a configuration window may be created by double clicking or
* hitting the configure button.
* <p>
* This class holds two different trees of operators, one for the standard level, one for
* the application level.
* These trees contain all <code>ALDAOperator</code> annotated operators allowed to be executed in a GUI,
* and annotated as <code>Level.STANDARD</code> and <code>Level.APPLICATION</code>, respectively.
* Deriving classes may override the method <code>additionalOperators</code> to extend the trees.
* <p>
* In deriving classes the method <code>getOpControlFrame</code> may be overridden to define a different
* frame to handle the configuration of the selected operator. The frame created in by
* <code>ALDChooseOpNameFrame</code> is
* {@link ALDOperatorControlFrame}.
*
* @author Stefan Posch
* @author Birgit Moeller
*/
public class ALDChooseOpNameFrame extends JFrame
implements ActionListener, TreeSelectionListener {
/**
* Debug flag (not accessible from outside).
*/
private boolean debug = false;
/**
* Location of recently selected operator.
*/
protected ALDOperatorLocation opLocation = null;
/**
* JComponent containing both trees of available operators.
*/
protected ALDOperatorChooserTree opTree;
/**
* Main panel of chooser window.
*/
protected JRootPane mainPanel;
/**
* Label to display selected operator.
*/
protected JLabel opNameJText;
/**
* Text field to enter filter to select operators
*/
protected JTextField filterField;
/**
* Scroll pane displaying the operator tree.
*/
protected JScrollPane opTreePane;
/**
* Title of frame.
*/
protected String titleString =
"Alida - OpRunner: simply choose an operator...";
/**
* List of active GUI managers.
*/
protected LinkedList<WeakReference<ALDOperatorGUIExecutionProxy>> guiProxys;
/**
* Constructor.
*/
public ALDChooseOpNameFrame() {
if ( this.debug )
System.out.println( " ALDChooseOpNameFrame instantiate");
// instantiate operator trees
Collection<ALDOperatorLocation> standardOps =
ALDClassInfo.lookupOperators(
ALDAOperator.Level.STANDARD, ALDAOperator.ExecutionMode.SWING);
standardOps.addAll( ALDWorkflowHelper.lookupWorkflows());
standardOps.addAll( additionalOperators( ALDAOperator.Level.STANDARD));
Collection<ALDOperatorLocation> allicationOps =
ALDClassInfo.lookupOperators(
ALDAOperator.Level.APPLICATION, ALDAOperator.ExecutionMode.SWING);
allicationOps.addAll( ALDWorkflowHelper.lookupWorkflows());
allicationOps.addAll( additionalOperators( ALDAOperator.Level.APPLICATION));
// init the operator chooser tree
this.opTree = new ALDOperatorChooserTree( standardOps, allicationOps);
MouseListener ml = new MyMouseAdapter();
this.opTree.addMouseListener(ml);
this.opTree.addTreeSelectionListener(this);
// init list of active GUI managers
this.guiProxys=
new LinkedList<WeakReference<ALDOperatorGUIExecutionProxy>>();
// global language settings
Locale.setDefault(Locale.ENGLISH);
JComponent.setDefaultLocale(Locale.ENGLISH);
// set up main window
this.mainPanel = new JRootPane();
BoxLayout ylayout = new BoxLayout( this.mainPanel, BoxLayout.Y_AXIS);
this.mainPanel.setLayout( ylayout);
this.opTreePane = new JScrollPane( this.opTree);
this.mainPanel.add(this.opTreePane,0);
// do some global settings
this.setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
// TODO Does this anything? -> if not, remove...
this.mainPanel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
// text field for operator filter
JButton buttonApplyFilter = new JButton("Apply Filter");
buttonApplyFilter.setActionCommand( "filter");
buttonApplyFilter.addActionListener(this);
// add panel for filtering operators
JPanel filterPanel = new JPanel();
filterPanel.add(new JLabel("Operator Filter:"));
this.filterField = new JTextField(20);
this.filterField.setActionCommand( "filter");
this.filterField.addActionListener(this);
filterPanel.add(this.filterField);
filterPanel.add(buttonApplyFilter);
filterPanel.add(Box.createRigidArea(new Dimension(10, 0)));
this.mainPanel.add(filterPanel);
// add panel for displaying selected operator
JLabel lab = new JLabel("Selected Operator: ");
this.opNameJText = new JLabel( "- none -");
JPanel selelectePanel = new JPanel();
selelectePanel.add( lab);
selelectePanel.add(Box.createRigidArea(new Dimension(10, 0)));
selelectePanel.add( this.opNameJText);
this.mainPanel.add( selelectePanel);
// add buttons
JButton configButton = new JButton("Configure Operator...");
configButton.setActionCommand( "execute");
configButton.addActionListener(this);
configButton.setBounds(50, 60, 80, 30);
configButton.setAlignmentX(Component.LEFT_ALIGNMENT);
JButton quitButton = new JButton("Quit");
quitButton.setActionCommand( "quit");
quitButton.addActionListener(this);
quitButton.setBounds(50, 60, 80, 30);
quitButton.setAlignmentX(Component.LEFT_ALIGNMENT);
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.LINE_AXIS));
buttonPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
buttonPanel.add(Box.createHorizontalGlue());
buttonPanel.add(configButton);
buttonPanel.add(Box.createRigidArea(new Dimension(10, 0)));
buttonPanel.add(quitButton);
this.mainPanel.add(buttonPanel);
// add a nice menu bar, file menu first
JMenuBar mainWindowMenu = new JMenuBar();
JMenu fileM = new JMenu("File");
JMenuItem quitItem = new JMenuItem("Quit");
quitItem.setActionCommand("quit");
quitItem.addActionListener(this);
fileM.add(quitItem);
// options menu
JMenu opSelectM = new JMenu("Options");
// ButtonGroup operatorLevelGroup = new ButtonGroup();
// // default
// JRadioButtonMenuItem radioItemApplication =
// new JRadioButtonMenuItem("Application");
// radioItemApplication.setActionCommand("viewApps");
// radioItemApplication.addActionListener(this);
// JRadioButtonMenuItem radioItemStandard =
// new JRadioButtonMenuItem("Standard");
// radioItemStandard.setActionCommand("viewStd");
// radioItemStandard.addActionListener(this);
// operatorLevelGroup.add(radioItemApplication);
// operatorLevelGroup.add(radioItemStandard);
// opSelectM.add(radioItemApplication);
// opSelectM.add(radioItemStandard);
//
// if ( this.opTree.getLevel() == Level.APPLICATION)
// radioItemApplication.setSelected(true);
// else
// radioItemStandard.setSelected(true);
JMenu operatorSet = new JMenu("Operators to Show");
ButtonGroup operatorSetGroup = new ButtonGroup();
JRadioButtonMenuItem radioItemApplication =
new JRadioButtonMenuItem("Default");
radioItemApplication.setToolTipText("<html>Shows operators to be used "
+ "out-of-the-box<br> and well-suited also for non-expert users.</html>");
radioItemApplication.setActionCommand("viewApps");
radioItemApplication.addActionListener(this);
JRadioButtonMenuItem radioItemAll =
new JRadioButtonMenuItem("All");
radioItemAll.setToolTipText("<html>Shows all operators including very"
+ " specialized<br> ones requiring advanced expert knowledge.</html>");
radioItemAll.setActionCommand("viewStd");
radioItemAll.addActionListener(this);
operatorSetGroup.add(radioItemApplication);
operatorSetGroup.add(radioItemAll);
operatorSet.add(radioItemApplication);
operatorSet.add(radioItemAll);
opSelectM.add(operatorSet);
// set correct initial display mode
if ( this.opTree.getLevel() == Level.APPLICATION)
radioItemApplication.setSelected(true);
else
radioItemAll.setSelected(true);
JMenu helpM = this.generateHelpMenu();
mainWindowMenu.add(fileM);
mainWindowMenu.add(opSelectM);
mainWindowMenu.add(Box.createHorizontalGlue());
mainWindowMenu.add(helpM);
// ... and go setup the frame
this.setTitle(this.titleString);
this.getContentPane().setPreferredSize(new Dimension(500, 700));
this.pack();
this.setJMenuBar(mainWindowMenu);
this.add(this.mainPanel);
this.setDefaultCloseOperation( DISPOSE_ON_CLOSE);
this.setVisible(true);
}
/** This method may be overridden in extending classes to add operators to the
* list of available operators.
*
* @param level Level to which operators are to be added
*/
protected Collection<ALDOperatorLocation> additionalOperators(
@SuppressWarnings("unused") ALDAOperator.Level level) {
return new LinkedList<ALDOperatorLocation>();
}
/**
* Sets up the help menu.
*
* @return Generated help menu.
*/
protected JMenu generateHelpMenu() {
JMenu helpM = new JMenu("Help");
JMenuItem itemHelp = new JMenuItem("Online Help");
JMenuItem itemAbout = new JMenuItem("About Alida");
itemHelp.addActionListener(
OnlineHelpDisplayer.getHelpActionListener(itemHelp,
"alida.guiOpRunner" ,this));
itemAbout.setActionCommand("showAbout");
itemAbout.addActionListener(this);
helpM.add(itemHelp);
helpM.add(itemAbout);
return helpM;
}
/**
* Show an about box window.
* <p>
* Method is supposed to be overwritten by subclasses.
*/
protected void showAboutBox() {
Object[] options = { "OK" };
String year = Integer.toString(Calendar.getInstance().get(Calendar.YEAR));
String rev = ALDVersionProviderFactory.getProviderInstance().getVersion();
if (rev.contains("=")) {
int equalSign = rev.indexOf("=");
int closingBracket = rev.lastIndexOf("]");
rev = rev.substring(0, equalSign + 9) + rev.substring(closingBracket);
}
String msg = "<html>Alida - Advanced Library for Integrated Development<p>"
+ "\t of Data Analysis Applications<p><p>"
+ "Release " + rev + "<p>" + "\u00a9 2010 - " + year + " "
+ "Martin Luther University Halle-Wittenberg<p>"
+ "Institute of Computer Science, Faculty of Natural Sciences III<p><p>"
+ "Email: mitobo@informatik.uni-halle.de<p>"
+ "Internet: <i>www.informatik.uni-halle.de/alida</i><p>"
+ "License: GPL 3.0, <i>http://www.gnu.org/licenses/gpl.html</i></html>";
JOptionPane.showOptionDialog(null, new JLabel(msg),
"Information about Alida", JOptionPane.DEFAULT_OPTION,
JOptionPane.INFORMATION_MESSAGE, ALDIcon.getInstance().getIcon(),
options, options[0]);
}
/**
* Executes the chosen operator, i.e. opens the config/control window.
* @param opLoc Location from where to instantiate the operator object.
*/
protected void executeOperator(ALDOperatorLocation opLoc) {
// do we have an operator name?
if (opLoc != null ) {
ALDOperatorGUIExecutionProxy execManager =
new ALDOperatorGUIExecutionProxy(opLoc);
this.guiProxys.add(
new WeakReference<ALDOperatorGUIExecutionProxy>(execManager));
execManager.showGUI();
}
}
/**
* Cleans-up on termination, e.g. closes all windows.
*/
protected void quit() {
// terminate all running GUI managers
boolean quitsOk = true;
for (WeakReference<ALDOperatorGUIExecutionProxy> guimRef: this.guiProxys) {
ALDOperatorGUIExecutionProxy guim = guimRef.get();
if (guim != null) {
quitsOk = quitsOk && guim.quit();
}
}
// close online help window
OnlineHelpDisplayer.closeWindow();
// close the chooser window itself
if (quitsOk)
this.dispose();
}
/* (non-Javadoc)
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
*/
@Override
public final void actionPerformed(ActionEvent e) {
// local variables
String command = e.getActionCommand();
// configure button has been pressed
if ( command.equals("execute") ) {
this.executeOperator(this.opLocation);
}
// quit button has been pressed
else if ( command.equals("quit") ) {
this.quit();
}
/* handle tree view options */
else if (command.equals("viewApps")) {
this.opTree.setLevel( ALDAOperator.Level.APPLICATION);
}
else if (command.equals("viewStd")) {
this.opTree.setLevel( ALDAOperator.Level.STANDARD);
}
/* display about box */
else if (command.equals("showAbout")) {
showAboutBox();
}
/* operator name filter */
else if (command.equals("filter")) {
this.opTree.setOpNameFilter( this.filterField.getText());
}
}
@Override
public void valueChanged(TreeSelectionEvent event) {
ALDOperatorChooserTreeNode node =
this.opTree.getLastSelectedPathComponent();
// if sub-tree has been folded in, last selected node is null -
// do nothing in that case
if (node == null)
return;
if (node.isOperator()) {
this.opLocation = node.getLocation(); //new String(node.getFullName());
// this.opName = this.opTree.getLastSelectedPathComponent().toString();
this.opNameJText.setText(
this.opTree.getLastSelectedPathComponent().toString());
this.opNameJText.setToolTipText(node.getLocation().getName());
} else {
this.opLocation = null;
// this.opName = null;
}
}
/**
* Local {@link MouseAdapter} class.
* <p>
* Handles double click on operator name to execute it.
*
* @author posch
*/
protected class MyMouseAdapter extends MouseAdapter {
/**
* Constructor.
*/
public MyMouseAdapter() {
// nothing to do here
}
@Override
public void mousePressed(MouseEvent e) {
int selRow =
ALDChooseOpNameFrame.this.opTree.getRowForLocation(e.getX(), e.getY());
if(selRow != -1) {
if(e.getClickCount() == 2) {
ALDOperatorChooserTreeNode node =
ALDChooseOpNameFrame.this.opTree.getLastSelectedPathComponent();
if ( node.isOperator() ) {
// do some changes in chooser frame
ALDChooseOpNameFrame.this.opLocation = node.getLocation();
ALDChooseOpNameFrame.this.opNameJText.setText(node.toString());
ALDChooseOpNameFrame.this.opNameJText.setToolTipText(
node.getLocation().getName());
ALDChooseOpNameFrame.this.executeOperator(node.getLocation());
}
}
}
}
}
}