source: src/main/java/weka/gui/beans/KnowledgeFlowApp.java @ 9

Last change on this file since 9 was 4, checked in by gnappo, 14 years ago

Import di weka.

File size: 109.5 KB
RevLine 
[4]1/*
2 *    This program is free software; you can redistribute it and/or modify
3 *    it under the terms of the GNU General Public License as published by
4 *    the Free Software Foundation; either version 2 of the License, or
5 *    (at your option) any later version.
6 *
7 *    This program is distributed in the hope that it will be useful,
8 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
9 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 *    GNU General Public License for more details.
11 *
12 *    You should have received a copy of the GNU General Public License
13 *    along with this program; if not, write to the Free Software
14 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
15 */
16
17/*
18 *    KnowledgeFlowApp.java
19 *    Copyright (C) 2005 University of Waikato, Hamilton, New Zealand
20 *
21 */
22
23package weka.gui.beans;
24
25import weka.core.ClassloaderUtil;
26import weka.core.Copyright;
27import weka.core.Environment;
28import weka.core.EnvironmentHandler;
29import weka.core.Memory;
30import weka.core.SerializedObject;
31import weka.core.Utils;
32import weka.core.xml.KOML;
33import weka.core.xml.XStream;
34import weka.gui.ExtensionFileFilter;
35import weka.gui.GenericObjectEditor;
36import weka.gui.GenericPropertiesCreator;
37import weka.gui.HierarchyPropertyParser;
38import weka.gui.LookAndFeel;
39import weka.gui.beans.xml.XMLBeans;
40import weka.gui.visualize.PrintablePanel;
41
42import java.awt.BorderLayout;
43import java.awt.Cursor;
44import java.awt.Dimension;
45import java.awt.Font;
46import java.awt.FontMetrics;
47import java.awt.Graphics;
48import java.awt.Graphics2D;
49import java.awt.GridLayout;
50import java.awt.Image;
51import java.awt.MenuItem;
52import java.awt.Point;
53import java.awt.PopupMenu;
54import java.awt.Rectangle;
55import java.awt.Toolkit;
56import java.awt.event.ActionEvent;
57import java.awt.event.ActionListener;
58import java.awt.event.InputEvent;
59import java.awt.event.MouseAdapter;
60import java.awt.event.MouseEvent;
61import java.awt.event.MouseMotionAdapter;
62import java.awt.image.BufferedImage;
63import java.beans.BeanInfo;
64import java.beans.Beans;
65import java.beans.Customizer;
66import java.beans.EventSetDescriptor;
67import java.beans.IntrospectionException;
68import java.beans.Introspector;
69import java.beans.MethodDescriptor;
70import java.beans.PropertyChangeEvent;
71import java.beans.PropertyChangeListener;
72import java.beans.beancontext.BeanContextChild;
73import java.beans.beancontext.BeanContextSupport;
74import java.io.File;
75import java.io.FileInputStream;
76import java.io.FileOutputStream;
77import java.io.IOException;
78import java.io.InputStream;
79import java.io.InputStreamReader;
80import java.io.LineNumberReader;
81import java.io.ObjectInputStream;
82import java.io.ObjectOutputStream;
83import java.io.OutputStream;
84import java.lang.reflect.Method;
85import java.text.SimpleDateFormat;
86import java.util.ArrayList;
87import java.util.Date;
88import java.util.Enumeration;
89import java.util.Hashtable;
90import java.util.Iterator;
91import java.util.Properties;
92import java.util.StringTokenizer;
93import java.util.TreeMap;
94import java.util.Vector;
95
96import javax.swing.Box;
97import javax.swing.ButtonGroup;
98import javax.swing.ImageIcon;
99import javax.swing.JButton;
100import javax.swing.JComponent;
101import javax.swing.JFileChooser;
102import javax.swing.JFrame;
103import javax.swing.JLabel;
104import javax.swing.JOptionPane;
105import javax.swing.JPanel;
106import javax.swing.JScrollPane;
107import javax.swing.JTabbedPane;
108import javax.swing.JTextArea;
109import javax.swing.JToggleButton;
110import javax.swing.JToolBar;
111import javax.swing.JWindow;
112import javax.swing.filechooser.FileFilter;
113
114/**
115 * Main GUI class for the KnowledgeFlow. Modifications to allow interoperability
116 * with swt provided by Davide Zerbetto (davide dot zerbetto at eng dot it).
117 *
118 * @author Mark Hall
119 * @version  $Revision: 6140 $
120 * @since 1.0
121 * @see JPanel
122 * @see PropertyChangeListener
123 */
124public class KnowledgeFlowApp
125  extends JPanel
126  implements PropertyChangeListener {
127
128  /** for serialization */
129  private static final long serialVersionUID = -7064906770289728431L;
130
131  /**
132   * Location of the property file for the KnowledgeFlowApp
133   */
134  protected static String PROPERTY_FILE = "weka/gui/beans/Beans.props";
135
136  /** Contains the editor properties */
137  protected static Properties BEAN_PROPERTIES;
138
139  private static ArrayList<Properties> BEAN_PLUGINS_PROPERTIES;
140
141  /**
142   * Holds the details needed to construct button bars for various supported
143   * classes of weka algorithms/tools
144   */
145  private static Vector TOOLBARS = new Vector();
146
147  /**
148   * Loads KnowledgeFlow properties and any plugins (adds jars to
149   * the classpath)
150   */
151  public static void loadProperties() {
152    if (BEAN_PROPERTIES == null) {
153      System.out.println("[KnowledgeFlow] Loading properties and plugins...");
154      /** Loads the configuration property file */
155      //  static {
156      // Allow a properties file in the current directory to override
157      try {
158        BEAN_PROPERTIES = Utils.readProperties(PROPERTY_FILE);
159        java.util.Enumeration keys =
160          (java.util.Enumeration)BEAN_PROPERTIES.propertyNames();
161        if (!keys.hasMoreElements()) {
162          throw new Exception( "Could not read a configuration file for the bean\n"
163                               +"panel. An example file is included with the Weka distribution.\n"
164                               +"This file should be named \"" + PROPERTY_FILE + "\" and\n"
165                               +"should be placed either in your user home (which is set\n"
166                               + "to \"" + System.getProperties().getProperty("user.home") + "\")\n"
167                               + "or the directory that java was started from\n");
168        }
169      } catch (Exception ex) {
170        JOptionPane.showMessageDialog(null,
171                                      ex.getMessage(),
172                                      "KnowledgeFlow",
173                                      JOptionPane.ERROR_MESSAGE);
174      }
175
176
177      // try and load any plugin beans properties
178      File pluginDir = new File(System.getProperty("user.home")
179                                +File.separator+".knowledgeFlow"
180                                +File.separator+"plugins");
181      if (pluginDir.exists() && pluginDir.isDirectory()) {
182        BEAN_PLUGINS_PROPERTIES = new ArrayList<Properties>();
183        // How many sub-dirs are there?
184        File[] contents = pluginDir.listFiles();
185        for (int i = 0; i < contents.length; i++) {
186          if (contents[i].isDirectory() && 
187              contents[i].listFiles().length > 0) {
188            try {     
189              Properties tempP = new Properties();
190              File propFile = new File(contents[i].getPath()
191                                       + File.separator
192                                       + "Beans.props");
193              tempP.load(new FileInputStream(propFile));
194              BEAN_PLUGINS_PROPERTIES.add(tempP);
195
196              // Now try and add all jar files in this directory to the classpath
197              File anyJars[] = contents[i].listFiles();
198              for (int j = 0; j < anyJars.length; j++) {
199                if (anyJars[j].getPath().endsWith(".jar")) {
200                  System.out.println("[KnowledgeFlow] Plugins: adding "+anyJars[j].getPath()
201                                     +" to classpath...");
202                  ClassloaderUtil.addFile(anyJars[j].getPath());
203                }
204              }
205            } catch (Exception ex) {
206              // Don't make a fuss
207              System.err.println("[KnowledgeFlow] Warning: Unable to load bean properties for plugin "
208                                 +"directory: " + contents[i].getPath());
209            }
210          }
211          //        BEAN_PLUGINS_PROPERTIES = new Properties();
212          //        BEAN_PLUGINS_PROPERTIES.load(new FileInputStream(pluginDir));
213        }
214      } else {
215        // make the plugin directory for the user
216        pluginDir.mkdir();
217      }
218    }
219  }
220
221  /**
222   * Initializes the temporary files necessary to construct the toolbars
223   * from.
224   */
225  private static void init() {
226    System.out.println("[KnowledgeFlow] Initializing KF...");
227
228    try {
229      TreeMap wrapList = new TreeMap();
230      GenericPropertiesCreator creator = new GenericPropertiesCreator();
231      Properties GEOProps = null;
232
233      if (creator.useDynamic()) {
234        creator.execute(false);
235        /* now process the keys in the GenericObjectEditor.props. For each
236           key that has an entry in the Beans.props associating it with a
237           bean component a button tool bar will be created */
238        GEOProps = creator.getOutputProperties();
239      } else {
240        // Read the static information from the GenericObjectEditor.props
241        GEOProps = Utils.readProperties("weka/gui/GenericObjectEditor.props");
242      }
243      Enumeration en = GEOProps.propertyNames();
244      while (en.hasMoreElements()) {
245        String geoKey = (String)en.nextElement();
246
247        // try to match this key with one in the Beans.props file
248        String beanCompName = BEAN_PROPERTIES.getProperty(geoKey);
249        if (beanCompName != null) {
250          // add details necessary to construct a button bar for this class
251          // of algorithms
252          Vector newV = new Vector();
253          // check for a naming alias for this toolbar
254          String toolBarNameAlias = 
255            BEAN_PROPERTIES.getProperty(geoKey+".alias");
256          String toolBarName = (toolBarNameAlias != null) ?
257            toolBarNameAlias :
258            geoKey.substring(geoKey.lastIndexOf('.')+1, geoKey.length());
259
260          // look for toolbar ordering information for this wrapper type
261          String order = 
262            BEAN_PROPERTIES.getProperty(geoKey+".order");
263          Integer intOrder = (order != null) ?
264            new Integer(order) :
265            new Integer(0);
266           
267          // Name for the toolbar (name of weka algorithm class)
268          newV.addElement(toolBarName);
269          // Name of bean capable of handling this class of algorithm
270          newV.addElement(beanCompName);
271
272          // add the root package for this key
273          String rootPackage = geoKey.substring(0, geoKey.lastIndexOf('.'));
274
275          newV.addElement(rootPackage);
276
277          // All the weka algorithms of this class of algorithm
278          String wekaAlgs = GEOProps.getProperty(geoKey);
279
280          Hashtable roots = GenericObjectEditor.sortClassesByRoot(wekaAlgs);
281          Hashtable hpps = new Hashtable();
282          Enumeration enm = roots.keys();
283          while (enm.hasMoreElements()) {
284            String root = (String) enm.nextElement();
285            String classes = (String) roots.get(root);
286            weka.gui.HierarchyPropertyParser hpp = 
287              new weka.gui.HierarchyPropertyParser();
288            hpp.build(classes, ", ");
289            //            System.err.println(hpp.showTree());
290            hpps.put(root, hpp);
291          }
292
293          //------ test the HierarchyPropertyParser
294          /*  weka.gui.HierarchyPropertyParser hpp =
295            new weka.gui.HierarchyPropertyParser();
296          hpp.build(wekaAlgs, ", ");
297
298          System.err.println(hpp.showTree()); */
299          // ----- end test the HierarchyPropertyParser
300          //      newV.addElement(hpp); // add the hierarchical property parser
301          newV.addElement(hpps); // add the hierarchical property parser
302
303          StringTokenizer st = new StringTokenizer(wekaAlgs, ", ");
304          while (st.hasMoreTokens()) {
305            String current = st.nextToken().trim();
306            newV.addElement(current);
307          }
308          wrapList.put(intOrder, newV);
309          //      TOOLBARS.addElement(newV);
310        }
311      }
312      Iterator keysetIt = wrapList.keySet().iterator();
313      while (keysetIt.hasNext()) {
314        Integer key = (Integer)keysetIt.next();
315        Vector newV = (Vector)wrapList.get(key);
316        if (newV != null) {
317          TOOLBARS.addElement(newV);
318        }
319      }
320    } catch (Exception ex) {
321      JOptionPane.showMessageDialog(null,
322          "Could not read a configuration file for the generic objecte editor"
323         +". An example file is included with the Weka distribution.\n"
324         +"This file should be named \"GenericObjectEditor.props\" and\n"
325         +"should be placed either in your user home (which is set\n"
326         + "to \"" + System.getProperties().getProperty("user.home") + "\")\n"
327         + "or the directory that java was started from\n",
328         "KnowledgeFlow",
329         JOptionPane.ERROR_MESSAGE);
330    }
331
332    try {
333      String standardToolBarNames = 
334        BEAN_PROPERTIES.
335        getProperty("weka.gui.beans.KnowledgeFlow.standardToolBars");
336      StringTokenizer st = new StringTokenizer(standardToolBarNames, ", ");
337       while (st.hasMoreTokens()) {
338         String tempBarName = st.nextToken().trim();
339         // construct details for this toolbar
340         Vector newV = new Vector();
341         // add the name of the toolbar
342         newV.addElement(tempBarName);
343
344         // indicate that this is a standard toolbar (no wrapper bean)
345         newV.addElement("null");
346         String toolBarContents = 
347           BEAN_PROPERTIES.
348           getProperty("weka.gui.beans.KnowledgeFlow."+tempBarName);
349         StringTokenizer st2 = new StringTokenizer(toolBarContents, ", ");
350         while (st2.hasMoreTokens()) {
351           String tempBeanName = st2.nextToken().trim();
352           newV.addElement(tempBeanName);
353         }
354         TOOLBARS.addElement(newV);
355       }       
356    } catch (Exception ex) {
357      JOptionPane.showMessageDialog(null,
358                                    ex.getMessage(),
359                                    "KnowledgeFlow",
360                                    JOptionPane.ERROR_MESSAGE);
361    }
362  } 
363 
364  /**
365   * Used for displaying the bean components and their visible
366   * connections
367   *
368   * @author <a href="mailto:mhall@cs.waikato.ac.nz">Mark Hall</a>
369   * @version $Revision: 6140 $
370   * @since 1.0
371   * @see PrintablePanel
372   */
373  protected class BeanLayout
374    extends PrintablePanel {
375
376    /** for serialization */
377    private static final long serialVersionUID = -146377012429662757L;
378
379    public void paintComponent(Graphics gx) {
380      super.paintComponent(gx);
381      BeanInstance.paintLabels(gx);
382      BeanConnection.paintConnections(gx);
383      //      BeanInstance.paintConnections(gx);
384      if (m_mode == CONNECTING) {
385        gx.drawLine(m_startX, m_startY, m_oldX, m_oldY);
386      } else if (m_mode == SELECTING) {
387        gx.drawRect((m_startX < m_oldX) ? m_startX : m_oldX, 
388                    (m_startY < m_oldY) ? m_startY : m_oldY, 
389                    Math.abs(m_oldX-m_startX), Math.abs(m_oldY-m_startY));
390      }
391    }
392
393    public void doLayout() {
394      super.doLayout();
395      Vector comps = BeanInstance.getBeanInstances();
396      for (int i = 0; i < comps.size(); i++) {
397        BeanInstance bi = (BeanInstance)comps.elementAt(i);
398        JComponent c = (JComponent)bi.getBean();
399        Dimension d = c.getPreferredSize();
400        c.setBounds(bi.getX(), bi.getY(), d.width, d.height);
401        c.revalidate();
402      }
403    }
404  }
405
406  // Used for measuring and splitting icon labels
407  // over multiple lines
408  FontMetrics m_fontM;
409
410  // constants for operations in progress
411  protected static final int NONE = 0;
412  protected static final int MOVING = 1;
413  protected static final int CONNECTING = 2;
414  protected static final int ADDING = 3;
415  protected static final int SELECTING = 4;
416
417  // which operation is in progress
418  private int m_mode = NONE;
419
420  /** the extension for the user components, when serialized to XML */
421  protected final static String USERCOMPONENTS_XML_EXTENSION = ".xml";
422 
423  /**
424   * Button group to manage all toolbar buttons
425   */
426  private ButtonGroup m_toolBarGroup = new ButtonGroup();
427
428  /**
429   * Holds the selected toolbar bean
430   */
431  private Object m_toolBarBean;
432
433  /**
434   * The layout area
435   */
436  private BeanLayout m_beanLayout = new BeanLayout();
437
438  /**
439   * Tabbed pane to hold tool bars
440   */
441  private JTabbedPane m_toolBars = new JTabbedPane();
442
443  /**
444   * Stuff relating to plugin beans
445   */
446  private JToolBar m_pluginsToolBar = null;
447  private Box m_pluginsBoxPanel = null;
448 
449  /**
450   * Stuff relating to user created meta beans
451   */
452  private JToolBar m_userToolBar = null;
453  private Box m_userBoxPanel = null;
454  private Vector m_userComponents = new Vector();
455  private boolean m_firstUserComponentOpp = true;
456
457  private JToggleButton m_pointerB;
458  private JButton m_saveB;
459  private JButton m_loadB;
460  private JButton m_stopB;
461  private JButton m_helpB;
462  private JButton m_newB;
463
464  /**
465   * Reference to bean being manipulated
466   */
467  private BeanInstance m_editElement;
468
469  /**
470   * Event set descriptor for the bean being manipulated
471   */
472  private EventSetDescriptor m_sourceEventSetDescriptor;
473
474  /**
475   * Used to record screen coordinates during move, select and connect
476   * operations
477   */
478  private int m_oldX, m_oldY;
479  private int m_startX, m_startY;
480 
481  /** The file chooser for selecting layout files */
482  protected JFileChooser m_FileChooser
483    = new JFileChooser(new File(System.getProperty("user.dir")));
484
485  protected LogPanel m_logPanel = new LogPanel();//new LogPanel(null, true);
486
487  protected BeanContextSupport m_bcSupport = new BeanContextSupport();
488
489  /** the extension for the serialized setups (Java serialization) */
490  public final static String FILE_EXTENSION = ".kf";
491
492  /** the extension for the serialized setups (Java serialization) */
493  public final static String FILE_EXTENSION_XML = ".kfml";
494 
495  /** A filter to ensure only KnowledgeFlow files in binary format get shown in
496      the chooser */
497  protected FileFilter m_KfFilter = 
498    new ExtensionFileFilter(FILE_EXTENSION, 
499                            "Binary KnowledgeFlow configuration files (*" 
500                            + FILE_EXTENSION + ")");
501
502  /** A filter to ensure only KnowledgeFlow files in KOML format
503      get shown in the chooser */
504  protected FileFilter m_KOMLFilter = 
505    new ExtensionFileFilter(KOML.FILE_EXTENSION + "kf", 
506                            "XML KnowledgeFlow configuration files (*" 
507                            + KOML.FILE_EXTENSION + "kf)");
508
509  /** A filter to ensure only KnowledgeFlow files in XStream format
510      get shown in the chooser */
511  protected FileFilter m_XStreamFilter = 
512    new ExtensionFileFilter(XStream.FILE_EXTENSION + "kf", 
513                            "XML KnowledgeFlow configuration files (*" 
514                            + XStream.FILE_EXTENSION + "kf)");
515
516  /** A filter to ensure only KnowledgeFlow layout files in XML format get
517      shown in the chooser */
518  protected FileFilter m_XMLFilter = 
519    new ExtensionFileFilter(FILE_EXTENSION_XML, 
520                            "XML KnowledgeFlow layout files (*" 
521                            + FILE_EXTENSION_XML + ")");
522
523  /** the scrollbar increment of the layout scrollpane */
524  protected int m_ScrollBarIncrementLayout = 20;
525
526  /** the scrollbar increment of the components scrollpane */
527  protected int m_ScrollBarIncrementComponents = 50;
528
529  /** the flow layout width */
530  protected int m_FlowWidth = 1024;
531
532  /** the flow layout height */
533  protected int m_FlowHeight = 768;
534
535  /** the preferred file extension */
536  protected String m_PreferredExtension = FILE_EXTENSION;
537 
538  /** whether to store the user components in XML or in binary format */
539  protected boolean m_UserComponentsInXML = false;
540 
541  /** Environment variables for the current flow */
542  protected Environment m_flowEnvironment = new Environment();
543 
544  /**
545   * Set the environment variables to use. NOTE: loading a new layout
546   * resets back to the default set of variables
547   *
548   * @param env
549   */
550  public void setEnvironment(Environment env) {
551    m_flowEnvironment = env;
552    setEnvironment();
553  }
554 
555  private void setEnvironment() {
556    // pass m_flowEnvironment to all components
557    // that implement EnvironmentHandler
558    Vector beans = BeanInstance.getBeanInstances();
559    for (int i = 0; i < beans.size(); i++) {
560      Object temp = ((BeanInstance) beans.elementAt(i)).getBean();
561
562      if (temp instanceof EnvironmentHandler) {
563        ((EnvironmentHandler) temp).setEnvironment(m_flowEnvironment);
564      }
565    }
566  }
567 
568  /**
569   * Creates a new <code>KnowledgeFlowApp</code> instance.
570   */
571  // modifications by Zerbetto
572  //public KnowledgeFlowApp() {
573  public KnowledgeFlowApp(boolean showFileMenu) {
574    if (BEAN_PROPERTIES == null) {
575      loadProperties();
576      init();
577    }
578
579    m_showFileMenu = showFileMenu;
580
581    // end modifications by Zerbetto
582    // Grab a fontmetrics object
583    JWindow temp = new JWindow();
584    temp.setVisible(true);
585    temp.getGraphics().setFont(new Font(null, Font.PLAIN, 9));
586    m_fontM = temp.getGraphics().getFontMetrics();
587    temp.setVisible(false);
588
589    // some GUI defaults
590    try {
591      m_ScrollBarIncrementLayout = Integer.parseInt(
592          BEAN_PROPERTIES.getProperty(
593            "ScrollBarIncrementLayout", "" + m_ScrollBarIncrementLayout));
594      m_ScrollBarIncrementComponents = Integer.parseInt(
595          BEAN_PROPERTIES.getProperty(
596            "ScrollBarIncrementComponents", "" + m_ScrollBarIncrementComponents));
597      m_FlowWidth = Integer.parseInt(
598          BEAN_PROPERTIES.getProperty(
599            "FlowWidth", "" + m_FlowWidth));
600      m_FlowHeight = Integer.parseInt(
601          BEAN_PROPERTIES.getProperty(
602            "FlowHeight", "" + m_FlowHeight));
603      m_PreferredExtension = BEAN_PROPERTIES.getProperty(
604          "PreferredExtension", m_PreferredExtension);
605      m_UserComponentsInXML = Boolean.valueOf(
606          BEAN_PROPERTIES.getProperty(
607            "UserComponentsInXML", "" + m_UserComponentsInXML)).booleanValue();
608    }
609    catch (Exception ex) {
610      ex.printStackTrace();
611    }
612
613    // FileChooser
614    m_FileChooser.addChoosableFileFilter(m_KfFilter);
615    if (KOML.isPresent()) {
616      m_FileChooser.addChoosableFileFilter(m_KOMLFilter);
617    }
618    if (XStream.isPresent()) {
619      m_FileChooser.addChoosableFileFilter(m_XStreamFilter);
620    }
621
622    m_FileChooser.addChoosableFileFilter(m_XMLFilter);
623
624    if (m_PreferredExtension.equals(FILE_EXTENSION_XML)) {
625      m_FileChooser.setFileFilter(m_XMLFilter);
626    } else if (KOML.isPresent() && m_PreferredExtension.equals(KOML.FILE_EXTENSION + "kf")) {
627      m_FileChooser.setFileFilter(m_KOMLFilter);
628    } else if (XStream.isPresent() && m_PreferredExtension.equals(XStream.FILE_EXTENSION + "kf")) {
629      m_FileChooser.setFileFilter(m_XStreamFilter);
630    } else {
631      m_FileChooser.setFileFilter(m_KfFilter);
632    }
633    m_FileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
634
635    m_bcSupport.setDesignTime(true);
636    m_beanLayout.setLayout(null);
637   
638    // handle mouse events
639    m_beanLayout.addMouseListener(new MouseAdapter() {
640
641        public void mousePressed(MouseEvent me) {
642          if (m_toolBarBean == null) {
643            if (((me.getModifiers() & InputEvent.BUTTON1_MASK)
644                 == InputEvent.BUTTON1_MASK) && m_mode == NONE) {
645              BeanInstance bi = BeanInstance.findInstance(me.getPoint());
646              JComponent bc = null;
647              if (bi != null) {
648                bc = (JComponent)(bi.getBean());
649              }
650              if (bc != null && (bc instanceof Visible)) {
651                m_editElement = bi;
652                m_oldX = me.getX();
653                m_oldY = me.getY();
654                m_mode = MOVING;
655              }
656              if (m_mode != MOVING) {
657                m_mode = SELECTING;
658                m_oldX = me.getX();
659                m_oldY = me.getY();
660                m_startX = m_oldX;
661                m_startY = m_oldY;
662                Graphics2D gx = (Graphics2D)m_beanLayout.getGraphics();
663                gx.setXORMode(java.awt.Color.white);
664                //                gx.drawRect(m_oldX, m_oldY, m_oldX, m_oldY);
665                //                gx.drawLine(m_startX, m_startY, m_startX, m_startY);
666                gx.dispose();
667                m_mode = SELECTING;
668              }
669            }
670          }
671        }
672
673        public void mouseReleased(MouseEvent me) {
674          if (m_editElement != null && m_mode == MOVING) {
675            m_editElement = null;
676            revalidate();
677            m_beanLayout.repaint();
678            m_mode = NONE;
679          }
680          if (m_mode == SELECTING) {
681            revalidate();
682            m_beanLayout.repaint();
683            m_mode = NONE;
684                       
685            checkSubFlow(m_startX, m_startY, me.getX(), me.getY());
686          }
687        }
688
689        public void mouseClicked(MouseEvent me) {
690          BeanInstance bi = BeanInstance.findInstance(me.getPoint());
691          if (m_mode == ADDING || m_mode == NONE) {
692            // try and popup a context sensitive menu if we have
693            // been clicked over a bean.
694            if (bi != null) {
695              JComponent bc = (JComponent)bi.getBean();
696              // if we've been double clicked, then popup customizer
697              // as long as we're not a meta bean
698              if (me.getClickCount() == 2 && !(bc instanceof MetaBean)) {
699                try {
700                  Class custClass = 
701                    Introspector.getBeanInfo(bc.getClass()).getBeanDescriptor().getCustomizerClass();
702                  if (custClass != null) {
703                    if (bc instanceof BeanCommon) {
704                      if (!((BeanCommon)bc).
705                          isBusy()) {
706                        popupCustomizer(custClass, bc);
707                      }
708                    } else {
709                      popupCustomizer(custClass, bc);
710                    }
711                  }
712                } catch (IntrospectionException ex) {
713                  ex.printStackTrace();
714                }
715              } else if (((me.getModifiers() & InputEvent.BUTTON1_MASK)
716                          != InputEvent.BUTTON1_MASK) || me.isAltDown()) {
717                doPopup(me.getPoint(), bi, me.getX(), me.getY());
718              }
719            } else {
720              if (((me.getModifiers() & InputEvent.BUTTON1_MASK)
721                   != InputEvent.BUTTON1_MASK) || me.isAltDown()) {
722                // find connections if any close to this point
723                int delta = 10;
724                deleteConnectionPopup(BeanConnection.
725                      getClosestConnections(new Point(me.getX(), me.getY()), 
726                                            delta), me.getX(), me.getY());
727              } else if (m_toolBarBean != null) {
728                // otherwise, if a toolbar button is active then
729                // add the component
730                addComponent(me.getX(), me.getY());
731              }
732            }
733          }
734       
735          if (m_mode == CONNECTING) {
736            // turn off connecting points and remove connecting line
737            m_beanLayout.repaint();
738            Vector beanInstances = BeanInstance.getBeanInstances();
739            for (int i = 0; i < beanInstances.size(); i++) {
740              JComponent bean = 
741                (JComponent)((BeanInstance)beanInstances.elementAt(i)).
742                getBean();
743              if (bean instanceof Visible) {
744                ((Visible)bean).getVisual().setDisplayConnectors(false);
745              }
746            }
747
748            if (bi != null) {
749              boolean doConnection = false;
750              if (!(bi.getBean() instanceof BeanCommon)) {
751                doConnection = true;
752              } else {
753                // Give the target bean a chance to veto the proposed
754                // connection
755                if (((BeanCommon)bi.getBean()).
756                    //connectionAllowed(m_sourceEventSetDescriptor.getName())) {
757                    connectionAllowed(m_sourceEventSetDescriptor)) {
758                  doConnection = true;
759                }
760              }
761              if (doConnection) {
762                // attempt to connect source and target beans
763
764                if (bi.getBean() instanceof MetaBean) {
765                  BeanConnection.doMetaConnection(m_editElement, bi,
766                                                  m_sourceEventSetDescriptor,
767                                                  m_beanLayout);
768                } else {
769                  BeanConnection bc = 
770                    new BeanConnection(m_editElement, bi, 
771                                       m_sourceEventSetDescriptor);
772                }
773              }
774              m_beanLayout.repaint();
775            }
776            m_mode = NONE;
777            m_editElement = null;
778            m_sourceEventSetDescriptor = null;
779          }
780        }
781      });
782   
783     m_beanLayout.addMouseMotionListener(new MouseMotionAdapter() {
784
785        public void mouseDragged(MouseEvent me) {
786          if (m_editElement != null && m_mode == MOVING) {
787            ImageIcon ic = ((Visible)m_editElement.getBean()).
788              getVisual().getStaticIcon();
789            int width = ic.getIconWidth() / 2;
790            int height = ic.getIconHeight() / 2;
791
792            /*      m_editElement.setX(m_oldX-width);
793                    m_editElement.setY(m_oldY-height); */
794
795            m_editElement.setXY(m_oldX-width,
796                                m_oldY-height);
797            m_beanLayout.repaint();
798           
799            // note the new points
800            m_oldX = me.getX(); m_oldY = me.getY();
801          }
802          if (m_mode == SELECTING) {
803            m_beanLayout.repaint();
804            m_oldX = me.getX(); m_oldY = me.getY();
805          }
806        }
807
808         public void mouseMoved(MouseEvent e) {
809           if (m_mode == CONNECTING) {
810             m_beanLayout.repaint();
811             // note the new coordinates
812             m_oldX = e.getX(); m_oldY = e.getY();
813           }
814         }
815       });
816     
817     String date = (new SimpleDateFormat("EEEE, d MMMM yyyy"))
818       .format(new Date());
819     m_logPanel.logMessage("Weka Knowledge Flow was written by Mark Hall");
820     m_logPanel.logMessage("Weka Knowledge Flow");
821     m_logPanel.logMessage("(c) 2002-" + Copyright.getToYear() + " " 
822         + Copyright.getOwner() + ", " + Copyright.getAddress());
823     m_logPanel.logMessage("web: " + Copyright.getURL());
824     m_logPanel.logMessage( date);
825     m_logPanel.statusMessage("[KnowledgeFlow]|Welcome to the Weka Knowledge Flow");
826     m_logPanel.getStatusTable().addMouseListener(new MouseAdapter() {
827       public void mouseClicked(MouseEvent e) {
828         if (m_logPanel.getStatusTable().rowAtPoint(e.getPoint()) == 0) {
829           if (((e.getModifiers() & InputEvent.BUTTON1_MASK)
830               != InputEvent.BUTTON1_MASK) || e.isAltDown()) {
831             System.gc();
832             Runtime currR = Runtime.getRuntime();
833             long freeM = currR.freeMemory();
834             long totalM = currR.totalMemory();
835             long maxM = currR.maxMemory();
836             m_logPanel.
837             logMessage("[KnowledgeFlow] Memory (free/total/max.) in bytes: " 
838                 + String.format("%,d", freeM) + " / " 
839                 + String.format("%,d", totalM) + " / " 
840                 + String.format("%,d", maxM));
841             m_logPanel.statusMessage("[KnowledgeFlow]|Memory (free/total/max.) in bytes: " 
842                 + String.format("%,d", freeM) + " / " 
843                 + String.format("%,d", totalM) + " / " 
844                 + String.format("%,d", maxM)); 
845           }
846         }
847       }
848     });
849   
850     JPanel p1 = new JPanel();
851     p1.setLayout(new BorderLayout());
852     p1.setBorder(javax.swing.BorderFactory.createCompoundBorder(
853                            javax.swing.BorderFactory.
854                            createTitledBorder("Knowledge Flow Layout"),
855                   javax.swing.BorderFactory.createEmptyBorder(0, 5, 5, 5)
856                   ));
857     final JScrollPane js = new JScrollPane(m_beanLayout);
858     p1.add(js, BorderLayout.CENTER);
859     js.getVerticalScrollBar().setUnitIncrement(m_ScrollBarIncrementLayout);
860     js.getHorizontalScrollBar().setUnitIncrement(m_ScrollBarIncrementLayout);
861
862     setLayout(new BorderLayout());
863     
864     add(p1, BorderLayout.CENTER);
865     m_beanLayout.setSize(m_FlowWidth, m_FlowHeight);
866     Dimension d = m_beanLayout.getPreferredSize();
867     m_beanLayout.setMinimumSize(d);
868     m_beanLayout.setMaximumSize(d);
869     m_beanLayout.setPreferredSize(d);
870
871     Dimension d2 = new Dimension(100, 170);
872     m_logPanel.setPreferredSize(d2);
873     m_logPanel.setMinimumSize(d2);
874     add(m_logPanel, BorderLayout.SOUTH);
875     
876     setUpToolBars();
877     loadUserComponents();
878  }
879 
880  private Image loadImage(String path) {
881    Image pic = null;
882    // Modified by Zerbetto
883    //java.net.URL imageURL = ClassLoader.getSystemResource(path);
884    java.net.URL imageURL = this.getClass().getClassLoader().getResource(path);
885
886    // end modifications
887    if (imageURL == null) {
888      //      System.err.println("Warning: unable to load "+path);
889    } else {
890      pic = Toolkit.getDefaultToolkit().
891        getImage(imageURL);
892    }
893    return pic;
894  }
895
896  /**
897   * Describe <code>setUpToolBars</code> method here.
898   */
899  private void setUpToolBars() {
900    JPanel toolBarPanel = new JPanel();
901    toolBarPanel.setLayout(new BorderLayout());
902
903    // modifications by Zerbetto
904    // first construct the toolbar for saving, loading etc
905    if (m_showFileMenu) {
906      JToolBar fixedTools = new JToolBar();
907      fixedTools.setOrientation(JToolBar.VERTICAL);
908      m_saveB = new JButton(new ImageIcon(loadImage(BeanVisual.ICON_PATH +
909              "Save24.gif")));
910      m_saveB.setToolTipText("Save layout");
911      m_loadB = new JButton(new ImageIcon(loadImage(BeanVisual.ICON_PATH +
912              "Open24.gif")));
913      m_loadB.setToolTipText("Load layout");
914      m_newB = new JButton(new ImageIcon(loadImage(BeanVisual.ICON_PATH +
915              "New24.gif")));
916      m_newB.setToolTipText("Clear the layout");
917      fixedTools.add(m_newB);
918      fixedTools.add(m_saveB);
919      fixedTools.add(m_loadB);
920
921      m_saveB.addActionListener(new ActionListener() {
922          public void actionPerformed(ActionEvent e) {
923            saveLayout();
924          }
925        });
926
927      m_loadB.addActionListener(new ActionListener() {
928          public void actionPerformed(ActionEvent e) {
929            m_flowEnvironment = new Environment();
930            loadLayout();
931          }
932        });
933
934      m_newB.addActionListener(new ActionListener() {
935          public void actionPerformed(ActionEvent ae) {
936            clearLayout();
937          }
938        });
939
940      fixedTools.setFloatable(false);
941      toolBarPanel.add(fixedTools, BorderLayout.WEST);
942    }
943
944    m_stopB = new JButton(new ImageIcon(loadImage(BeanVisual.ICON_PATH +
945            "Stop24.gif")));
946    m_helpB = new JButton(new ImageIcon(loadImage(BeanVisual.ICON_PATH +
947            "Help24.gif")));
948    m_stopB.setToolTipText("Stop all execution");
949    m_helpB.setToolTipText("Display help");
950
951    Image tempI = loadImage(BeanVisual.ICON_PATH + "Pointer.gif");
952    m_pointerB = new JToggleButton(new ImageIcon(tempI));
953    m_pointerB.addActionListener(new ActionListener() {
954        public void actionPerformed(ActionEvent e) {
955          m_toolBarBean = null;
956          m_mode = NONE;
957          setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
958        }
959      });
960
961    //    Dimension dP = m_saveB.getPreferredSize();
962    //    Dimension dM = m_saveB.getMaximumSize();
963    //    Dimension dP = m_stopB.getPreferredSize();
964    //    Dimension dM = m_stopB.getMaximumSize();
965    //    m_pointerB.setPreferredSize(dP);
966    //    m_pointerB.setMaximumSize(dM);
967    m_toolBarGroup.add(m_pointerB);
968
969    JToolBar fixedTools2 = new JToolBar();
970    fixedTools2.setOrientation(JToolBar.VERTICAL);
971    fixedTools2.setFloatable(false);
972    fixedTools2.add(m_pointerB);
973    fixedTools2.add(m_helpB);
974    fixedTools2.add(m_stopB);
975    //    m_helpB.setPreferredSize(dP);
976    //    m_helpB.setMaximumSize(dP);
977    m_helpB.setSize(m_pointerB.getSize().width, m_pointerB.getSize().height);
978    toolBarPanel.add(fixedTools2, BorderLayout.EAST);
979    // end modifications by Zerbetto
980    m_stopB.addActionListener(new ActionListener() {
981        public void actionPerformed(ActionEvent e) {
982          m_logPanel.statusMessage("[KnowledgeFlow]|Attempting to stop all components...");
983          stopFlow();
984          m_logPanel.statusMessage("[KnowledgeFlow]|OK.");
985        }
986      });
987
988    m_helpB.addActionListener(new ActionListener() {
989        public void actionPerformed(ActionEvent ae) {
990          popupHelp();
991        }
992      });
993
994    final int STANDARD_TOOLBAR = 0;
995    final int WEKAWRAPPER_TOOLBAR = 1;
996
997    int toolBarType = STANDARD_TOOLBAR;
998
999    // set up wrapper toolbars
1000    for (int i = 0; i < TOOLBARS.size(); i++) {
1001      Vector tempBarSpecs = (Vector) TOOLBARS.elementAt(i);
1002
1003      // name for the tool bar
1004      String tempBarName = (String) tempBarSpecs.elementAt(0);
1005
1006      // Used for weka leaf packages
1007      Box singletonHolderPanel = null;
1008
1009      // name of the bean component to handle this class of weka algorithms
1010      String tempBeanCompName = (String) tempBarSpecs.elementAt(1);
1011
1012      // a JPanel holding an instantiated bean + label ready to be added
1013      // to the current toolbar
1014      JPanel tempBean;
1015
1016      // the root package for weka algorithms
1017      String rootPackage = "";
1018      weka.gui.HierarchyPropertyParser hpp = null;
1019      Hashtable hpps = null;
1020
1021      // Is this a wrapper toolbar?
1022      if (tempBeanCompName.compareTo("null") != 0) {
1023        tempBean = null;
1024        toolBarType = WEKAWRAPPER_TOOLBAR;
1025        rootPackage = (String) tempBarSpecs.elementAt(2);
1026        //      hpp = (weka.gui.HierarchyPropertyParser)tempBarSpecs.elementAt(3);
1027        hpps = (Hashtable) tempBarSpecs.elementAt(3);
1028
1029        try {
1030          // modifications by Zerbetto
1031          // Beans.instantiate(null, tempBeanCompName);
1032          Beans.instantiate(this.getClass().getClassLoader(), tempBeanCompName);
1033
1034          // end modifications by Zerbetto
1035        } catch (Exception ex) {
1036          // ignore
1037          System.err.println("[KnowledgeFlow] Failed to instantiate: " + tempBeanCompName);
1038
1039          break;
1040        }
1041      } else {
1042        toolBarType = STANDARD_TOOLBAR;
1043      }
1044
1045      // a toolbar to hold buttons---one for each algorithm
1046      JToolBar tempToolBar = new JToolBar();
1047
1048      //      System.err.println(tempToolBar.getLayout());
1049      //      tempToolBar.setLayout(new FlowLayout());
1050      int z = 2;
1051
1052      if (toolBarType == WEKAWRAPPER_TOOLBAR) {
1053        Enumeration enm = hpps.keys();
1054
1055        while (enm.hasMoreElements()) {
1056          String root = (String) enm.nextElement();
1057          String userPrefix = "";
1058          hpp = (HierarchyPropertyParser) hpps.get(root);
1059
1060          if (!hpp.goTo(rootPackage)) {
1061            System.out.println("[KnowledgeFlow] Processing user package... ");
1062            //            System.exit(1);
1063            userPrefix = root + ".";
1064          }
1065
1066          String[] primaryPackages = hpp.childrenValues();
1067
1068          for (int kk = 0; kk < primaryPackages.length; kk++) {
1069            hpp.goToChild(primaryPackages[kk]);
1070
1071            // check to see if this is a leaf - if so then there are no
1072            // sub packages
1073            if (hpp.isLeafReached()) {
1074              if (singletonHolderPanel == null) {
1075                singletonHolderPanel = Box.createHorizontalBox();
1076                singletonHolderPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(
1077                    tempBarName));
1078              }
1079
1080              String algName = hpp.fullValue();
1081              tempBean = instantiateToolBarBean(true, tempBeanCompName, algName);
1082
1083              if (tempBean != null) {
1084                // tempToolBar.add(tempBean);
1085                singletonHolderPanel.add(tempBean);
1086              }
1087
1088              hpp.goToParent();
1089            } else {
1090              // make a titledborder JPanel to hold all the schemes in this
1091              // package
1092              //            JPanel holderPanel = new JPanel();
1093              Box holderPanel = Box.createHorizontalBox();
1094              holderPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(userPrefix +
1095                  primaryPackages[kk]));
1096              processPackage(holderPanel, tempBeanCompName, hpp);
1097              tempToolBar.add(holderPanel);
1098            }
1099          }
1100
1101          if (singletonHolderPanel != null) {
1102            tempToolBar.add(singletonHolderPanel);
1103            singletonHolderPanel = null;
1104          }
1105        }
1106      } else {
1107        Box holderPanel = Box.createHorizontalBox();
1108        holderPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(
1109            tempBarName));
1110
1111        for (int j = z; j < tempBarSpecs.size(); j++) {
1112          tempBean = null;
1113          tempBeanCompName = (String) tempBarSpecs.elementAt(j);
1114          tempBean = instantiateToolBarBean((toolBarType == WEKAWRAPPER_TOOLBAR),
1115              tempBeanCompName, "");
1116
1117          if (tempBean != null) {
1118            // set tool tip text (if any)
1119            // setToolTipText(tempBean)
1120            holderPanel.add(tempBean);
1121          }
1122        }
1123
1124        tempToolBar.add(holderPanel);
1125      }
1126
1127      JScrollPane tempJScrollPane = createScrollPaneForToolBar(tempToolBar);
1128      // ok, now create tabbed pane to hold this toolbar
1129      m_toolBars.addTab(tempBarName, null, tempJScrollPane, tempBarName);
1130    }
1131
1132    // Any plugin components to process?
1133    if (BEAN_PLUGINS_PROPERTIES != null && 
1134        BEAN_PLUGINS_PROPERTIES.size() > 0) {
1135      for (int i = 0; i < BEAN_PLUGINS_PROPERTIES.size(); i++) {
1136        Properties tempP = BEAN_PLUGINS_PROPERTIES.get(i);
1137        JPanel tempBean = null;
1138        String components = 
1139        tempP.getProperty("weka.gui.beans.KnowledgeFlow.Plugins");
1140        StringTokenizer st2 = new StringTokenizer(components, ", ");
1141
1142        while (st2.hasMoreTokens()) {
1143          String tempBeanCompName = st2.nextToken().trim();
1144          tempBean = instantiateToolBarBean(false, tempBeanCompName, "");
1145          if (m_pluginsToolBar == null) {
1146            // need to create the plugins tab and toolbar
1147            setUpPluginsToolBar();
1148          }
1149          m_pluginsBoxPanel.add(tempBean);
1150        }
1151      }
1152    }
1153
1154    toolBarPanel.add(m_toolBars, BorderLayout.CENTER);
1155
1156    //    add(m_toolBars, BorderLayout.NORTH);
1157    add(toolBarPanel, BorderLayout.NORTH);
1158  }
1159 
1160  private void stopFlow() {
1161    Vector components = BeanInstance.getBeanInstances();
1162
1163    for (int i = 0; i < components.size(); i++) {
1164      Object temp = ((BeanInstance) components.elementAt(i)).getBean();
1165
1166      if (temp instanceof BeanCommon) {
1167        ((BeanCommon) temp).stop();
1168      }
1169    }
1170  }
1171
1172
1173  private JScrollPane createScrollPaneForToolBar(JToolBar tb) {
1174    JScrollPane tempJScrollPane = 
1175      new JScrollPane(tb, 
1176                      JScrollPane.VERTICAL_SCROLLBAR_NEVER,
1177                      JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
1178   
1179    Dimension d = tb.getPreferredSize();
1180    tempJScrollPane.setMinimumSize(new Dimension((int)d.getWidth(),
1181                                                 (int)(d.getHeight()+15)));
1182    tempJScrollPane.setPreferredSize(new Dimension((int)d.getWidth(),
1183                                                   (int)(d.getHeight()+15)));
1184    tempJScrollPane.getHorizontalScrollBar().setUnitIncrement(
1185        m_ScrollBarIncrementComponents);
1186
1187    return tempJScrollPane;
1188  }
1189
1190  private void processPackage(JComponent holderPanel,
1191                              String tempBeanCompName,
1192                              weka.gui.HierarchyPropertyParser hpp) {
1193    if (hpp.isLeafReached()) {
1194      // instantiate a bean and add it to the holderPanel
1195      //      System.err.println("Would add "+hpp.fullValue());
1196      String algName = hpp.fullValue();
1197      JPanel tempBean = 
1198        instantiateToolBarBean(true, tempBeanCompName, algName);
1199      if (tempBean != null) {
1200        holderPanel.add(tempBean);
1201      }
1202      hpp.goToParent();
1203      return;
1204    }
1205    String [] children = hpp.childrenValues();
1206    for (int i = 0; i < children.length; i++) {
1207      hpp.goToChild(children[i]);
1208      processPackage(holderPanel, tempBeanCompName, hpp);
1209    }
1210    hpp.goToParent();
1211  }
1212
1213  /**
1214   * Instantiates a bean for display in the toolbars
1215   *
1216   * @param wekawrapper true if the bean to be instantiated is a wekawrapper
1217   * @param tempBeanCompName the name of the bean to instantiate
1218   * @param algName holds the name of a weka algorithm to configure the
1219   * bean with if it is a wekawrapper bean
1220   * @return a JPanel holding the instantiated (and configured bean)
1221   */
1222  private JPanel instantiateToolBarBean(boolean wekawrapper, 
1223                                        String tempBeanCompName,
1224                                        String algName) {
1225    Object tempBean;
1226    if (wekawrapper) {
1227      try {
1228        // modifications by Zerbetto
1229        //tempBean = Beans.instantiate(null, tempBeanCompName);
1230        tempBean = Beans.instantiate(this.getClass().getClassLoader(),
1231                                     tempBeanCompName);
1232       
1233        // end modifications by Zerbetto
1234      } catch (Exception ex) {
1235        System.err.println("[KnowledgeFlow] Failed to instantiate :"+tempBeanCompName
1236                           +"KnowledgeFlowApp.instantiateToolBarBean()");
1237        return null;
1238      }
1239      if (tempBean instanceof WekaWrapper) {
1240        //      algName = (String)tempBarSpecs.elementAt(j);
1241        Class c = null;
1242        try {
1243          c = Class.forName(algName);
1244        } catch (Exception ex) {
1245          System.err.println("[KnowledgeFlow] Can't find class called: "+algName);
1246          return null;
1247        }
1248        try {
1249          Object o = c.newInstance();
1250          ((WekaWrapper)tempBean).setWrappedAlgorithm(o);
1251        } catch (Exception ex) {
1252          System.err.println("[KnowledgeFlow] Failed to configure "+tempBeanCompName
1253                             +" with "+algName);
1254          return null;
1255        }
1256      }
1257    } else {
1258      try {
1259        // modifications by Zerbetto
1260        //tempBean = Beans.instantiate(null, tempBeanCompName);
1261        tempBean = Beans.instantiate(this.getClass().getClassLoader(),
1262            tempBeanCompName);
1263
1264        // end modifications
1265      } catch (Exception ex) {
1266        ex.printStackTrace();
1267        System.err.println("[KnowledgeFlow] Failed to instantiate :"+tempBeanCompName
1268                           +"KnowledgeFlowApp.setUpToolBars()");
1269        return null;
1270      }
1271    }
1272   
1273    if (tempBean instanceof BeanContextChild) {
1274      m_bcSupport.add(tempBean);
1275    }
1276    if (tempBean instanceof Visible) {
1277      ((Visible)tempBean).getVisual().scale(3);
1278    }
1279
1280    return makeHolderPanelForToolBarBean(tempBeanCompName, tempBean, 
1281                                         wekawrapper, algName, false);
1282  }
1283
1284  /**
1285   * Instantiates (by making a serialized copy) the supplied
1286   * template meta bean for display in the user tool bar
1287   *
1288   * @param bean the prototype MetaBean to display in the toolbar
1289   */
1290  private JPanel instantiateToolBarMetaBean(MetaBean bean) {
1291    // copy the bean via serialization
1292    ((Visible)bean).getVisual().removePropertyChangeListener(this);
1293    bean.removePropertyChangeListenersSubFlow(this);
1294    Object copy = null;
1295    try {
1296      SerializedObject so = new SerializedObject(bean);
1297      copy = (MetaBean)so.getObject();
1298    } catch (Exception ex) {
1299      ex.printStackTrace();
1300      return null;
1301    }
1302    ((Visible)bean).getVisual().addPropertyChangeListener(this);
1303    bean.addPropertyChangeListenersSubFlow(this);
1304
1305    String displayName ="";
1306    //
1307    if (copy instanceof Visible) {
1308      ((Visible)copy).getVisual().scale(3);
1309      displayName = ((Visible)copy).getVisual().getText();
1310    }
1311    return makeHolderPanelForToolBarBean(displayName,
1312                                         copy,
1313                                         false,
1314                                         null,
1315                                         true);
1316  }
1317
1318  private JPanel makeHolderPanelForToolBarBean(final String tempName,
1319                                               Object tempBean,
1320                                               boolean wekawrapper,
1321                                               String algName,
1322                                               final boolean metabean) {
1323    // ---------------------------------------
1324    JToggleButton tempButton;
1325    final JPanel tempP = new JPanel();
1326    JLabel tempL = new JLabel();
1327    tempL.setFont(new Font(null, Font.PLAIN, 9));
1328
1329    String labelName = (wekawrapper == true) 
1330      ? algName
1331      : tempName;
1332    labelName = labelName.substring(labelName.lastIndexOf('.')+1, 
1333                                    labelName.length());
1334    tempL.setText(" "+labelName+" ");
1335    tempL.setHorizontalAlignment(JLabel.CENTER);
1336    tempP.setLayout(new BorderLayout());
1337
1338    if (tempBean instanceof Visible) {
1339      BeanVisual bv = ((Visible)tempBean).getVisual();
1340
1341      tempButton = 
1342        new JToggleButton(bv.getStaticIcon());
1343      int width = bv.getStaticIcon().getIconWidth();
1344      int height = bv.getStaticIcon().getIconHeight();
1345     
1346      JPanel labelPanel = 
1347        multiLineLabelPanel(labelName, width);
1348      tempP.add(labelPanel, BorderLayout.SOUTH);
1349    } else {
1350      tempButton = new JToggleButton();
1351      tempP.add(tempL, BorderLayout.SOUTH);
1352    }
1353    tempP.add(tempButton, BorderLayout.NORTH);
1354    //    tempP.add(tempL, BorderLayout.SOUTH);
1355   
1356    //  holderPanel.add(tempP);
1357    //    tempToolBar.add(tempP);
1358    m_toolBarGroup.add(tempButton);
1359   
1360    // add an action listener for the button here
1361    final Object tempBN = tempBean;
1362    final JToggleButton fButton = tempButton;
1363    //    final JToggleButton tempButton2 = tempButton;
1364    tempButton.addActionListener(new ActionListener() {
1365        public void actionPerformed(ActionEvent e) {
1366          boolean changeCursor = true;
1367          try {
1368            m_toolBarBean = null;
1369            if (metabean) {
1370              if ((e.getModifiers() & ActionEvent.SHIFT_MASK) != 0) {
1371                changeCursor = false;
1372                m_toolBarGroup.remove(fButton);
1373                m_userBoxPanel.remove(tempP);
1374                m_userBoxPanel.revalidate();
1375                m_userComponents.remove(tempBN);
1376                if (m_firstUserComponentOpp) {
1377                  installWindowListenerForSavingUserBeans();
1378                  m_firstUserComponentOpp = false;
1379                }
1380                if (m_userComponents.size() == 0) {
1381                  m_toolBars.removeTabAt(m_toolBars.getTabCount() - 1);
1382                  m_userToolBar = null;
1383                  notifyIsDirty();
1384                }
1385              } else {
1386                SerializedObject so = new SerializedObject(tempBN);
1387                MetaBean copy = (MetaBean)so.getObject();
1388                /*((Visible)copy).getVisual().
1389                  addPropertyChangeListener(KnowledgeFlowApp.this); */
1390                copy.addPropertyChangeListenersSubFlow(KnowledgeFlowApp.this);
1391                m_toolBarBean = copy;
1392              }
1393            } else {
1394              // modifications by Zerbetto
1395              //m_toolBarBean = Beans.instantiate(null, tempName);
1396              m_toolBarBean = Beans.instantiate(this.getClass().getClassLoader(),
1397                  tempName);
1398
1399              // end modifications
1400            }
1401            if (m_toolBarBean instanceof WekaWrapper) {
1402              Object wrappedAlg = 
1403                ((WekaWrapper)tempBN).getWrappedAlgorithm();
1404             
1405              ((WekaWrapper)m_toolBarBean).
1406                setWrappedAlgorithm(wrappedAlg.getClass().newInstance());
1407              //                    tempButton2.setSelected(false);
1408            }
1409            if (changeCursor) {
1410              setCursor(Cursor.
1411                        getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
1412              m_mode = ADDING;
1413            }
1414          } catch (Exception ex) {
1415            System.err.
1416              println("[KnowledgeFlow] Problem adding bean to data flow layout");
1417            ex.printStackTrace();
1418          }
1419          notifyIsDirty();
1420        }
1421      });
1422   
1423    if (tempBean instanceof MetaBean) {
1424      tempButton.setToolTipText("Hold down shift and click to remove");
1425      m_userComponents.add(tempBean);
1426    } else {
1427      // set tool tip text from global info if supplied
1428      String summary = getGlobalInfo(tempBean);
1429      if (summary != null) {
1430        int ci = summary.indexOf('.');
1431        if (ci != -1) {
1432          summary = summary.substring(0, ci + 1);
1433        }
1434        tempButton.setToolTipText(summary);
1435      }
1436    }
1437
1438    //return tempBean;
1439    return tempP;
1440  }
1441
1442  private JPanel multiLineLabelPanel(String sourceL,
1443                                     int splitWidth) {
1444    JPanel jp = new JPanel();
1445    Vector v = new Vector();
1446
1447    int labelWidth = m_fontM.stringWidth(sourceL);
1448
1449    if (labelWidth < splitWidth) {
1450      v.addElement(sourceL);
1451    } else {
1452      // find mid point
1453      int mid = sourceL.length() / 2;
1454     
1455      // look for split point closest to the mid
1456      int closest = sourceL.length();
1457      int closestI = -1;
1458      for (int i = 0; i < sourceL.length(); i++) {
1459        if (sourceL.charAt(i) < 'a') {
1460          if (Math.abs(mid - i) < closest) {
1461            closest = Math.abs(mid - i);
1462            closestI = i;
1463          }
1464        }
1465      }
1466      if (closestI != -1) {
1467        String left = sourceL.substring(0, closestI);
1468        String right = sourceL.substring(closestI, sourceL.length());
1469        if (left.length() > 1 && right.length() > 1) {
1470          v.addElement(left);
1471          v.addElement(right);
1472        } else {
1473          v.addElement(sourceL);
1474        }
1475      } else {
1476        v.addElement(sourceL);
1477      }
1478    }
1479
1480    jp.setLayout(new GridLayout(v.size(), 1));
1481    for (int i = 0; i < v.size(); i++) {
1482      JLabel temp = new JLabel();
1483      temp.setFont(new Font(null, Font.PLAIN, 9));
1484      temp.setText(" "+((String)v.elementAt(i))+" ");
1485      temp.setHorizontalAlignment(JLabel.CENTER);
1486      jp.add(temp);
1487    }
1488    return jp;
1489  }
1490
1491  private void setUpUserToolBar() {
1492    m_userBoxPanel = Box.createHorizontalBox();
1493    m_userBoxPanel.setBorder(javax.swing.BorderFactory.
1494                             createTitledBorder("User"));
1495    m_userToolBar = new JToolBar();
1496    m_userToolBar.add(m_userBoxPanel);
1497    JScrollPane tempJScrollPane = 
1498      createScrollPaneForToolBar(m_userToolBar);
1499    // ok, now create tabbed pane to hold this toolbar
1500   
1501    m_toolBars.addTab("User", null, 
1502                      tempJScrollPane,
1503                      "User created components");
1504  }
1505
1506  private void setUpPluginsToolBar() {
1507    m_pluginsBoxPanel = Box.createHorizontalBox();
1508    m_pluginsBoxPanel.setBorder(javax.swing.BorderFactory.
1509                                createTitledBorder("Plugins"));
1510    m_pluginsToolBar = new JToolBar();
1511    m_pluginsToolBar.add(m_pluginsBoxPanel);
1512    JScrollPane tempJScrollPane = 
1513      createScrollPaneForToolBar(m_pluginsToolBar);
1514    // ok, now create tabbed pane to hold this toolbar
1515   
1516    m_toolBars.addTab("Plugins", null, 
1517                      tempJScrollPane,
1518                      "Plugin components");
1519  }
1520
1521  /**
1522   * Pop up a help window
1523   */
1524  private void popupHelp() {
1525    final JButton tempB = m_helpB;
1526    try {
1527      tempB.setEnabled(false);
1528      // Modified by Zerbetto
1529      //InputStream inR =
1530      //        ClassLoader.
1531      //        getSystemResourceAsStream("weka/gui/beans/README_KnowledgeFlow");
1532      InputStream inR = this.getClass().getClassLoader()
1533                            .getResourceAsStream("weka/gui/beans/README_KnowledgeFlow");
1534
1535      // end modifications
1536      StringBuffer helpHolder = new StringBuffer();
1537      LineNumberReader lnr = new LineNumberReader(new InputStreamReader(inR));
1538     
1539      String line;
1540     
1541      while ((line = lnr.readLine()) != null) {
1542        helpHolder.append(line+"\n");
1543      }
1544     
1545      lnr.close();
1546      final javax.swing.JFrame jf = new javax.swing.JFrame();
1547      jf.getContentPane().setLayout(new java.awt.BorderLayout());
1548      final JTextArea ta = new JTextArea(helpHolder.toString());
1549      ta.setFont(new Font("Monospaced", Font.PLAIN, 12));
1550      ta.setEditable(false);
1551      final JScrollPane sp = new JScrollPane(ta);
1552      jf.getContentPane().add(sp, java.awt.BorderLayout.CENTER);
1553      jf.addWindowListener(new java.awt.event.WindowAdapter() {
1554        public void windowClosing(java.awt.event.WindowEvent e) {
1555          tempB.setEnabled(true);
1556          jf.dispose();
1557        }
1558      });
1559      jf.setSize(600,600);
1560      jf.setVisible(true);
1561     
1562    } catch (Exception ex) {
1563      tempB.setEnabled(true);
1564    }
1565  }
1566
1567  public void clearLayout() {
1568    stopFlow(); // try and stop any running components
1569    BeanInstance.reset(m_beanLayout);
1570    BeanConnection.reset();
1571    m_beanLayout.revalidate();
1572    m_beanLayout.repaint();
1573    m_logPanel.clearStatus();
1574    m_logPanel.statusMessage("[KnowledgeFlow]|Welcome to the Weka Knowledge Flow");
1575  }
1576 
1577  /**
1578   * Popup a context sensitive menu for the bean component
1579   *
1580   * @param pt holds the panel coordinates for the component
1581   * @param bi the bean component over which the user right clicked the mouse
1582   * @param x the x coordinate at which to popup the menu
1583   * @param y the y coordinate at which to popup the menu
1584   *
1585   * Modified by Zerbetto: javax.swing.JPopupMenu transformed into java.awt.PopupMenu
1586   *
1587   */
1588  private void doPopup(Point pt, final BeanInstance bi, int x, int y) {
1589    final JComponent bc = (JComponent) bi.getBean();
1590    final int xx = x;
1591    final int yy = y;
1592    int menuItemCount = 0;
1593
1594    // modifications by Zerbetto
1595    PopupMenu beanContextMenu = new PopupMenu();
1596
1597    //JPopupMenu beanContextMenu = new JPopupMenu();
1598
1599    //    beanContextMenu.insert(new JLabel("Edit",
1600    //                                SwingConstants.CENTER),
1601    //                     menuItemCount);
1602    MenuItem edit = new MenuItem("Edit:");
1603    edit.setEnabled(false);
1604    beanContextMenu.insert(edit, menuItemCount);
1605    menuItemCount++;
1606
1607    if (bc instanceof MetaBean) {
1608      //JMenuItem ungroupItem = new JMenuItem("Ungroup");
1609      MenuItem ungroupItem = new MenuItem("Ungroup");
1610      ungroupItem.addActionListener(new ActionListener() {
1611          public void actionPerformed(ActionEvent e) {
1612            // ungroup
1613            bi.removeBean(m_beanLayout);
1614
1615            Vector group = ((MetaBean) bc).getBeansInSubFlow();
1616            Vector associatedConnections = ((MetaBean) bc).getAssociatedConnections();
1617            ((MetaBean) bc).restoreBeans();
1618
1619            for (int i = 0; i < group.size(); i++) {
1620              BeanInstance tbi = (BeanInstance) group.elementAt(i);
1621              addComponent(tbi, false);
1622              tbi.addBean(m_beanLayout);
1623            }
1624
1625            for (int i = 0; i < associatedConnections.size(); i++) {
1626              BeanConnection tbc = (BeanConnection) associatedConnections.elementAt(i);
1627              tbc.setHidden(false);
1628            }
1629
1630            m_beanLayout.repaint();
1631            notifyIsDirty();
1632          }
1633        });
1634      beanContextMenu.add(ungroupItem);
1635      menuItemCount++;
1636
1637      // Add to user tab
1638      //JMenuItem addToUserTabItem = new JMenuItem("Add to user tab");
1639      MenuItem addToUserTabItem = new MenuItem("Add to user tab");
1640      addToUserTabItem.addActionListener(new ActionListener() {
1641          public void actionPerformed(ActionEvent e) {
1642            addToUserToolBar((MetaBean) bi.getBean(), true);
1643            notifyIsDirty();
1644          }
1645        });
1646      beanContextMenu.add(addToUserTabItem);
1647      menuItemCount++;
1648    }
1649
1650    //JMenuItem deleteItem = new JMenuItem("Delete");
1651    MenuItem deleteItem = new MenuItem("Delete");
1652    deleteItem.addActionListener(new ActionListener() {
1653        public void actionPerformed(ActionEvent e) {
1654          BeanConnection.removeConnections(bi);
1655          bi.removeBean(m_beanLayout);
1656          if (bc instanceof BeanCommon) {           
1657            String key = ((BeanCommon)bc).getCustomName()
1658              + "$" + bc.hashCode();
1659            m_logPanel.statusMessage(key + "|remove");
1660          }
1661          revalidate();
1662          notifyIsDirty();
1663        }
1664      });
1665    if (bc instanceof BeanCommon) {
1666      if (((BeanCommon)bc).isBusy()) {
1667        deleteItem.setEnabled(false);
1668      }
1669    }
1670    beanContextMenu.add(deleteItem);
1671    menuItemCount++;
1672
1673    if (bc instanceof BeanCommon) {
1674      MenuItem nameItem = new MenuItem("Set name");
1675      nameItem.addActionListener(new ActionListener() {
1676          public void actionPerformed(ActionEvent e) {
1677            String oldName = ((BeanCommon)bc).getCustomName();
1678            String name = JOptionPane.showInputDialog(KnowledgeFlowApp.this,
1679                                                      "Enter a name for this component",
1680                                                      oldName);
1681            if (name != null) {
1682              ((BeanCommon)bc).setCustomName(name);
1683            }
1684          }
1685        });
1686      if (bc instanceof BeanCommon) {
1687        if (((BeanCommon)bc).isBusy()) {
1688          nameItem.setEnabled(false);
1689        }
1690      }
1691      beanContextMenu.add(nameItem);
1692      menuItemCount++;
1693    }
1694
1695    try {
1696      //BeanInfo [] compInfo = null;
1697      //JComponent [] associatedBeans = null;
1698      Vector compInfo = new Vector(1);
1699      Vector associatedBeans = null;
1700      Vector outputBeans = null;
1701      Vector compInfoOutputs = null;
1702
1703      if (bc instanceof MetaBean) {
1704        compInfo = ((MetaBean) bc).getBeanInfoSubFlow();
1705        associatedBeans = ((MetaBean) bc).getBeansInSubFlow();
1706
1707        outputBeans = ((MetaBean) bc).getBeansInOutputs();
1708        compInfoOutputs = ((MetaBean) bc).getBeanInfoOutputs();
1709      } else {
1710        compInfo.add(Introspector.getBeanInfo(bc.getClass()));
1711        compInfoOutputs = compInfo;
1712      }
1713
1714      final Vector tempAssociatedBeans = associatedBeans;
1715
1716      if (compInfo == null) {
1717        System.err.println("[KnowledgeFlow] Error in doPopup()");
1718      } else {
1719        //      System.err.println("Got bean info");
1720        for (int zz = 0; zz < compInfo.size(); zz++) {
1721          final int tt = zz;
1722          final Class custClass = ((BeanInfo) compInfo.elementAt(zz)).getBeanDescriptor()
1723            .getCustomizerClass();
1724
1725          if (custClass != null) {
1726            //    System.err.println("Got customizer class");
1727            //    popupCustomizer(custClass, bc);
1728            //JMenuItem custItem = null;
1729            MenuItem custItem = null;
1730            boolean customizationEnabled = true;
1731
1732            if (!(bc instanceof MetaBean)) {
1733              //custItem = new JMenuItem("Configure...");
1734              custItem = new MenuItem("Configure...");
1735              if (bc instanceof BeanCommon) {
1736                customizationEnabled = 
1737                  !((BeanCommon)bc).isBusy();
1738              }
1739            } else {
1740              String custName = custClass.getName();
1741              BeanInstance tbi = (BeanInstance) associatedBeans.elementAt(zz);
1742              if (tbi.getBean() instanceof BeanCommon) {
1743                custName = ((BeanCommon)tbi.getBean()).getCustomName();
1744              } else {
1745                if (tbi.getBean() instanceof WekaWrapper) {
1746                  custName = ((WekaWrapper) tbi.getBean()).getWrappedAlgorithm()
1747                  .getClass().getName();
1748                } else {
1749                  custName = custName.substring(0, custName.indexOf("Customizer"));
1750                }
1751
1752                custName = custName.substring(custName.lastIndexOf('.') + 1,             
1753                                            custName.length());
1754              }
1755              //custItem = new JMenuItem("Configure: "+ custName);
1756              custItem = new MenuItem("Configure: " + custName);
1757              if (tbi.getBean() instanceof BeanCommon) {
1758                customizationEnabled = 
1759                  !((BeanCommon)tbi.getBean()).isBusy();
1760              }
1761            }
1762
1763            custItem.addActionListener(new ActionListener() {
1764                public void actionPerformed(ActionEvent e) {
1765                  if (bc instanceof MetaBean) {
1766                    popupCustomizer(custClass,
1767                      (JComponent) ((BeanInstance) tempAssociatedBeans.
1768                                    elementAt(tt)).getBean());
1769                  } else {
1770                    popupCustomizer(custClass, bc);
1771                  }
1772
1773                  notifyIsDirty();
1774                }
1775              });
1776            custItem.setEnabled(customizationEnabled);
1777            beanContextMenu.add(custItem);
1778            menuItemCount++;
1779          } else {
1780            System.err.println("[KnowledgeFlow] No customizer class");
1781          }
1782        }
1783
1784        Vector esdV = new Vector();
1785
1786        //for (int i = 0; i < compInfoOutputs.size(); i++) {
1787        for (int i = 0; i < compInfo.size(); i++) {
1788          EventSetDescriptor[] temp = 
1789          //  ((BeanInfo) compInfoOutputs.elementAt(i)).getEventSetDescriptors();
1790          ((BeanInfo) compInfo.elementAt(i)).getEventSetDescriptors();
1791
1792          if ((temp != null) && (temp.length > 0)) {
1793            esdV.add(temp);
1794          }
1795        }
1796
1797        //        EventSetDescriptor [] esds = compInfo.getEventSetDescriptors();
1798        //        if (esds != null && esds.length > 0) {
1799        if (esdV.size() > 0) {
1800          //          beanContextMenu.insert(new JLabel("Connections",
1801          //                                            SwingConstants.CENTER),
1802          //                                 menuItemCount);
1803          MenuItem connections = new MenuItem("Connections:");
1804          connections.setEnabled(false);
1805          beanContextMenu.insert(connections, menuItemCount);
1806          menuItemCount++;
1807        }
1808
1809        //final Vector finalOutputs = outputBeans;
1810        final Vector finalOutputs = associatedBeans;
1811
1812        for (int j = 0; j < esdV.size(); j++) {
1813          final int fj = j;
1814          String sourceBeanName = "";
1815
1816          if (bc instanceof MetaBean) {
1817            //Object sourceBean = ((BeanInstance) outputBeans.elementAt(j)).getBean();
1818            Object sourceBean = ((BeanInstance) associatedBeans.elementAt(j)).getBean();
1819            if (sourceBean instanceof BeanCommon) {
1820              sourceBeanName = ((BeanCommon)sourceBean).getCustomName();
1821            } else {
1822              if (sourceBean instanceof WekaWrapper) {
1823                sourceBeanName = ((WekaWrapper) sourceBean).getWrappedAlgorithm()
1824                .getClass().getName();
1825              } else {
1826                sourceBeanName = sourceBean.getClass().getName();
1827              }
1828
1829              sourceBeanName = 
1830                sourceBeanName.substring(sourceBeanName.lastIndexOf('.') + 1, 
1831                    sourceBeanName.length());
1832            }
1833            sourceBeanName += ": ";
1834          }
1835
1836          EventSetDescriptor[] esds = (EventSetDescriptor[]) esdV.elementAt(j);
1837
1838          for (int i = 0; i < esds.length; i++) {
1839            //    System.err.println(esds[i].getName());
1840            // add each event name to the menu
1841            //            JMenuItem evntItem = new JMenuItem(sourceBeanName
1842            //                                               +esds[i].getName());
1843            MenuItem evntItem = new MenuItem(sourceBeanName +
1844                                             esds[i].getName());
1845            final EventSetDescriptor esd = esds[i];
1846
1847            // Check EventConstraints (if any) here
1848            boolean ok = true;
1849
1850            if (bc instanceof EventConstraints) {
1851              ok = ((EventConstraints) bc).eventGeneratable(esd.getName());
1852            }
1853
1854            if (ok) {
1855              evntItem.addActionListener(new ActionListener() {
1856                  public void actionPerformed(ActionEvent e) {
1857                    connectComponents(esd,
1858                                      (bc instanceof MetaBean)
1859                                      ? ((BeanInstance) finalOutputs.elementAt(fj)) : bi, xx, yy);
1860                    notifyIsDirty();
1861                  }
1862                });
1863            } else {
1864              evntItem.setEnabled(false);
1865            }
1866
1867            beanContextMenu.add(evntItem);
1868            menuItemCount++;
1869          }
1870        }
1871      }
1872    } catch (IntrospectionException ie) {
1873      ie.printStackTrace();
1874    }
1875
1876    //    System.err.println("Just before look for other options");
1877    // now look for other options for this bean
1878    if (bc instanceof UserRequestAcceptor || bc instanceof Startable) {
1879      Enumeration req = null;
1880     
1881      if (bc instanceof UserRequestAcceptor) {
1882        req = ((UserRequestAcceptor) bc).enumerateRequests();
1883      }
1884
1885      if ((bc instanceof Startable) || (req !=null && req.hasMoreElements())) {
1886        //      beanContextMenu.insert(new JLabel("Actions",
1887        //                                        SwingConstants.CENTER),
1888        //                             menuItemCount);
1889        MenuItem actions = new MenuItem("Actions:");
1890        actions.setEnabled(false);
1891        beanContextMenu.insert(actions, menuItemCount);
1892        menuItemCount++;
1893      }
1894
1895      if (bc instanceof Startable) {
1896        String tempS = ((Startable)bc).getStartMessage();
1897        insertUserOrStartableMenuItem(bc, true, tempS, beanContextMenu);
1898      }
1899     
1900      while (req != null && req.hasMoreElements()) {
1901        String tempS = (String) req.nextElement();
1902        insertUserOrStartableMenuItem(bc, false, tempS, beanContextMenu);
1903        menuItemCount++;
1904      }
1905    }
1906
1907    //    System.err.println("Just before showing menu");
1908    // popup the menu
1909    if (menuItemCount > 0) {
1910      //beanContextMenu.show(m_beanLayout, x, y);
1911      m_beanLayout.add(beanContextMenu);
1912      beanContextMenu.show(m_beanLayout, x, y);
1913    }
1914  }
1915 
1916  private void insertUserOrStartableMenuItem(final JComponent bc, 
1917      final boolean startable, String tempS, PopupMenu beanContextMenu) {
1918
1919    boolean disabled = false;
1920    boolean confirmRequest = false;
1921
1922    // check to see if this item is currently disabled
1923    if (tempS.charAt(0) == '$') {
1924      tempS = tempS.substring(1, tempS.length());
1925      disabled = true;
1926    }
1927   
1928    // check to see if this item requires confirmation
1929    if (tempS.charAt(0) == '?') {
1930      tempS = tempS.substring(1, tempS.length());
1931      confirmRequest = true;
1932    }
1933
1934    final String tempS2 = tempS;
1935
1936    //      JMenuItem custItem = new JMenuItem(tempS2);
1937    MenuItem custItem = new MenuItem(tempS2);
1938    if (confirmRequest) {
1939      custItem.addActionListener(new ActionListener() {
1940        public void actionPerformed(ActionEvent e) {
1941          //
1942          int result = JOptionPane.showConfirmDialog(KnowledgeFlowApp.this,
1943              tempS2,
1944              "Confirm action",
1945              JOptionPane.YES_NO_OPTION);
1946          if (result == JOptionPane.YES_OPTION) {
1947            Thread startPointThread = new Thread() {
1948              public void run() {
1949                try {
1950                  if (startable) {
1951                    ((Startable)bc).start();                   
1952                  } else if (bc instanceof UserRequestAcceptor) {
1953                    ((UserRequestAcceptor) bc).performRequest(tempS2);
1954                  }
1955                  notifyIsDirty();
1956                } catch (Exception ex) {
1957                  ex.printStackTrace();
1958                }
1959              }
1960            };
1961            startPointThread.setPriority(Thread.MIN_PRIORITY);
1962            startPointThread.start();
1963          }
1964        }
1965      });
1966    } else {
1967      custItem.addActionListener(new ActionListener() {
1968        public void actionPerformed(ActionEvent e) {
1969          Thread startPointThread = new Thread() {
1970            public void run() {
1971              try {
1972                if (startable) {
1973                  ((Startable)bc).start();                 
1974                } else if (bc instanceof UserRequestAcceptor) {
1975                  ((UserRequestAcceptor) bc).performRequest(tempS2);
1976                }
1977                notifyIsDirty();
1978              } catch (Exception ex) {
1979                ex.printStackTrace();
1980              }
1981            }
1982          };
1983          startPointThread.setPriority(Thread.MIN_PRIORITY);
1984          startPointThread.start();
1985        }
1986      });
1987    }
1988
1989    if (disabled) {
1990      custItem.setEnabled(false);
1991    }
1992
1993    beanContextMenu.add(custItem); 
1994  }
1995
1996  /**
1997   * Popup the customizer for this bean
1998   *
1999   * @param custClass the class of the customizer
2000   * @param bc the bean to be customized
2001   */
2002  private void popupCustomizer(Class custClass, JComponent bc) {
2003    try {
2004      // instantiate
2005      final Object customizer = custClass.newInstance();
2006      // set environment **before** setting object!!
2007      if (customizer instanceof EnvironmentHandler) {
2008        ((EnvironmentHandler)customizer).setEnvironment(m_flowEnvironment);
2009      }
2010      ((Customizer)customizer).setObject(bc);
2011      final javax.swing.JFrame jf = new javax.swing.JFrame();
2012      jf.getContentPane().setLayout(new BorderLayout());
2013      jf.getContentPane().add((JComponent)customizer, BorderLayout.CENTER);
2014      if (customizer instanceof CustomizerCloseRequester) {
2015        ((CustomizerCloseRequester)customizer).setParentFrame(jf);
2016      }
2017      jf.addWindowListener(new java.awt.event.WindowAdapter() {
2018          public void windowClosing(java.awt.event.WindowEvent e) {
2019            if (customizer instanceof CustomizerClosingListener) {
2020              ((CustomizerClosingListener)customizer).customizerClosing();
2021            }
2022            jf.dispose();
2023          }
2024        });
2025      jf.pack();
2026      jf.setVisible(true);
2027    } catch (Exception ex) {
2028      ex.printStackTrace();
2029    }
2030  }
2031
2032                               
2033  /**
2034   * Handles adding a custom MetaBean to the user toolbar
2035   *
2036   * @param bean the MetaBean
2037   * @param installListener install a listener for window close
2038   * events so as to save the user components
2039   */
2040  private void addToUserToolBar(MetaBean bean, 
2041                                boolean installListener) {
2042
2043    if (m_userToolBar == null) {
2044      // need to create the user tab and toolbar
2045      setUpUserToolBar();
2046    }
2047
2048    // Disconnect any beans connected to the inputs or outputs
2049    // of this MetaBean (prevents serialization of the entire
2050    // KnowledgeFlow!!)
2051    Vector tempRemovedConnections = new Vector();
2052    Vector allConnections = BeanConnection.getConnections();
2053    Vector inputs = bean.getInputs();
2054    Vector outputs = bean.getOutputs();
2055    Vector allComps = bean.getSubFlow();
2056       
2057    for (int i = 0; i < inputs.size(); i++) {
2058      BeanInstance temp = (BeanInstance)inputs.elementAt(i);
2059      // is this input a target for some event?
2060      for (int j = 0; j < allConnections.size(); j++) {
2061        BeanConnection tempC = (BeanConnection)allConnections.elementAt(j);
2062        if (tempC.getTarget() == temp) {
2063          tempRemovedConnections.add(tempC);
2064        }
2065       
2066        // also check to see if this input is a source for
2067        // some target that is *not* in the subFlow
2068        if (tempC.getSource() == temp && !bean.subFlowContains(tempC.getTarget())) {
2069          tempRemovedConnections.add(tempC);
2070        }
2071      }
2072    }
2073
2074    for (int i = 0; i < outputs.size(); i++) {
2075      BeanInstance temp = (BeanInstance)outputs.elementAt(i);
2076      // is this output a source for some target?
2077      for (int j = 0; j < allConnections.size(); j++) {
2078        BeanConnection tempC = (BeanConnection)allConnections.elementAt(j);
2079        if (tempC.getSource() == temp) {
2080          tempRemovedConnections.add(tempC);
2081        }
2082      }
2083    }
2084   
2085   
2086    for (int i = 0; i < tempRemovedConnections.size(); i++) {
2087      BeanConnection temp = 
2088        (BeanConnection)tempRemovedConnections.elementAt(i);
2089      temp.remove();
2090    }
2091   
2092    // now add to user tool bar
2093    JPanel tempUser = instantiateToolBarMetaBean(bean);
2094    m_userBoxPanel.add(tempUser);
2095    if (installListener && m_firstUserComponentOpp) {
2096      try {
2097        installWindowListenerForSavingUserBeans();
2098        m_firstUserComponentOpp = false;
2099      } catch (Exception ex) {
2100        ex.printStackTrace();
2101      }
2102    }
2103
2104    // Now reinstate any deleted connections to the original MetaBean
2105    for (int i = 0; i < tempRemovedConnections.size(); i++) {
2106      BeanConnection temp = 
2107        (BeanConnection)tempRemovedConnections.elementAt(i);
2108      BeanConnection newC = 
2109        new BeanConnection(temp.getSource(), temp.getTarget(),
2110                           temp.getSourceEventSetDescriptor());
2111    }   
2112  }
2113
2114  /**
2115   * Popup a menu giving choices for connections to delete (if any)
2116   *
2117   * @param closestConnections a vector containing 0 or more BeanConnections
2118   * @param x the x coordinate at which to popup the menu
2119   * @param y the y coordinate at which to popup the menu
2120   *
2121   * Modified by Zerbetto: javax.swing.JPopupMenu transformed into java.awt.PopupMenu
2122   */
2123  private void deleteConnectionPopup(Vector closestConnections, int x, int y) {
2124    if (closestConnections.size() > 0) {
2125      int menuItemCount = 0;
2126
2127      // modifications by Zerbetto
2128      //JPopupMenu deleteConnectionMenu = new JPopupMenu();
2129      PopupMenu deleteConnectionMenu = new PopupMenu();
2130
2131      //      deleteConnectionMenu.insert(new JLabel("Delete Connection",
2132      //                                             SwingConstants.CENTER),
2133      //                                  menuItemCount);
2134      MenuItem deleteConnection = new MenuItem("Delete Connection:");
2135      deleteConnection.setEnabled(false);
2136      deleteConnectionMenu.insert(deleteConnection, menuItemCount);
2137      menuItemCount++;
2138
2139      for (int i = 0; i < closestConnections.size(); i++) {
2140        final BeanConnection bc = (BeanConnection) closestConnections.elementAt(i);
2141        String connName = bc.getSourceEventSetDescriptor().getName();
2142
2143        //JMenuItem deleteItem = new JMenuItem(connName);
2144        String targetName = "";
2145        if (bc.getTarget().getBean() instanceof BeanCommon) {
2146          targetName = ((BeanCommon)bc.getTarget().getBean()).getCustomName();
2147        } else {
2148          targetName = bc.getTarget().getBean().getClass().getName();
2149          targetName = targetName.substring(targetName.lastIndexOf('.')+1, targetName.length());
2150        }
2151        MenuItem deleteItem = new MenuItem(connName + "-->" + targetName);
2152        deleteItem.addActionListener(new ActionListener() {
2153            public void actionPerformed(ActionEvent e) {
2154              bc.remove();
2155              m_beanLayout.revalidate();
2156              m_beanLayout.repaint();
2157              notifyIsDirty();
2158            }
2159          });
2160        deleteConnectionMenu.add(deleteItem);
2161        menuItemCount++;
2162      }
2163
2164      //deleteConnectionMenu.show(m_beanLayout, x, y);
2165      m_beanLayout.add(deleteConnectionMenu);
2166      deleteConnectionMenu.show(m_beanLayout, x, y);
2167    }
2168  }
2169
2170  /**
2171   * Initiates the connection process for two beans
2172   *
2173   * @param esd the EventSetDescriptor for the source bean
2174   * @param bi the source bean
2175   * @param x the x coordinate to start connecting from
2176   * @param y the y coordinate to start connecting from
2177   */
2178  private void connectComponents(EventSetDescriptor esd, 
2179                                 BeanInstance bi,
2180                                 int x,
2181                                 int y) {
2182    // record the event set descriptior for this event
2183    m_sourceEventSetDescriptor = esd;
2184
2185    Class listenerClass = esd.getListenerType(); // class of the listener
2186    JComponent source = (JComponent)bi.getBean();
2187    // now determine which (if any) of the other beans implement this
2188    // listener
2189    int targetCount = 0;
2190    Vector beanInstances = BeanInstance.getBeanInstances();
2191    for (int i = 0; i < beanInstances.size(); i++) {
2192      JComponent bean = 
2193        (JComponent)((BeanInstance)beanInstances.elementAt(i)).getBean();
2194      boolean connectable = false;
2195      boolean canContinue = false;
2196      if (bean != source) {
2197        if (bean instanceof MetaBean) {
2198          if (((MetaBean)bean).canAcceptConnection(listenerClass)) {
2199            canContinue = true;
2200          }
2201        } else if (listenerClass.isInstance(bean) && bean != source) {
2202          canContinue = true;
2203        }
2204      }
2205      if (canContinue) {
2206        if (!(bean instanceof BeanCommon)) {
2207          connectable = true; // assume this bean is happy to receive a connection
2208        } else {
2209          // give this bean a chance to veto any proposed connection via
2210          // the listener interface
2211          if (((BeanCommon)bean).
2212              //connectionAllowed(esd.getName())) {
2213              connectionAllowed(esd)) {
2214            connectable = true;
2215          }
2216        }
2217        if (connectable) {
2218          if (bean instanceof Visible) {
2219            targetCount++;
2220            ((Visible)bean).getVisual().setDisplayConnectors(true);
2221          }
2222        }
2223      }
2224    }
2225   
2226    // have some possible beans to connect to?
2227    if (targetCount > 0) {
2228      //      System.err.println("target count "+targetCount);
2229      if (source instanceof Visible) {
2230        ((Visible)source).getVisual().setDisplayConnectors(true);
2231      }
2232
2233      m_editElement = bi;
2234      Point closest = ((Visible)source).getVisual().
2235        getClosestConnectorPoint(new Point(x, y));
2236
2237      m_startX = (int)closest.getX();
2238      m_startY = (int)closest.getY();
2239      m_oldX = m_startX;
2240      m_oldY = m_startY;
2241
2242      Graphics2D gx = (Graphics2D)m_beanLayout.getGraphics();
2243      gx.setXORMode(java.awt.Color.white);
2244      gx.drawLine(m_startX, m_startY, m_startX, m_startY);
2245      gx.dispose();
2246      m_mode = CONNECTING;
2247    }
2248  }
2249
2250  private void addComponent(BeanInstance comp, boolean repaint) {
2251    if (comp.getBean() instanceof Visible) {
2252      ((Visible)comp.getBean()).getVisual().addPropertyChangeListener(this);
2253    }
2254    if (comp.getBean() instanceof BeanCommon) {
2255      ((BeanCommon)comp.getBean()).setLog(m_logPanel);
2256    }
2257    if (comp.getBean() instanceof MetaBean) {
2258      // re-align sub-beans
2259      Vector list;
2260     
2261      list = ((MetaBean) comp.getBean()).getInputs();
2262      for (int i = 0; i < list.size(); i++) {
2263        ((BeanInstance) list.get(i)).setX(comp.getX());
2264        ((BeanInstance) list.get(i)).setY(comp.getY());
2265      }
2266
2267      list = ((MetaBean) comp.getBean()).getOutputs();
2268      for (int i = 0; i < list.size(); i++) {
2269        ((BeanInstance) list.get(i)).setX(comp.getX());
2270        ((BeanInstance) list.get(i)).setY(comp.getY());
2271      }
2272    }
2273    setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
2274    if (repaint) {
2275      m_beanLayout.repaint();
2276    }
2277    m_pointerB.setSelected(true);
2278    m_mode = NONE;
2279  }
2280
2281  private void addComponent(int x, int y) {
2282    if (m_toolBarBean instanceof MetaBean) {
2283      // need to add the MetaBean's internal connections
2284      // to BeanConnection's vector
2285      Vector associatedConnections = 
2286        ((MetaBean)m_toolBarBean).getAssociatedConnections();
2287      BeanConnection.getConnections().addAll(associatedConnections);
2288    }
2289
2290    if (m_toolBarBean instanceof BeanContextChild) {
2291      m_bcSupport.add(m_toolBarBean);
2292    }
2293    BeanInstance bi = new BeanInstance(m_beanLayout, m_toolBarBean, x, y);
2294    //    addBean((JComponent)bi.getBean());
2295    m_toolBarBean = null;
2296    addComponent(bi, true);
2297  }
2298
2299  /**
2300   * Handles the checking of a selected set of components
2301   * for suitability for grouping. If suitable the user
2302   * is prompted for a name and then a MetaBean is used
2303   * group the components.
2304   */
2305  private void checkSubFlow(int startX, int startY,
2306                            int endX, int endY) {
2307
2308    java.awt.Rectangle r = 
2309      new java.awt.Rectangle((startX < endX) ? startX : endX,
2310                             (startY < endY) ? startY: endY,
2311                             Math.abs(startX - endX),
2312                             Math.abs(startY - endY));
2313    //    System.err.println(r);
2314    Vector selected = BeanInstance.findInstances(r);
2315    //    System.err.println(r);
2316    // check if sub flow is valid
2317    Vector inputs = BeanConnection.inputs(selected);
2318    Vector outputs = BeanConnection.outputs(selected);
2319   
2320    // screen the inputs and outputs
2321    if (inputs.size() == 0 || outputs.size() == 0) {
2322      return;
2323    }
2324
2325    // dissallow MetaBeans in the selected set (for the
2326    // time being).
2327    for (int i = 0; i < selected.size(); i++) {
2328      BeanInstance temp = (BeanInstance)selected.elementAt(i);
2329      if (temp.getBean() instanceof MetaBean) {
2330        return;
2331      }
2332    }
2333
2334    // show connector dots for selected beans
2335    for (int i = 0; i < selected.size(); i++) {
2336      BeanInstance temp = (BeanInstance)selected.elementAt(i);
2337      if (temp.getBean() instanceof Visible) {
2338        ((Visible)temp.getBean()).getVisual().setDisplayConnectors(true);
2339      }
2340    }
2341
2342    // show connector dots for input beans
2343    for (int i = 0; i < inputs.size(); i++) {
2344      BeanInstance temp = (BeanInstance)inputs.elementAt(i);
2345      if (temp.getBean() instanceof Visible) {
2346        ((Visible)temp.getBean()).getVisual().
2347          setDisplayConnectors(true, java.awt.Color.red);
2348      }
2349    }
2350
2351    // show connector dots for output beans
2352    for (int i = 0; i < outputs.size(); i++) {
2353      BeanInstance temp = (BeanInstance)outputs.elementAt(i);
2354      if (temp.getBean() instanceof Visible) {
2355        ((Visible)temp.getBean()).getVisual().
2356          setDisplayConnectors(true, java.awt.Color.green);
2357      }
2358    }
2359   
2360    BufferedImage subFlowPreview = null; 
2361    try {
2362        subFlowPreview = createImage(m_beanLayout, r);             
2363    } catch (IOException ex) {
2364      ex.printStackTrace();
2365      // drop through quietly
2366    }
2367
2368    // Confirmation pop-up
2369    int result = JOptionPane.showConfirmDialog(KnowledgeFlowApp.this,
2370                                               "Group this sub-flow?",
2371                                               "Group Components",
2372                                               JOptionPane.YES_NO_OPTION);
2373    if (result == JOptionPane.YES_OPTION) {
2374      Vector associatedConnections = 
2375        BeanConnection.associatedConnections(selected);
2376
2377      String name = JOptionPane.showInputDialog(KnowledgeFlowApp.this,
2378                                                "Enter a name for this group",
2379                                                "MyGroup");
2380      if (name != null) {       
2381        MetaBean group = new MetaBean();
2382        group.setSubFlow(selected);
2383        group.setAssociatedConnections(associatedConnections);
2384        group.setInputs(inputs);
2385        group.setOutputs(outputs);
2386        group.setSubFlowPreview(new ImageIcon(subFlowPreview));
2387        if (name.length() > 0) {
2388          //          group.getVisual().setText(name);
2389          group.setCustomName(name);
2390        }
2391       
2392        if (group instanceof BeanContextChild) {
2393          m_bcSupport.add(group);
2394        }
2395        BeanInstance bi = new BeanInstance(m_beanLayout, group, 
2396                                           (int)r.getX()+(int)(r.getWidth()/2),
2397                                           (int)r.getY()+(int)(r.getHeight()/2));
2398        for (int i = 0; i < selected.size(); i++) {
2399          BeanInstance temp = (BeanInstance)selected.elementAt(i);
2400          temp.removeBean(m_beanLayout);
2401          if (temp.getBean() instanceof Visible) {
2402            ((Visible)temp.getBean()).getVisual().removePropertyChangeListener(this);
2403          }
2404        }
2405        for (int i = 0; i < associatedConnections.size(); i++) {
2406          BeanConnection temp = (BeanConnection)associatedConnections.elementAt(i);
2407          temp.setHidden(true);
2408        }
2409        group.shiftBeans(bi, true);
2410       
2411        addComponent(bi, true);
2412      }
2413    }
2414
2415    // hide connector dots
2416    for (int i = 0; i < selected.size(); i++) {
2417      BeanInstance temp = (BeanInstance)selected.elementAt(i);
2418      if (temp.getBean() instanceof Visible) {
2419        ((Visible)temp.getBean()).getVisual().setDisplayConnectors(false);
2420      }
2421    }   
2422  }
2423
2424  /**
2425   * Accept property change events
2426   *
2427   * @param e a <code>PropertyChangeEvent</code> value
2428   */
2429  public void propertyChange(PropertyChangeEvent e) {
2430    revalidate();
2431    m_beanLayout.repaint();
2432  }
2433 
2434  /**
2435   * Load a pre-saved layout
2436   */
2437  private void loadLayout() {
2438    m_loadB.setEnabled(false);
2439    m_saveB.setEnabled(false);
2440    int returnVal = m_FileChooser.showOpenDialog(this);
2441    if (returnVal == JFileChooser.APPROVE_OPTION) {
2442      stopFlow();
2443
2444      // determine filename
2445      File oFile = m_FileChooser.getSelectedFile();
2446      // set internal flow directory environment variable
2447      m_flowEnvironment.addVariable("Internal.knowledgeflow.directory", oFile.getParent());
2448
2449      // add extension if necessary
2450      if (m_FileChooser.getFileFilter() == m_KfFilter) {
2451        if (!oFile.getName().toLowerCase().endsWith(FILE_EXTENSION)) {
2452          oFile = new File(oFile.getParent(), 
2453                           oFile.getName() + FILE_EXTENSION);
2454        }
2455      } else if (m_FileChooser.getFileFilter() == m_KOMLFilter) {
2456        if (!oFile.getName().toLowerCase().endsWith(KOML.FILE_EXTENSION + "kf")) {
2457          oFile = new File(oFile.getParent(), 
2458                           oFile.getName() + KOML.FILE_EXTENSION + "kf");
2459        }
2460      } else if (m_FileChooser.getFileFilter() == m_XMLFilter) {
2461        if (!oFile.getName().toLowerCase().endsWith(FILE_EXTENSION_XML)) {
2462          oFile = new File(oFile.getParent(), 
2463                           oFile.getName() + FILE_EXTENSION_XML);
2464        }
2465      } else if (m_FileChooser.getFileFilter() == m_XStreamFilter) {
2466        if (!oFile.getName().toLowerCase().endsWith(XStream.FILE_EXTENSION +"kf")) {
2467          oFile = new File(oFile.getParent(), 
2468                           oFile.getName() + XStream.FILE_EXTENSION + "kf");
2469        }
2470      }
2471   
2472      try {
2473        Vector beans       = new Vector();
2474        Vector connections = new Vector();
2475
2476        // KOML?
2477        if ( (KOML.isPresent()) && 
2478             (oFile.getAbsolutePath().toLowerCase().
2479              endsWith(KOML.FILE_EXTENSION + "kf")) ) {
2480          Vector v     = (Vector) KOML.read(oFile.getAbsolutePath());
2481          beans        = (Vector) v.get(XMLBeans.INDEX_BEANINSTANCES);
2482          connections  = (Vector) v.get(XMLBeans.INDEX_BEANCONNECTIONS);
2483        } /* XStream */ else if ( (XStream.isPresent()) && 
2484             (oFile.getAbsolutePath().toLowerCase().
2485              endsWith(XStream.FILE_EXTENSION + "kf")) ) {
2486          Vector v     = (Vector) XStream.read(oFile.getAbsolutePath());
2487          beans        = (Vector) v.get(XMLBeans.INDEX_BEANINSTANCES);
2488          connections  = (Vector) v.get(XMLBeans.INDEX_BEANCONNECTIONS);
2489        } /* XML? */ else if (oFile.getAbsolutePath().toLowerCase().
2490                              endsWith(FILE_EXTENSION_XML)) {
2491          XMLBeans xml = new XMLBeans(m_beanLayout, m_bcSupport); 
2492          Vector v     = (Vector) xml.read(oFile);
2493          beans        = (Vector) v.get(XMLBeans.INDEX_BEANINSTANCES);
2494          connections  = (Vector) v.get(XMLBeans.INDEX_BEANCONNECTIONS);
2495          //connections  = new Vector();
2496        } /* binary */ else {
2497          InputStream is = new FileInputStream(oFile);
2498          ObjectInputStream ois = new ObjectInputStream(is);
2499          beans = (Vector) ois.readObject();
2500          connections = (Vector) ois.readObject();
2501          ois.close();
2502        }
2503
2504        integrateFlow(beans, connections);
2505        setEnvironment();
2506        m_logPanel.clearStatus();
2507        m_logPanel.statusMessage("[KnowledgeFlow]|Flow loaded.");
2508      } catch (Exception ex) {
2509        m_logPanel.statusMessage("[KnowledgeFlow]|Unable to load flow (see log).");
2510        m_logPanel.logMessage("[KnowledgeFlow] Unable to load flow ("
2511            + ex.getMessage() + ").");
2512        ex.printStackTrace();
2513      }
2514    }
2515    m_loadB.setEnabled(true);
2516    m_saveB.setEnabled(true);
2517  }
2518
2519  // Link the supplied beans into the KnowledgeFlow gui
2520  private void integrateFlow(Vector beans, Vector connections) {
2521    java.awt.Color bckC = getBackground();
2522    m_bcSupport = new BeanContextSupport();
2523    m_bcSupport.setDesignTime(true);
2524
2525    // register this panel as a property change listener with each
2526    // bean
2527    for (int i = 0; i < beans.size(); i++) {
2528      BeanInstance tempB = (BeanInstance)beans.elementAt(i);
2529      if (tempB.getBean() instanceof Visible) {
2530        ((Visible)(tempB.getBean())).getVisual().
2531          addPropertyChangeListener(this);
2532
2533        // A workaround to account for JPanel's with their default
2534        // background colour not being serializable in Apple's JRE
2535        ((Visible)(tempB.getBean())).getVisual().
2536          setBackground(bckC);
2537        ((JComponent)(tempB.getBean())).setBackground(bckC);
2538      }
2539      if (tempB.getBean() instanceof BeanCommon) {
2540        ((BeanCommon)(tempB.getBean())).setLog(m_logPanel);
2541      }
2542      if (tempB.getBean() instanceof BeanContextChild) {
2543        m_bcSupport.add(tempB.getBean());
2544      }
2545    }
2546    BeanInstance.setBeanInstances(beans, m_beanLayout);
2547    BeanConnection.setConnections(connections);
2548    m_beanLayout.revalidate();
2549    m_beanLayout.repaint();
2550  }
2551
2552  /**
2553   * Set the flow for the KnowledgeFlow to edit. Assumes that client
2554   * has loaded a Vector of beans and a Vector of connections. the supplied
2555   * beans and connections are deep-copied via serialization before being
2556   * set in the layout.
2557   *
2558   * @param v a Vector containing a Vector of beans and a Vector of connections
2559   * @exception Exception if something goes wrong
2560   */
2561  public void setFlow(Vector v) throws Exception {
2562    //    Vector beansCopy = null, connectionsCopy = null;
2563    clearLayout();
2564    SerializedObject so = new SerializedObject(v);
2565    Vector copy = (Vector)so.getObject();
2566   
2567    Vector beans = (Vector)copy.elementAt(0);
2568    Vector connections = (Vector)copy.elementAt(1);
2569   
2570    // reset environment variables
2571    m_flowEnvironment = new Environment();
2572    integrateFlow(beans, connections);
2573  }
2574
2575  /**
2576   * Gets the current flow being edited. The flow is returned as a single
2577   * Vector containing two other Vectors: the beans and the connections.
2578   * These two vectors are deep-copied via serialization before being
2579   * returned.
2580   *
2581   * @return the current flow being edited
2582   */
2583  public Vector getFlow() throws Exception {
2584    Vector v = new Vector();
2585    Vector beans = BeanInstance.getBeanInstances();
2586    Vector connections = BeanConnection.getConnections();
2587    detachFromLayout(beans);
2588    v.add(beans);
2589    v.add(connections);
2590
2591    SerializedObject so = new SerializedObject(v);
2592    Vector copy = (Vector)so.getObject();
2593
2594    //    tempWrite(beans, connections);
2595   
2596    integrateFlow(beans, connections);
2597    return copy;
2598  }
2599 
2600  /**
2601   * Utility method to create an image of a region of the given component
2602   * @param component the component to create an image of
2603   * @param region the region of the component to put into the image
2604   * @return the image
2605   * @throws IOException
2606   */
2607  protected static BufferedImage createImage(JComponent component, Rectangle region)
2608  throws IOException {
2609    boolean opaqueValue = component.isOpaque();
2610    component.setOpaque( true );
2611    BufferedImage image = new BufferedImage(region.width, 
2612        region.height, BufferedImage.TYPE_INT_RGB);
2613    Graphics2D g2d = image.createGraphics();
2614    g2d.translate(-region.getX(), -region.getY());
2615    //g2d.setClip( region );
2616    component.paint( g2d );
2617    g2d.dispose();
2618    component.setOpaque( opaqueValue );
2619   
2620    return image;
2621  }
2622
2623  // Remove this panel as a property changle listener from
2624  // each bean
2625  private void detachFromLayout(Vector beans) {
2626    for (int i = 0; i < beans.size(); i++) {
2627      BeanInstance tempB = (BeanInstance)beans.elementAt(i);
2628      if (tempB.getBean() instanceof Visible) {
2629        ((Visible)(tempB.getBean())).getVisual().
2630          removePropertyChangeListener(this);
2631         
2632        if (tempB.getBean() instanceof MetaBean) {
2633          ((MetaBean)tempB.getBean()).
2634            removePropertyChangeListenersSubFlow(this);
2635        }
2636
2637        // A workaround to account for JPanel's with their default
2638        // background colour not being serializable in Apple's JRE.
2639        // JComponents are rendered with a funky stripy background
2640        // under OS X using java.awt.TexturePaint - unfortunately
2641        // TexturePaint doesn't implement Serializable.
2642        ((Visible)(tempB.getBean())).getVisual().
2643          setBackground(java.awt.Color.white);
2644        ((JComponent)(tempB.getBean())).setBackground(java.awt.Color.white);
2645      }
2646    }
2647  }
2648
2649  /**
2650   * Serialize the layout to a file
2651   */
2652  private void saveLayout() {
2653    //    m_loadB.setEnabled(false);
2654    //    m_saveB.setEnabled(false);
2655    int returnVal = m_FileChooser.showSaveDialog(this);
2656    java.awt.Color bckC = getBackground();
2657    if (returnVal == JFileChooser.APPROVE_OPTION) {
2658      // temporarily remove this panel as a property changle listener from
2659      // each bean
2660
2661      Vector beans = BeanInstance.getBeanInstances();
2662      detachFromLayout(beans);
2663
2664      // determine filename
2665      File sFile = m_FileChooser.getSelectedFile();
2666
2667      // add extension if necessary
2668      if (m_FileChooser.getFileFilter() == m_KfFilter) {
2669        if (!sFile.getName().toLowerCase().endsWith(FILE_EXTENSION)) {
2670          sFile = new File(sFile.getParent(), 
2671                           sFile.getName() + FILE_EXTENSION);
2672        }
2673      } else if (m_FileChooser.getFileFilter() == m_KOMLFilter) {
2674        if (!sFile.getName().toLowerCase().endsWith(KOML.FILE_EXTENSION + "kf")) {
2675          sFile = new File(sFile.getParent(), 
2676                           sFile.getName() + KOML.FILE_EXTENSION + "kf");
2677        }
2678      } else if (m_FileChooser.getFileFilter() == m_XStreamFilter) {
2679        if (!sFile.getName().toLowerCase().endsWith(XStream.FILE_EXTENSION + "kf")) {
2680          sFile = new File(sFile.getParent(), 
2681                           sFile.getName() + XStream.FILE_EXTENSION + "kf");
2682        }
2683      } else if (m_FileChooser.getFileFilter() == m_XMLFilter) {
2684        if (!sFile.getName().toLowerCase().endsWith(FILE_EXTENSION_XML)) {
2685          sFile = new File(sFile.getParent(), 
2686                           sFile.getName() + FILE_EXTENSION_XML);
2687        }
2688      }
2689   
2690      // now serialize components vector and connections vector
2691      try {
2692        // KOML?
2693        if ((KOML.isPresent()) && 
2694            (sFile.getAbsolutePath().toLowerCase().
2695             endsWith(KOML.FILE_EXTENSION + "kf")) ) {
2696          Vector v = new Vector();
2697          v.setSize(2);
2698          v.set(XMLBeans.INDEX_BEANINSTANCES, beans);
2699          v.set(XMLBeans.INDEX_BEANCONNECTIONS, BeanConnection.getConnections());
2700          KOML.write(sFile.getAbsolutePath(), v);
2701        } /* XStream */ else if ((XStream.isPresent()) && 
2702            (sFile.getAbsolutePath().toLowerCase().
2703             endsWith(XStream.FILE_EXTENSION + "kf")) ) {
2704          Vector v = new Vector();
2705          v.setSize(2);
2706          v.set(XMLBeans.INDEX_BEANINSTANCES, beans);
2707          v.set(XMLBeans.INDEX_BEANCONNECTIONS, BeanConnection.getConnections());
2708          XStream.write(sFile.getAbsolutePath(), v);
2709        } /* XML? */ else if (sFile.getAbsolutePath().
2710                              toLowerCase().endsWith(FILE_EXTENSION_XML)) {
2711          Vector v = new Vector();
2712          v.setSize(2);
2713          v.set(XMLBeans.INDEX_BEANINSTANCES, beans);
2714          v.set(XMLBeans.INDEX_BEANCONNECTIONS, BeanConnection.getConnections());
2715          XMLBeans xml = new XMLBeans(m_beanLayout, m_bcSupport); 
2716          xml.write(sFile, v);
2717        } /* binary */ else {
2718          OutputStream os = new FileOutputStream(sFile);
2719          ObjectOutputStream oos = new ObjectOutputStream(os);
2720          oos.writeObject(beans);
2721          oos.writeObject(BeanConnection.getConnections());
2722          oos.flush();
2723          oos.close();
2724        }
2725        m_logPanel.statusMessage("[KnowledgeFlow]|Flow saved.");
2726       
2727        // set the internal knowledgeflow directory environment var for this flow
2728        m_flowEnvironment.addVariable("Internal.knowledgeflow.directory", sFile.getParent());
2729        setEnvironment();
2730      } catch (Exception ex) {
2731        m_logPanel.statusMessage("[KnowledgeFlow]|Unable to save flow (see log).");
2732        m_logPanel.logMessage("[KnowledgeFlow] Unable to save flow ("
2733            + ex.getMessage() + ").");
2734        ex.printStackTrace();
2735      } finally {
2736        // restore this panel as a property change listener in the beans
2737        for (int i = 0; i < beans.size(); i++) {
2738          BeanInstance tempB = (BeanInstance)beans.elementAt(i);
2739          if (tempB.getBean() instanceof Visible) {
2740            ((Visible)(tempB.getBean())).getVisual().
2741              addPropertyChangeListener(this);
2742
2743            if (tempB.getBean() instanceof MetaBean) {
2744              ((MetaBean)tempB.getBean()).
2745                addPropertyChangeListenersSubFlow(this);
2746            }
2747            // Restore the default background colour
2748            ((Visible)(tempB.getBean())).getVisual().
2749              setBackground(bckC);
2750            ((JComponent)(tempB.getBean())).setBackground(bckC);
2751          }
2752        }
2753      }
2754    }
2755    //    m_saveB.setEnabled(true);
2756    //    m_loadB.setEnabled(true);
2757  }
2758
2759  /**
2760   * Save the knowledge flow into the OutputStream passed at input. Only
2761   * supports saving the layout data (no trained models) to XML.
2762   *
2763   * @param out         the output stream to save the layout in
2764   */
2765  public void saveLayout(OutputStream out) {
2766    // temporarily remove this panel as a property changle listener from
2767    // each bean
2768    Vector beans = BeanInstance.getBeanInstances();
2769
2770    for (int i = 0; i < beans.size(); i++) {
2771      BeanInstance tempB = (BeanInstance) beans.elementAt(i);
2772
2773      if (tempB.getBean() instanceof Visible) {
2774        ((Visible) (tempB.getBean())).getVisual()
2775         .removePropertyChangeListener(this);
2776
2777        if (tempB.getBean() instanceof MetaBean) {
2778          ((MetaBean) tempB.getBean()).removePropertyChangeListenersSubFlow(this);
2779        }
2780      }
2781    }
2782
2783    // now serialize components vector and connections vector
2784    try {
2785      Vector v = new Vector();
2786      v.setSize(2);
2787      v.set(XMLBeans.INDEX_BEANINSTANCES, beans);
2788      v.set(XMLBeans.INDEX_BEANCONNECTIONS, BeanConnection.getConnections());
2789
2790      XMLBeans xml = new XMLBeans(m_beanLayout, m_bcSupport);
2791      xml.write(out, v);
2792    } catch (Exception ex) {
2793      ex.printStackTrace();
2794    } finally {
2795      // restore this panel as a property change listener in the beans
2796      for (int i = 0; i < beans.size(); i++) {
2797        BeanInstance tempB = (BeanInstance) beans.elementAt(i);
2798
2799        if (tempB.getBean() instanceof Visible) {
2800          ((Visible) (tempB.getBean())).getVisual()
2801           .addPropertyChangeListener(this);
2802
2803          if (tempB.getBean() instanceof MetaBean) {
2804            ((MetaBean) tempB.getBean()).addPropertyChangeListenersSubFlow(this);
2805          }
2806        }
2807      }
2808    }
2809  }
2810
2811  private void loadUserComponents() {
2812    Vector tempV = null;
2813    String ext = "";
2814    if (m_UserComponentsInXML)
2815      ext = USERCOMPONENTS_XML_EXTENSION;
2816    File sFile = 
2817      new File(System.getProperty("user.home")
2818               +File.separator + ".knowledgeFlow"
2819               +File.separator + "userComponents"
2820               +ext);
2821    if (sFile.exists()) {
2822      try {
2823        if (m_UserComponentsInXML) {
2824          XMLBeans xml = new XMLBeans(m_beanLayout, m_bcSupport, XMLBeans.DATATYPE_USERCOMPONENTS);
2825          tempV = (Vector) xml.read(sFile);
2826        }
2827        else {
2828          InputStream is = new FileInputStream(sFile);
2829          ObjectInputStream ois = new ObjectInputStream(is);
2830          tempV = (Vector)ois.readObject();
2831          ois.close();
2832        }
2833      } catch (Exception ex) {
2834        System.err.println("[KnowledgeFlow] Problem reading user components.");
2835        ex.printStackTrace();
2836        return;
2837      }
2838      if (tempV.size() > 0) {
2839        // create the user tab and add the components
2840        for (int i = 0; i < tempV.size(); i++) {
2841          MetaBean tempB = (MetaBean)tempV.elementAt(i);
2842          addToUserToolBar(tempB, false);
2843        }
2844      }
2845    }
2846  }
2847
2848  private void installWindowListenerForSavingUserBeans() {
2849    ((java.awt.Window)getTopLevelAncestor()).
2850      addWindowListener(new java.awt.event.WindowAdapter() {
2851          public void windowClosing(java.awt.event.WindowEvent e) {
2852            System.out.println("[KnowledgeFlow] Saving user components....");
2853            File sFile = 
2854              new File(System.getProperty("user.home")
2855                       +File.separator+".knowledgeFlow");
2856            if (!sFile.exists()) {
2857              if (!sFile.mkdir()) {
2858                System.err.println("[KnowledgeFlow] Unable to create .knowledgeFlow "
2859                                   +"directory in your HOME.");
2860              } else {
2861                // make the plugins subdirectory for the user
2862                sFile = new File(sFile.toString() + File.separator 
2863                    + "plugins");
2864                sFile.mkdir();
2865              }
2866            }
2867            try {
2868              String ext = "";
2869              if (m_UserComponentsInXML)
2870                ext = USERCOMPONENTS_XML_EXTENSION;
2871              File sFile2 = new File(sFile.getAbsolutePath()
2872                                     +File.separator
2873                                     +"userComponents"
2874                                     +ext);
2875               
2876              if (m_UserComponentsInXML) {
2877                XMLBeans xml = new XMLBeans(m_beanLayout, m_bcSupport, XMLBeans.DATATYPE_USERCOMPONENTS);
2878                xml.write(sFile2, m_userComponents);
2879              }
2880              else {
2881                OutputStream os = new FileOutputStream(sFile2);
2882                ObjectOutputStream oos = new ObjectOutputStream(os);
2883                oos.writeObject(m_userComponents);
2884                oos.flush();
2885                oos.close();
2886              }
2887            } catch (Exception ex) {
2888              System.err.println("[KnowledgeFlow] Unable to save user components");
2889              ex.printStackTrace();
2890            } 
2891
2892          }
2893        });
2894  }
2895 
2896  /**
2897   * Utility method for grabbing the global info help (if it exists) from
2898   * an arbitrary object
2899   *
2900   * @param tempBean the object to grab global info from
2901   * @return the global help info or null if global info does not exist
2902   */
2903  public static String getGlobalInfo(Object tempBean) {
2904    // set tool tip text from global info if supplied
2905    String gi = null;
2906    try {
2907      BeanInfo bi = Introspector.getBeanInfo(tempBean.getClass());
2908      MethodDescriptor [] methods = bi.getMethodDescriptors();
2909      for (int i = 0; i < methods.length; i++) {
2910        String name = methods[i].getDisplayName();
2911        Method meth = methods[i].getMethod();
2912        if (name.equals("globalInfo")) {
2913          if (meth.getReturnType().equals(String.class)) {
2914            Object args[] = { };
2915            String globalInfo = (String)(meth.invoke(tempBean, args));
2916            gi = globalInfo;
2917            break;
2918          }
2919        }
2920      }
2921    } catch (Exception ex) {
2922     
2923    }
2924    return gi;
2925  }
2926
2927  /** variable for the KnowLedgeFlow class which would be set to null by the
2928      memory monitoring thread to free up some memory if we running out of
2929      memory.
2930   */
2931  private static KnowledgeFlowApp m_knowledgeFlow;
2932
2933  /** for monitoring the Memory consumption */
2934  private static Memory m_Memory = new Memory(true);
2935
2936  // list of things to be notified when the startup process of
2937  // the KnowledgeFlow is complete
2938  public static Vector s_startupListeners = new Vector();
2939
2940  // modifications by Zerbetto
2941  // If showFileMenu is true, the file menu (open file, new file, save file buttons) is showed
2942  private boolean m_showFileMenu = true;
2943 
2944  /**
2945   * Create the singleton instance of the KnowledgeFlow
2946   * @param args can contain a file argument for loading a flow layout
2947   * (format: "file=[path to layout file]")
2948   * Modified by Zerbetto: you can specify the path of a knowledge flow layout file at input
2949   */
2950  public static void createSingleton(String[] args) {
2951    //modifications by Zerbetto 05-12-2007
2952    String fileName = null;
2953    boolean showFileMenu = true;
2954
2955    if ((args != null) && (args.length > 0)) {
2956      for (int i = 0; i < args.length; i++) {
2957        String arg = args[i];
2958
2959        if (arg.startsWith("file=")) {
2960          fileName = arg.substring("file=".length());
2961        } else if (arg.startsWith("showFileMenu=")) {
2962          showFileMenu = Boolean.parseBoolean(arg.substring(
2963                "showFileMenu=".length()));
2964        }
2965      }
2966    }
2967
2968    if (m_knowledgeFlow == null) {
2969      m_knowledgeFlow = new KnowledgeFlowApp(showFileMenu);
2970    }
2971
2972    // end modifications by Zerbetto
2973
2974    // notify listeners (if any)
2975    for (int i = 0; i < s_startupListeners.size(); i++) {
2976      ((StartUpListener) s_startupListeners.elementAt(i)).startUpComplete();
2977    }
2978
2979    //modifications by Zerbetto 05-12-2007
2980    if (fileName != null) {
2981      m_knowledgeFlow.loadInitialLayout(fileName);
2982    }
2983
2984    // end modifications
2985  }
2986
2987  /**
2988   * Return the singleton instance of the KnowledgeFlow
2989   *
2990   * @return the singleton instance
2991   */
2992  public static KnowledgeFlowApp getSingleton() {
2993    return m_knowledgeFlow;
2994  }
2995
2996  /**
2997   * Add a listener to be notified when startup is complete
2998   *
2999   * @param s a listener to add
3000   */
3001  public static void addStartupListener(StartUpListener s) {
3002    s_startupListeners.add(s);
3003  }
3004
3005  /**
3006   * Loads the specified file at input
3007   *
3008   * Added by Zerbetto
3009   */
3010  //modifications by Zerbetto 05-12-2007
3011  private void loadInitialLayout(String fileName) {
3012    File oFile = new File(fileName);
3013
3014    if (oFile.exists() && oFile.isFile()) {
3015      m_FileChooser.setSelectedFile(oFile);
3016
3017      int index = fileName.lastIndexOf('.');
3018
3019      if (index != -1) {
3020        String extension = fileName.substring(index);
3021
3022        if (FILE_EXTENSION_XML.equalsIgnoreCase(extension)) {
3023          m_FileChooser.setFileFilter(m_knowledgeFlow.m_XMLFilter);
3024        } else if (FILE_EXTENSION.equalsIgnoreCase(extension)) {
3025          m_FileChooser.setFileFilter(m_knowledgeFlow.m_KfFilter);
3026        }
3027      }
3028    } else {
3029      System.err.println("[KnowledgeFlow] File '" + fileName + "' does not exists.");
3030    }
3031
3032    try {
3033      Vector beans = new Vector();
3034      Vector connections = new Vector();
3035
3036      // KOML?
3037      if ((KOML.isPresent()) &&
3038            (oFile.getAbsolutePath().toLowerCase().endsWith(KOML.FILE_EXTENSION))) {
3039        Vector v = (Vector) KOML.read(oFile.getAbsolutePath());
3040        beans = (Vector) v.get(XMLBeans.INDEX_BEANINSTANCES);
3041        connections = (Vector) v.get(XMLBeans.INDEX_BEANCONNECTIONS);
3042      } /* XML? */ else if (oFile.getAbsolutePath().toLowerCase()
3043                                     .endsWith(FILE_EXTENSION_XML)) {
3044        XMLBeans xml = new XMLBeans(m_beanLayout, m_bcSupport);
3045        Vector v = (Vector) xml.read(oFile);
3046        beans = (Vector) v.get(XMLBeans.INDEX_BEANINSTANCES);
3047        connections = (Vector) v.get(XMLBeans.INDEX_BEANCONNECTIONS);
3048
3049        //connections  = new Vector();
3050      } /* binary */ else {
3051        InputStream is = new FileInputStream(oFile);
3052        ObjectInputStream ois = new ObjectInputStream(is);
3053        beans = (Vector) ois.readObject();
3054        connections = (Vector) ois.readObject();
3055        ois.close();
3056      }
3057
3058      java.awt.Color bckC = getBackground();
3059      m_bcSupport = new BeanContextSupport();
3060      m_bcSupport.setDesignTime(true);
3061
3062      // register this panel as a property change listener with each
3063      // bean
3064      for (int i = 0; i < beans.size(); i++) {
3065        BeanInstance tempB = (BeanInstance) beans.elementAt(i);
3066
3067        if (tempB.getBean() instanceof Visible) {
3068          ((Visible) (tempB.getBean())).getVisual()
3069           .addPropertyChangeListener(this);
3070
3071          // A workaround to account for JPanel's with their default
3072          // background colour not being serializable in Apple's JRE
3073          ((Visible) (tempB.getBean())).getVisual().setBackground(bckC);
3074          ((JComponent) (tempB.getBean())).setBackground(bckC);
3075        }
3076
3077        if (tempB.getBean() instanceof BeanCommon) {
3078          ((BeanCommon) (tempB.getBean())).setLog(m_logPanel);
3079        }
3080
3081        if (tempB.getBean() instanceof BeanContextChild) {
3082          m_bcSupport.add(tempB.getBean());
3083        }
3084      }
3085
3086      BeanInstance.setBeanInstances(beans, m_beanLayout);
3087      BeanConnection.setConnections(connections);
3088      m_beanLayout.revalidate();
3089      m_beanLayout.repaint();
3090    } catch (Exception ex) {
3091      ex.printStackTrace();
3092    }
3093  }
3094
3095  //end modifications
3096
3097  /**
3098   * Notifies to the parent swt that the layout is dirty
3099   *
3100   * Added by Zerbetto
3101   */
3102  private void notifyIsDirty() {
3103    //this.firePropertyChange(new Integer(IEditorPart.PROP_DIRTY).toString(), null, null);
3104    this.firePropertyChange("PROP_DIRTY", null, null);
3105  }
3106
3107  /**
3108   * Main method.
3109   *
3110   * @param args a <code>String[]</code> value
3111   */
3112  public static void main(String [] args) {
3113
3114    LookAndFeel.setLookAndFeel();
3115   
3116    try {
3117      // uncomment to disable the memory management:
3118      //m_Memory.setEnabled(false);
3119
3120      final javax.swing.JFrame jf = new javax.swing.JFrame();
3121      jf.getContentPane().setLayout(new java.awt.BorderLayout());
3122      //final KnowledgeFlowApp tm = new KnowledgeFlowApp();
3123      m_knowledgeFlow = new KnowledgeFlowApp(true);
3124
3125      jf.getContentPane().add(m_knowledgeFlow, java.awt.BorderLayout.CENTER);
3126      jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
3127
3128      jf.setSize(1000,750);
3129      jf.setVisible(true);     
3130
3131     
3132      Thread memMonitor = new Thread() {
3133        public void run() {
3134          while(true) {
3135            try {
3136              //System.out.println("Before sleeping");
3137              this.sleep(4000);
3138             
3139              System.gc();
3140
3141              if (m_Memory.isOutOfMemory()) {
3142                // clean up
3143                jf.dispose();
3144                m_knowledgeFlow = null;
3145                System.gc();
3146
3147                // stop threads
3148                m_Memory.stopThreads();
3149               
3150                // display error
3151                System.err.println("\n[KnowledgeFlow] displayed message:");
3152                m_Memory.showOutOfMemory();
3153                System.err.println("\nexiting");
3154                System.exit(-1);
3155              }
3156
3157            } catch(InterruptedException ex) { ex.printStackTrace(); }
3158          }
3159        }
3160      };
3161
3162      memMonitor.setPriority(Thread.NORM_PRIORITY);
3163      memMonitor.start();
3164    } catch (Exception ex) {
3165      ex.printStackTrace();
3166      System.err.println(ex.getMessage());
3167    }
3168  }
3169}
Note: See TracBrowser for help on using the repository browser.