source: src/main/java/weka/classifiers/bayes/net/GUI.java @ 24

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

Import di weka.

File size: 109.5 KB
Line 
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 *    GUI.java
19 *    Copyright (C) 2007 University of Waikato, Hamilton, New Zealand
20 *
21 */
22package weka.classifiers.bayes.net;
23
24import weka.classifiers.bayes.net.MarginCalculator.JunctionTreeNode;
25import weka.core.FastVector;
26import weka.core.Instances;
27import weka.core.OptionHandler;
28import weka.core.SerializedObject;
29import weka.core.Utils;
30import weka.core.converters.AbstractFileLoader;
31import weka.core.converters.AbstractFileSaver;
32import weka.core.converters.ArffSaver;
33import weka.core.converters.ConverterUtils;
34import weka.gui.ConverterFileChooser;
35import weka.gui.ExtensionFileFilter;
36import weka.gui.GenericObjectEditor;
37import weka.gui.LookAndFeel;
38import weka.gui.PropertyDialog;
39import weka.gui.graphvisualizer.BIFFormatException;
40import weka.gui.graphvisualizer.BIFParser;
41import weka.gui.graphvisualizer.GraphNode;
42import weka.gui.graphvisualizer.HierarchicalBCEngine;
43import weka.gui.graphvisualizer.LayoutCompleteEvent;
44import weka.gui.graphvisualizer.LayoutCompleteEventListener;
45import weka.gui.graphvisualizer.LayoutEngine;
46import weka.gui.visualize.PrintablePanel;
47
48import java.awt.BorderLayout;
49import java.awt.Color;
50import java.awt.Container;
51import java.awt.Dimension;
52import java.awt.Font;
53import java.awt.FontMetrics;
54import java.awt.Frame;
55import java.awt.Graphics;
56import java.awt.Graphics2D;
57import java.awt.GridBagConstraints;
58import java.awt.GridBagLayout;
59import java.awt.GridLayout;
60import java.awt.Insets;
61import java.awt.Rectangle;
62import java.awt.RenderingHints;
63import java.awt.event.ActionEvent;
64import java.awt.event.ActionListener;
65import java.awt.event.MouseAdapter;
66import java.awt.event.MouseEvent;
67import java.awt.event.MouseMotionAdapter;
68import java.awt.event.WindowAdapter;
69import java.awt.event.WindowEvent;
70import java.awt.image.BufferedImage;
71import java.awt.print.PageFormat;
72import java.awt.print.Printable;
73import java.awt.print.PrinterException;
74import java.awt.print.PrinterJob;
75import java.beans.PropertyEditor;
76import java.io.File;
77import java.io.FileReader;
78import java.io.FileWriter;
79import java.io.IOException;
80import java.util.Random;
81
82import javax.swing.AbstractAction;
83import javax.swing.Action;
84import javax.swing.BorderFactory;
85import javax.swing.ImageIcon;
86import javax.swing.JButton;
87import javax.swing.JCheckBox;
88import javax.swing.JCheckBoxMenuItem;
89import javax.swing.JDialog;
90import javax.swing.JFileChooser;
91import javax.swing.JFrame;
92import javax.swing.JLabel;
93import javax.swing.JMenu;
94import javax.swing.JMenuBar;
95import javax.swing.JMenuItem;
96import javax.swing.JOptionPane;
97import javax.swing.JPanel;
98import javax.swing.JPopupMenu;
99import javax.swing.JScrollPane;
100import javax.swing.JTable;
101import javax.swing.JTextField;
102import javax.swing.JToolBar;
103import javax.swing.KeyStroke;
104import javax.swing.table.AbstractTableModel;
105
106/**
107 * GUI interface to Bayesian Networks. Allows editing Bayesian networks
108 * on screen and provides GUI interface to various Bayesian network facilities
109 * in Weka, including random network generation, data set generation and
110 * Bayesion network inference.
111 *
112 * @author Remco Bouckaert (remco@cs.waikato.ac.nz)
113 * @version $Revision: 4902 $
114 */
115public class GUI extends JPanel implements LayoutCompleteEventListener {
116
117        /** for serialization */
118        private static final long serialVersionUID = -2038911085935515624L;
119
120        /** The current LayoutEngine */
121        protected LayoutEngine m_layoutEngine;
122
123        /** Panel actually displaying the graph */
124        protected GraphPanel m_GraphPanel;
125
126        /** Container of Bayesian network */
127        EditableBayesNet m_BayesNet = new EditableBayesNet(true);
128
129        /** String containing file name storing current network */
130        protected String m_sFileName = "";
131        /** used for calculating marginals in Bayesian netwowrks */
132        MarginCalculator m_marginCalculator = null;
133
134        /**
135         * used for calculating marginals in Bayesian netwowrks when evidence is
136         * present
137         */
138        MarginCalculator m_marginCalculatorWithEvidence = null;
139
140        /** flag indicating whether marginal distributions of each of the nodes
141         * should be shown in display.
142         */
143        boolean m_bViewMargins = false;
144        boolean m_bViewCliques = false;
145       
146        /** The menu bar */
147        private JMenuBar m_menuBar;
148
149        /** data selected from file. Used to train a Bayesian network on */
150        Instances m_Instances = null;
151
152        /** Text field for specifying zoom */
153        final JTextField m_jTfZoom;
154        /** toolbar containing buttons at top of window */
155        final JToolBar m_jTbTools;
156        /** status bar at bottom of window */
157        final JLabel m_jStatusBar;
158        /** TextField for node's width */
159        private final JTextField m_jTfNodeWidth = new JTextField(3);
160        /** TextField for nodes height */
161        private final JTextField m_jTfNodeHeight = new JTextField(3);
162        /** this contains the m_GraphPanel GraphPanel */
163        JScrollPane m_jScrollPane;
164
165        /** path for icons */
166        private final String ICONPATH = "weka/classifiers/bayes/net/icons/";
167
168        /** current zoom value */
169        private double m_fScale = 1;
170
171        /** standard width of node */
172        private int m_nNodeHeight = 2 * getFontMetrics(getFont()).getHeight();
173        /** standard height of node */
174        final static int DEFAULT_NODE_WIDTH = 50;
175        private int m_nNodeWidth = DEFAULT_NODE_WIDTH;
176        /** width of node, allowing for some padding */ 
177        final static int PADDING = 10;
178        private int m_nPaddedNodeWidth = DEFAULT_NODE_WIDTH + PADDING;
179
180
181        /** used when using zoomIn and zoomOut buttons */
182        private int [] m_nZoomPercents = { 10, 25, 50, 75, 100, 125, 150, 175, 200, 225, 250, 275, 300, 350, 400, 450, 500,
183                        550, 600, 650, 700, 800, 900, 999 };
184
185        /** actions triggered by GUI events */
186        Action a_new = new ActionNew();
187
188        Action a_quit = new ActionQuit();
189        Action a_save = new ActionSave();
190        ActionExport a_export = new ActionExport();
191        ActionPrint a_print = new ActionPrint();
192        Action a_load = new ActionLoad();
193        Action a_zoomin = new ActionZoomIn();
194        Action a_zoomout = new ActionZoomOut();
195        Action a_layout = new ActionLayout();
196
197        Action a_saveas = new ActionSaveAs();
198
199        Action a_viewtoolbar = new ActionViewToolbar();
200
201        Action a_viewstatusbar = new ActionViewStatusbar();
202
203        Action a_networkgenerator = new ActionGenerateNetwork();
204
205        Action a_datagenerator = new ActionGenerateData();
206
207        Action a_datasetter = new ActionSetData();
208
209        Action a_learn = new ActionLearn();
210        Action a_learnCPT = new ActionLearnCPT();
211
212        Action a_help = new ActionHelp();
213
214        Action a_about = new ActionAbout();
215
216        ActionAddNode a_addnode = new ActionAddNode();
217
218        Action a_delnode = new ActionDeleteNode();
219        Action a_cutnode = new ActionCutNode();
220        Action a_copynode = new ActionCopyNode();
221        Action a_pastenode = new ActionPasteNode();
222        Action a_selectall = new ActionSelectAll();
223
224        Action a_addarc = new ActionAddArc();
225
226        Action a_delarc = new ActionDeleteArc();
227
228        Action a_undo = new ActionUndo();
229
230        Action a_redo= new ActionRedo();
231       
232        Action a_alignleft = new ActionAlignLeft();
233        Action a_alignright = new ActionAlignRight();
234        Action a_aligntop = new ActionAlignTop();
235        Action a_alignbottom = new ActionAlignBottom();
236        Action a_centerhorizontal = new ActionCenterHorizontal();
237        Action a_centervertical = new ActionCenterVertical();
238        Action a_spacehorizontal = new ActionSpaceHorizontal();
239        Action a_spacevertical = new ActionSpaceVertical();
240       
241        /** node currently selected through right clicking */
242        int m_nCurrentNode = -1;
243        /** selection of nodes */
244        Selection m_Selection = new Selection();
245        /** selection rectangle drawn through dragging with left mouse button */
246        Rectangle m_nSelectedRect = null;
247
248       
249        class Selection {
250                FastVector m_selected;
251                public Selection() {
252                        m_selected = new FastVector();
253                } // c'tor
254                public FastVector getSelected() {return m_selected;}
255                void updateGUI() {
256                        if (m_selected.size() > 0) {
257                                a_cutnode.setEnabled(true);
258                                a_copynode.setEnabled(true);
259                        } else {
260                                a_cutnode.setEnabled(false);
261                                a_copynode.setEnabled(false);
262                        }
263                        if (m_selected.size() > 1) {
264                                a_alignleft.setEnabled(true);
265                                a_alignright.setEnabled(true);
266                                a_aligntop.setEnabled(true);
267                                a_alignbottom.setEnabled(true);
268                                a_centerhorizontal.setEnabled(true);
269                                a_centervertical.setEnabled(true);
270                                a_spacehorizontal.setEnabled(true);
271                                a_spacevertical.setEnabled(true);
272                        } else {
273                                a_alignleft.setEnabled(false);
274                                a_alignright.setEnabled(false);
275                                a_aligntop.setEnabled(false);
276                                a_alignbottom.setEnabled(false);
277                                a_centerhorizontal.setEnabled(false);
278                                a_centervertical.setEnabled(false);
279                                a_spacehorizontal.setEnabled(false);
280                                a_spacevertical.setEnabled(false);
281                        }
282                } // updateGUI
283               
284                public void addToSelection(int nNode) {
285                        for (int iNode = 0; iNode < m_selected.size(); iNode++) {
286                                if (nNode == (Integer) m_selected.elementAt(iNode)) {
287                                        return;
288                                }
289                        }
290                        m_selected.addElement(nNode);
291                        updateGUI();
292                } // addToSelection
293               
294                public void addToSelection(int [] iNodes) {
295                        for (int iNode = 0; iNode < iNodes.length; iNode++) {
296                                addToSelection(iNodes[iNode]);
297                        }
298                        updateGUI();
299                } // addToSelection
300               
301                public void addToSelection(Rectangle selectedRect) {
302                        for (int iNode = 0; iNode < m_BayesNet.getNrOfNodes(); iNode++) {
303                                if (contains(selectedRect, iNode)) {
304                                        addToSelection(iNode);
305                                }
306                        }
307                } // addToSelection
308               
309                public void selectAll() {
310                        m_selected.removeAllElements();
311                        for (int iNode = 0; iNode < m_BayesNet.getNrOfNodes(); iNode++) {
312                                m_selected.addElement(iNode);
313                        }
314                        updateGUI();
315                } // selectAll
316
317                boolean contains(Rectangle rect, int iNode) {
318                        return rect.intersects((m_BayesNet.getPositionX(iNode)) * m_fScale,
319                                        (m_BayesNet.getPositionY(iNode)) * m_fScale,
320                                        m_nPaddedNodeWidth * m_fScale, m_nNodeHeight * m_fScale);
321                } // contains
322               
323                public void removeFromSelection(int nNode) {
324                        for (int iNode = 0; iNode < m_selected.size(); iNode++) {
325                                if (nNode == (Integer) m_selected.elementAt(iNode)) {
326                                        m_selected.removeElementAt(iNode);
327                                }
328                        }
329                        updateGUI();
330                } // removeFromSelection
331
332                public void toggleSelection(int nNode) {
333                        for (int iNode = 0; iNode < m_selected.size(); iNode++) {
334                                if (nNode == (Integer) m_selected.elementAt(iNode)) {
335                                        m_selected.removeElementAt(iNode);
336                                        updateGUI();
337                                        return;
338                                }
339                        }
340                        addToSelection(nNode);
341                } // toggleSelection
342
343                public void toggleSelection(Rectangle selectedRect)     {
344                        for (int iNode = 0; iNode < m_BayesNet.getNrOfNodes(); iNode++) {
345                                if (contains(selectedRect, iNode)) {
346                                        toggleSelection(iNode);
347                                }
348                        }
349                } // toggleSelection
350               
351                public void clear() {
352                        m_selected.removeAllElements();
353                        updateGUI();
354                }
355               
356                public void draw(Graphics g) {
357                        if (m_selected.size() == 0) {
358                                return;
359                        }
360
361                        for (int iNode = 0; iNode < m_selected.size(); iNode++) {
362                                int nNode = (Integer) m_selected.elementAt(iNode);
363                                int nPosX = m_BayesNet.getPositionX(nNode);
364                                int nPosY = m_BayesNet.getPositionY(nNode);
365                                g.setColor(Color.BLACK);
366                                int nXRC = nPosX + m_nPaddedNodeWidth - m_nNodeWidth - (m_nPaddedNodeWidth - m_nNodeWidth) / 2;
367                                int nYRC = nPosY;
368                                int d = 5;
369                                g.fillRect(nXRC, nYRC, d, d); 
370                                g.fillRect(nXRC, nYRC + m_nNodeHeight, d, d); 
371                                g.fillRect(nXRC + m_nNodeWidth, nYRC, d, d); 
372                                g.fillRect(nXRC + m_nNodeWidth, nYRC + m_nNodeHeight, d, d); 
373                        }
374                } // draw
375        } // Selection
376
377        ClipBoard m_clipboard = new ClipBoard();
378       
379        class ClipBoard {
380                String m_sText = null;
381                public ClipBoard() {
382                        if (a_pastenode != null) {
383                                a_pastenode.setEnabled(false);
384                        }
385                }
386                public boolean hasText() {return m_sText != null;}
387                public String getText() { 
388                        return m_sText;
389                }
390                public void setText(String sText) {
391                        m_sText = sText;
392                        a_pastenode.setEnabled(true);
393                }
394        } // class ClipBoard
395       
396        /** Base class used for definining actions
397         * with a name, tool tip text, possibly an icon and accelerator key.
398         * */
399        class MyAction extends AbstractAction {
400                /** for serialization */
401                private static final long serialVersionUID = -2038911111935517L;
402
403                public MyAction(String sName, String sToolTipText, String sIcon, String sAcceleratorKey) {
404                        super(sName);
405                        //setToolTipText(sToolTipText);
406                        putValue(Action.SHORT_DESCRIPTION, sToolTipText);
407                        putValue(Action.LONG_DESCRIPTION, sToolTipText);
408                        if (sAcceleratorKey.length() > 0) {
409                                KeyStroke keyStroke = KeyStroke.getKeyStroke(sAcceleratorKey);
410                                putValue(Action.ACCELERATOR_KEY, keyStroke);
411                        }
412                        putValue(Action.MNEMONIC_KEY, (int) sName.charAt(0));
413                        java.net.URL tempURL = ClassLoader.getSystemResource(ICONPATH + sIcon + ".png");
414                        if (tempURL != null) {
415                                putValue(Action.SMALL_ICON, new ImageIcon(tempURL));
416                        } else {
417                                putValue(Action.SMALL_ICON, new ImageIcon(new BufferedImage(20,20, BufferedImage.TYPE_4BYTE_ABGR)));
418                                //System.err.println(ICONPATH + sIcon + ".png not found for weka.gui.graphvisualizer.Graph");
419                        }
420                } // c'tor
421
422                /* Place holder. Should be implemented by derived classes.
423                 *  (non-Javadoc)
424                 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
425                 */
426                public void actionPerformed(ActionEvent ae) {}
427        } // class MyAction
428
429        class ActionGenerateNetwork extends MyAction {
430                /** for serialization */
431                private static final long serialVersionUID = -2038911085935517L;
432
433                public ActionGenerateNetwork() {
434                        super("Generate Network", "Generate Random Bayesian Network", "generate.network", "ctrl N");
435                } // c'tor
436
437                int m_nNrOfNodes = 10;
438
439                int m_nNrOfArcs = 15;
440
441                int m_nCardinality = 2;
442
443                int m_nSeed = 123;
444
445                JDialog dlg = null;
446
447                public void actionPerformed(ActionEvent ae) {
448                        if (dlg == null) {
449                                dlg = new JDialog();
450                                dlg.setTitle("Generate Random Bayesian Network Options");
451
452                                final JLabel jLbNrOfNodes = new JLabel("Nr of nodes");
453                                final JTextField jTfNrOfNodes = new JTextField(3);
454                                jTfNrOfNodes.setHorizontalAlignment(JTextField.CENTER);
455                                jTfNrOfNodes.setText("" + m_nNrOfNodes);
456                                final JLabel jLbNrOfArcs = new JLabel("Nr of arcs");
457                                final JTextField jTfNrOfArcs = new JTextField(3);
458                                jTfNrOfArcs.setHorizontalAlignment(JTextField.CENTER);
459                                jTfNrOfArcs.setText("" + m_nNrOfArcs);
460                                final JLabel jLbCardinality = new JLabel("Cardinality");
461                                final JTextField jTfCardinality = new JTextField(3);
462                                jTfCardinality.setHorizontalAlignment(JTextField.CENTER);
463                                jTfCardinality.setText("" + m_nCardinality);
464                                final JLabel jLbSeed = new JLabel("Random seed");
465                                final JTextField jTfSeed = new JTextField(3);
466                                jTfSeed.setHorizontalAlignment(JTextField.CENTER);
467                                jTfSeed.setText("" + m_nSeed);
468
469                                JButton jBtGo;
470                                jBtGo = new JButton("Generate Network");
471
472                                jBtGo.addActionListener(new ActionListener() {
473                                        public void actionPerformed(ActionEvent ae) {
474                                                try {
475                                                        BayesNetGenerator generator = new BayesNetGenerator();
476                                                        m_BayesNet = generator;
477                                                        m_BayesNet.clearUndoStack();
478                                                       
479                                                        String[] options = new String[8];
480                                                        options[0] = "-N";
481                                                        options[1] = "" + jTfNrOfNodes.getText();
482                                                        options[2] = "-A";
483                                                        options[3] = "" + jTfNrOfArcs.getText();
484                                                        options[4] = "-C";
485                                                        options[5] = "" + jTfCardinality.getText();
486                                                        options[6] = "-S";
487                                                        options[7] = "" + jTfSeed.getText();
488                                                        generator.setOptions(options);
489                                                        generator.generateRandomNetwork();
490                                                        // Convert to EditableBayesNet
491                                                        // This ensures the getOptions() called by GenericObjectEditor to get the correct result.
492                                                        BIFReader bifReader = new BIFReader();
493                                                        bifReader.processString(m_BayesNet.toXMLBIF03());
494                                                        m_BayesNet = new EditableBayesNet(bifReader);
495
496                                                        updateStatus();
497                                                        layoutGraph();
498                                                        a_datagenerator.setEnabled(true);
499                                                        m_Instances = null;;
500                                                        a_learn.setEnabled(false);
501                                                        a_learnCPT.setEnabled(false);
502
503                                                        dlg.setVisible(false);
504                                                } catch (Exception e) {
505                                                        e.printStackTrace();
506                                                }
507                                        }
508                                });
509
510                                JButton jBtCancel;
511                                jBtCancel = new JButton("Cancel");
512                                jBtCancel.setMnemonic('C');
513                                jBtCancel.addActionListener(new ActionListener() {
514                                        public void actionPerformed(ActionEvent ae) {
515                                                dlg.setVisible(false);
516                                        }
517                                });
518                                GridBagConstraints gbc = new GridBagConstraints();
519                                dlg.setLayout(new GridBagLayout());
520
521                                Container c = new Container();
522                                c.setLayout(new GridBagLayout());
523                                gbc.gridwidth = 2;
524                                gbc.insets = new Insets(8, 0, 0, 0);
525                                gbc.anchor = GridBagConstraints.NORTHWEST;
526                                gbc.gridwidth = GridBagConstraints.RELATIVE;
527                                gbc.fill = GridBagConstraints.HORIZONTAL;
528                                c.add(jLbNrOfNodes, gbc);
529                                gbc.gridwidth = GridBagConstraints.REMAINDER;
530                                c.add(jTfNrOfNodes, gbc);
531                                gbc.gridwidth = GridBagConstraints.RELATIVE;
532                                c.add(jLbNrOfArcs, gbc);
533                                gbc.gridwidth = GridBagConstraints.REMAINDER;
534                                c.add(jTfNrOfArcs, gbc);
535                                gbc.gridwidth = GridBagConstraints.RELATIVE;
536                                c.add(jLbCardinality, gbc);
537                                gbc.gridwidth = GridBagConstraints.REMAINDER;
538                                c.add(jTfCardinality, gbc);
539                                gbc.gridwidth = GridBagConstraints.RELATIVE;
540                                c.add(jLbSeed, gbc);
541                                gbc.gridwidth = GridBagConstraints.REMAINDER;
542                                c.add(jTfSeed, gbc);
543
544                                gbc.fill = GridBagConstraints.HORIZONTAL;
545                                dlg.add(c, gbc);
546                                dlg.add(jBtGo);
547                                gbc.gridwidth = GridBagConstraints.REMAINDER;
548                                dlg.add(jBtCancel);
549                        }
550                        dlg.pack();
551                        dlg.setLocation(100, 100);
552                        dlg.setVisible(true);
553                        dlg.setSize(dlg.getPreferredSize());
554                        dlg.setVisible(false);
555                        dlg.setVisible(true);
556                        dlg.repaint();
557                } // actionPerformed
558        } // class ActionGenerate
559
560        class ActionGenerateData extends MyAction {
561                /** for serialization */
562                private static final long serialVersionUID = -2038911085935516L;
563
564                public ActionGenerateData() {
565                        super("Generate Data", "Generate Random Instances from Network", "generate.data", "ctrl D");
566                } // c'tor
567
568                int m_nNrOfInstances = 100;
569
570                int m_nSeed = 1234;
571
572                String m_sFile = "";
573
574                JDialog dlg = null;
575
576                public void actionPerformed(ActionEvent ae) {
577                        if (dlg == null) {
578                                dlg = new JDialog();
579                                dlg.setTitle("Generate Random Data Options");
580
581                                final JLabel jLbNrOfInstances = new JLabel("Nr of instances");
582                                final JTextField jTfNrOfInstances = new JTextField(3);
583                                jTfNrOfInstances.setHorizontalAlignment(JTextField.CENTER);
584                                jTfNrOfInstances.setText("" + m_nNrOfInstances);
585                                final JLabel jLbSeed = new JLabel("Random seed");
586                                final JTextField jTfSeed = new JTextField(3);
587                                jTfSeed.setHorizontalAlignment(JTextField.CENTER);
588                                jTfSeed.setText("" + m_nSeed);
589                                final JLabel jLbFile = new JLabel("Output file (optional)");
590                                final JTextField jTfFile = new JTextField(12);
591                                jTfFile.setHorizontalAlignment(JTextField.CENTER);
592                                jTfFile.setText(m_sFile);
593
594                                JButton jBtGo;
595                                jBtGo = new JButton("Generate Data");
596
597                                jBtGo.addActionListener(new ActionListener() {
598                                        public void actionPerformed(ActionEvent ae) {
599                                                try {
600                                                        String tmpfilename = "tmp.bif.file.xml";
601                                                        BayesNetGenerator generator = new BayesNetGenerator();
602                                                        String[] options = new String[4];
603                                                        options[0] = "-M";
604                                                        options[1] = "" + jTfNrOfInstances.getText();
605                                                        options[2] = "-F";
606                                                        options[3] = tmpfilename;
607                                                        FileWriter outfile = new FileWriter(tmpfilename);
608                                                        StringBuffer text = new StringBuffer();
609                                                        if (m_marginCalculator == null) {
610                                                                m_marginCalculator = new MarginCalculator();
611                                                                m_marginCalculator.calcMargins(m_BayesNet);
612                                                        }
613                                                        text.append(m_marginCalculator.toXMLBIF03());
614                                                        outfile.write(text.toString());
615                                                        outfile.close();
616
617                                                        generator.setOptions(options);
618                                                        generator.generateRandomNetwork();
619                                                        generator.generateInstances();
620                                                        m_Instances = generator.m_Instances;
621                                                        a_learn.setEnabled(true);
622                                                        a_learnCPT.setEnabled(true);
623
624                                                        m_sFile = jTfFile.getText();
625                                                        if (m_sFile != null && !m_sFile.equals("")) {
626                                                                AbstractFileSaver saver = ConverterUtils.getSaverForFile(m_sFile);
627                                                                // no idea what the format is, so let's save it as ARFF file
628                                                                if (saver == null)
629                                                                        saver = new ArffSaver();
630                                                                saver.setFile(new File(m_sFile));
631                                                                saver.setInstances(m_Instances);
632                                                                saver.writeBatch();
633                                                        }
634
635                                                } catch (Exception e) {
636                                                        e.printStackTrace();
637                                                }
638                                                dlg.setVisible(false);
639                                        }
640                                });
641
642                                JButton jBtFile = new JButton("Browse");
643                                jBtFile.addActionListener(new ActionListener() {
644                                        public void actionPerformed(ActionEvent ae) {
645                                                ConverterFileChooser fc = new ConverterFileChooser(System.getProperty("user.dir"));
646                                                fc.setDialogTitle("Save Instances As");
647                                                int rval = fc.showSaveDialog(GUI.this);
648
649                                                if (rval == JFileChooser.APPROVE_OPTION) {
650                                                        String filename = fc.getSelectedFile().toString();
651                                                        jTfFile.setText(filename);
652                                                }
653                                                dlg.setVisible(true);
654                                        }
655                                });
656                                JButton jBtCancel;
657                                jBtCancel = new JButton("Cancel");
658                                jBtCancel.setMnemonic('C');
659                                jBtCancel.addActionListener(new ActionListener() {
660                                        public void actionPerformed(ActionEvent ae) {
661                                                dlg.setVisible(false);
662                                        }
663                                });
664                                GridBagConstraints gbc = new GridBagConstraints();
665                                dlg.setLayout(new GridBagLayout());
666
667                                Container c = new Container();
668                                c.setLayout(new GridBagLayout());
669                                gbc.gridwidth = 2;
670                                gbc.insets = new Insets(8, 0, 0, 0);
671                                gbc.anchor = GridBagConstraints.NORTHWEST;
672                                gbc.gridwidth = GridBagConstraints.RELATIVE;
673                                gbc.fill = GridBagConstraints.HORIZONTAL;
674                                c.add(jLbNrOfInstances, gbc);
675                                gbc.gridwidth = GridBagConstraints.REMAINDER;
676                                c.add(jTfNrOfInstances, gbc);
677                                gbc.gridwidth = GridBagConstraints.RELATIVE;
678                                c.add(jLbSeed, gbc);
679                                gbc.gridwidth = GridBagConstraints.REMAINDER;
680                                c.add(jTfSeed, gbc);
681                                gbc.gridwidth = GridBagConstraints.RELATIVE;
682                                c.add(jLbFile, gbc);
683                                gbc.gridwidth = GridBagConstraints.REMAINDER;
684                                c.add(jTfFile, gbc);
685                                gbc.gridwidth = GridBagConstraints.REMAINDER;
686                                c.add(jBtFile, gbc);
687
688                                gbc.fill = GridBagConstraints.HORIZONTAL;
689                                dlg.add(c, gbc);
690                                dlg.add(jBtGo);
691                                gbc.gridwidth = GridBagConstraints.REMAINDER;
692                                dlg.add(jBtCancel);
693                        }
694                        dlg.setLocation(100, 100);
695                        dlg.setVisible(true);
696                        dlg.setSize(dlg.getPreferredSize());
697                        dlg.setVisible(false);
698                        dlg.setVisible(true);
699                        dlg.repaint();
700
701                } // actionPerformed
702        } // class ActionGenerateData
703
704        class ActionLearn extends MyAction {
705                /** for serialization */
706                private static final long serialVersionUID = -2038911085935516L;
707
708                public ActionLearn() {
709                        super("Learn Network", "Learn Bayesian Network", "learn", "ctrl L");
710                        setEnabled(false);
711                } // c'tor
712
713                JDialog dlg = null;
714
715                public void actionPerformed(ActionEvent ae) {
716                        if (dlg == null) {
717                                dlg = new JDialog();
718                                dlg.setTitle("Learn Bayesian Network");
719
720                                final JButton jBtOptions = new JButton("Options");
721                                jBtOptions.addActionListener(new ActionListener() {
722                                        public void actionPerformed(ActionEvent ae) {
723                                                //m_BayesNet = new EditableBayesNet();
724                                                try {
725                                                        GenericObjectEditor.registerEditors();
726                                                        GenericObjectEditor ce = new GenericObjectEditor(true);
727                                                        ce.setClassType(weka.classifiers.Classifier.class);
728                                                        ce.setValue(m_BayesNet);
729
730                                                        PropertyDialog pd;
731                                                        if (PropertyDialog.getParentDialog(GUI.this) != null)
732                                                                pd = new PropertyDialog(PropertyDialog.getParentDialog(GUI.this), ce, 100, 100);
733                                                        else
734                                                                pd = new PropertyDialog(PropertyDialog.getParentFrame(GUI.this), ce, 100, 100);
735                                                        pd.addWindowListener(new WindowAdapter() {
736                                                                public void windowClosing(WindowEvent e) {
737                                                                        PropertyEditor pe = ((PropertyDialog) e.getSource()).getEditor();
738                                                                        Object c = (Object) pe.getValue();
739                                                                        String options = "";
740                                                                        if (c instanceof OptionHandler) {
741                                                                                options = Utils.joinOptions(((OptionHandler) c).getOptions());
742                                                                                try {
743                                                                                        m_BayesNet.setOptions(((OptionHandler) c).getOptions());
744                                                                                } catch (Exception e2) {
745                                                                                        e2.printStackTrace();
746                                                                                }
747                                                                        }
748                                                                        System.out.println(c.getClass().getName() + " " + options);
749                                                                        System.exit(0);
750                                                                }
751                                                        });
752                                                        pd.setVisible(true);
753                                                } catch (Exception ex) {
754                                                        ex.printStackTrace();
755                                                        System.err.println(ex.getMessage());
756                                                }
757                                                m_BayesNet.clearUndoStack();
758                                                a_undo.setEnabled(false);
759                                                a_redo.setEnabled(false);
760                                        }
761                                });
762
763                                final JTextField jTfOptions = new JTextField(40);
764                                jTfOptions.setHorizontalAlignment(JTextField.CENTER);
765                                jTfOptions.setText("" + Utils.joinOptions(m_BayesNet.getOptions()));
766
767                                JButton jBtGo;
768                                jBtGo = new JButton("Learn");
769
770                                jBtGo.addActionListener(new ActionListener() {
771                                        public void actionPerformed(ActionEvent ae) {
772                                                try {
773                                                        m_BayesNet.buildClassifier(m_Instances);
774                                                        layoutGraph();
775                                                        updateStatus();
776                                                        m_BayesNet.clearUndoStack();
777
778                                                        dlg.setVisible(false);
779                                                } catch (Exception e) {
780                                                        e.printStackTrace();
781                                                }
782                                                dlg.setVisible(false);
783                                        }
784                                });
785
786                                JButton jBtCancel;
787                                jBtCancel = new JButton("Cancel");
788                                jBtCancel.setMnemonic('C');
789                                jBtCancel.addActionListener(new ActionListener() {
790                                        public void actionPerformed(ActionEvent ae) {
791                                                dlg.setVisible(false);
792                                        }
793                                });
794                                GridBagConstraints gbc = new GridBagConstraints();
795                                dlg.setLayout(new GridBagLayout());
796
797                                Container c = new Container();
798                                c.setLayout(new GridBagLayout());
799                                gbc.gridwidth = 2;
800                                gbc.insets = new Insets(8, 0, 0, 0);
801                                gbc.anchor = GridBagConstraints.NORTHWEST;
802                                gbc.gridwidth = GridBagConstraints.RELATIVE;
803                                gbc.fill = GridBagConstraints.HORIZONTAL;
804                                c.add(jBtOptions, gbc);
805                                gbc.gridwidth = GridBagConstraints.REMAINDER;
806                                c.add(jTfOptions, gbc);
807
808                                gbc.fill = GridBagConstraints.HORIZONTAL;
809                                dlg.add(c, gbc);
810                                dlg.add(jBtGo);
811                                gbc.gridwidth = GridBagConstraints.REMAINDER;
812                                dlg.add(jBtCancel);
813                        }
814                        dlg.setLocation(100, 100);
815                        dlg.setVisible(true);
816                        dlg.setSize(dlg.getPreferredSize());
817                        dlg.setVisible(false);
818                        dlg.setVisible(true);
819                        dlg.repaint();
820                } // actionPerformed
821        } // class ActionLearn
822
823        class ActionLearnCPT extends MyAction {
824                /** for serialization */
825                private static final long serialVersionUID = -2022211085935516L;
826
827                public ActionLearnCPT() {
828                        super("Learn CPT", "Learn conditional probability tables", "learncpt", "");
829                        setEnabled(false);
830                } // c'tor
831
832                public void actionPerformed(ActionEvent ae) {
833                        if (m_Instances == null) {
834                                JOptionPane.showMessageDialog(null, "Select instances to learn from first (menu Tools/Set Data)");
835                                return;
836                        }
837                        try {
838                                m_BayesNet.setData(m_Instances);
839                        } catch (Exception e) {
840                                JOptionPane.showMessageDialog(null, "Data set is not compatible with network.\n"+e.getMessage() + "\nChoose other instances (menu Tools/Set Data)");
841                                return;
842                        }
843                        try {
844                                m_BayesNet.estimateCPTs();
845                                m_BayesNet.clearUndoStack();
846                        } catch (Exception e) {
847                                e.printStackTrace();
848                        }
849                        updateStatus();
850                } // actionPerformed
851        } // class ActionLearnCPT
852
853        class ActionSetData extends MyAction {
854                /** for serialization */
855                private static final long serialVersionUID = -2038911085935519L;
856
857                public ActionSetData() {
858                        super("Set Data", "Set Data File", "setdata", "ctrl A");
859                } // c'tor
860
861                public void actionPerformed(ActionEvent ae) {
862                        ConverterFileChooser fc = new ConverterFileChooser(System.getProperty("user.dir"));
863                        fc.setDialogTitle("Set Data File");
864                        int rval = fc.showOpenDialog(GUI.this);
865
866                        if (rval == JFileChooser.APPROVE_OPTION) {
867                                AbstractFileLoader loader = fc.getLoader();
868                                try {
869                                        if (loader != null)
870                                          m_Instances = loader.getDataSet();
871                                        if (m_Instances.classIndex() == -1)
872                                          m_Instances.setClassIndex(m_Instances.numAttributes() - 1);
873                                        a_learn.setEnabled(true);
874                                        a_learnCPT.setEnabled(true);
875                                        repaint();
876                                } catch (Exception e) {
877                                        e.printStackTrace();
878                                }
879                        }
880                }
881        } // class ActionSetData
882
883        class ActionUndo extends MyAction {
884                /** for serialization */
885                private static final long serialVersionUID = -3038910085935519L;
886
887                public ActionUndo() {
888                        super("Undo", "Undo", "undo", "ctrl Z");
889                        setEnabled(false);
890                } // c'tor
891
892                public boolean isEnabled() {
893                        return m_BayesNet.canUndo();
894                }
895
896                public void actionPerformed(ActionEvent ae) {
897                        String sMsg = m_BayesNet.undo();
898                        m_jStatusBar.setText("Undo action performed: " + sMsg);
899                        //if (!sMsg.equals("")) {
900                        //      JOptionPane.showMessageDialog(null, sMsg, "Undo action successful", JOptionPane.INFORMATION_MESSAGE);
901                        //}
902                        a_redo.setEnabled(m_BayesNet.canRedo());
903                        a_undo.setEnabled(m_BayesNet.canUndo());
904                        m_Selection.clear();
905                        updateStatus();
906                        repaint();
907                }
908        } // ActionUndo
909       
910        class ActionRedo extends MyAction {
911                /** for serialization */
912                private static final long serialVersionUID = -4038910085935519L;
913
914                public ActionRedo() {
915                        super("Redo", "Redo", "redo", "ctrl Y");
916                        setEnabled(false);
917                } // c'tor
918
919                public boolean isEnabled() {
920                        return m_BayesNet.canRedo();
921                }
922
923                public void actionPerformed(ActionEvent ae) {
924                        String sMsg = m_BayesNet.redo();
925                        m_jStatusBar.setText("Redo action performed: " + sMsg);
926                        //if (!sMsg.equals("")) {
927                        //      JOptionPane.showMessageDialog(null, sMsg, "Redo action successful", JOptionPane.INFORMATION_MESSAGE);
928                        //}
929                        m_Selection.clear();
930                        updateStatus();
931                        repaint();
932                }
933        } // ActionRedo
934
935        class ActionAddNode extends MyAction {
936                /** for serialization */
937                private static final long serialVersionUID = -2038910085935519L;
938
939                public ActionAddNode() {
940                        super("Add Node", "Add Node", "addnode", "");
941                } // c'tor
942
943                JDialog dlg = null;
944
945                JTextField jTfName = new JTextField(20);
946
947                JTextField jTfCard = new JTextField(3);
948
949                int m_X = Integer.MAX_VALUE;
950                int m_Y;
951                public void addNode(int nX, int nY) {
952                        m_X = nX;
953                        m_Y = nY;
954                        addNode();
955                } // addNode
956               
957                void addNode() {
958                        if (dlg == null) {
959                                dlg = new JDialog();
960                                dlg.setTitle("Add node");
961                                JLabel jLbName = new JLabel("Name");
962                                jTfName.setHorizontalAlignment(JTextField.CENTER);
963                                JLabel jLbCard = new JLabel("Cardinality");
964                                jTfCard.setHorizontalAlignment(JTextField.CENTER);
965                                jTfCard.setText("2");
966
967                                JButton jBtCancel;
968                                jBtCancel = new JButton("Cancel");
969                                jBtCancel.setMnemonic('C');
970                                jBtCancel.addActionListener(new ActionListener() {
971                                        public void actionPerformed(ActionEvent ae) {
972                                                dlg.setVisible(false);
973                                        }
974                                });
975                                JButton jBtOk = new JButton("Ok");
976                                jBtOk.setMnemonic('O');
977                                jBtOk.addActionListener(new ActionListener() {
978                                        public void actionPerformed(ActionEvent ae) {
979                                                String sName = jTfName.getText();
980                                                if (sName.length() <= 0) {
981                                                        JOptionPane.showMessageDialog(null, "Name should have at least one character");
982                                                        return;
983                                                }
984                                                int nCard = new Integer(jTfCard.getText()).intValue();
985                                                if (nCard <= 1) {
986                                                        JOptionPane.showMessageDialog(null, "Cardinality should be larger than 1");
987                                                        return;
988                                                }
989                                                try {
990                                                        if (m_X < Integer.MAX_VALUE) {
991                                                                m_BayesNet.addNode(sName, nCard, m_X, m_Y);
992                                                        } else {
993                                                                m_BayesNet.addNode(sName, nCard);
994                                                        }
995                                                    m_jStatusBar.setText(m_BayesNet.lastActionMsg());
996                                                        a_undo.setEnabled(true);
997                                                        a_redo.setEnabled(false);
998                                                        //GraphNode n = new GraphNode("id" + m_nodes.size(), sName);
999                                                        //n.probs = m_BayesNet.getDistribution(sName);
1000                                                        //n.outcomes = m_BayesNet.getValues(sName);
1001                                                        //n.x = 100 + m_nodes.size() * 10;
1002                                                        //n.y = 100 + m_nodes.size() * 10;
1003                                                        //m_nodes.addElement(n);
1004                                                } catch (Exception e) {
1005                                                        e.printStackTrace();
1006                                                }
1007                                                repaint();
1008                                                dlg.setVisible(false);
1009                                        }
1010                                });
1011                                dlg.setLayout(new GridLayout(3, 2, 10, 10));
1012                                dlg.add(jLbName);
1013                                dlg.add(jTfName);
1014                                dlg.add(jLbCard);
1015                                dlg.add(jTfCard);
1016                                dlg.add(jBtOk);
1017                                dlg.add(jBtCancel);
1018                                dlg.setSize(dlg.getPreferredSize());
1019                        }
1020                        jTfName.setText("Node" + (m_BayesNet.getNrOfNodes() + 1));
1021                        dlg.setVisible(true);
1022                } // addNode
1023               
1024                public void actionPerformed(ActionEvent ae) {
1025                        m_X = Integer.MAX_VALUE;
1026                        addNode();
1027                }
1028        } // class ActionAddNode
1029
1030        class ActionDeleteNode extends MyAction {
1031                /** for serialization */
1032                private static final long serialVersionUID = -2038912085935519L;
1033
1034                public ActionDeleteNode() {
1035                        super("Delete Node", "Delete Node", "delnode", "DELETE");
1036                } // c'tor
1037
1038                public void actionPerformed(ActionEvent ae) {
1039                        if (m_Selection.getSelected().size() > 0) {
1040                                m_BayesNet.deleteSelection(m_Selection.getSelected());
1041                            m_jStatusBar.setText(m_BayesNet.lastActionMsg());
1042                                m_Selection.clear();
1043                                updateStatus();
1044                                repaint();
1045                        } else {
1046                                String[] options = new String[m_BayesNet.getNrOfNodes()];
1047                                for (int i = 0; i < options.length; i++) {
1048                                        options[i] = m_BayesNet.getNodeName(i);
1049                                }
1050                                String sResult = (String) JOptionPane.showInputDialog(null, "Select node to delete", "Nodes", 0, null,
1051                                                options, options[0]);
1052                                if (sResult != null && !sResult.equals("")) {
1053                                        int iNode = m_BayesNet.getNode2(sResult);
1054                                        deleteNode(iNode);
1055                                }
1056                        }
1057                }
1058        } // class ActionDeleteNode
1059
1060        class ActionCopyNode extends MyAction {
1061                /** for serialization */
1062                private static final long serialVersionUID = -2038732085935519L;
1063
1064                public ActionCopyNode() {
1065                        super("Copy", "Copy Nodes", "copy", "ctrl C");
1066                } // c'tor
1067               
1068                public ActionCopyNode(String sName, String sToolTipText, String sIcon, String sAcceleratorKey) {
1069                        super(sName, sToolTipText, sIcon, sAcceleratorKey);
1070                } // c'rot
1071               
1072                public void actionPerformed(ActionEvent ae) {
1073                        copy();
1074                }
1075               
1076                public void copy() {
1077                        String sXML = m_BayesNet.toXMLBIF03(m_Selection.getSelected());
1078                        m_clipboard.setText(sXML);
1079                } // copy
1080        } // class ActionCopyNode
1081
1082        class ActionCutNode extends ActionCopyNode {
1083                /** for serialization */
1084                private static final long serialVersionUID = -2038822085935519L;
1085
1086                public ActionCutNode() {
1087                        super("Cut", "Cut Nodes", "cut", "ctrl X");
1088                } // c'tor
1089
1090                public void actionPerformed(ActionEvent ae) {
1091                        copy();
1092                        m_BayesNet.deleteSelection(m_Selection.getSelected());
1093                    m_jStatusBar.setText(m_BayesNet.lastActionMsg());
1094                        m_Selection.clear();
1095                        a_undo.setEnabled(true);
1096                        a_redo.setEnabled(false);
1097                        repaint();
1098                }
1099        } // class ActionCutNode
1100
1101        class ActionPasteNode extends MyAction {
1102                /** for serialization */
1103                private static final long serialVersionUID = -2038732085935519L;
1104
1105                public ActionPasteNode() {
1106                        super("Paste", "Paste Nodes", "paste", "ctrl V");
1107                } // c'tor
1108
1109                public void actionPerformed(ActionEvent ae) {
1110                        try {
1111                                m_BayesNet.paste(m_clipboard.getText());
1112                                updateStatus();
1113                            m_jStatusBar.setText(m_BayesNet.lastActionMsg());
1114                        } catch (Exception e) {
1115                                e.printStackTrace();
1116                        }
1117                }
1118                public boolean isEnabled() {
1119                        return m_clipboard.hasText();
1120                }
1121        } // class ActionPasteNode
1122
1123        class ActionSelectAll extends MyAction {
1124                /** for serialization */
1125                private static final long serialVersionUID = -2038642085935519L;
1126
1127                public ActionSelectAll() {
1128                        super("Select All", "Select All Nodes", "selectall", "ctrl A");
1129                } // c'tor
1130
1131                public void actionPerformed(ActionEvent ae) {
1132                        m_Selection.selectAll();
1133                        repaint();
1134                }
1135        } // class ActionSelectAll
1136
1137        class ActionExport extends MyAction {
1138                boolean m_bIsExporting = false;         
1139                /** for serialization */
1140                private static final long serialVersionUID = -3027642085935519L;
1141
1142                public ActionExport() {
1143                        super("Export", "Export to graphics file", "export", "");
1144                } // c'tor
1145
1146                public void actionPerformed(ActionEvent ae) {
1147                        m_bIsExporting = true;
1148                        m_GraphPanel.saveComponent();
1149                        m_bIsExporting = false;
1150                        repaint();
1151                }
1152                public boolean isExporting() {return m_bIsExporting;}
1153        } // class ActionExport
1154
1155        class ActionAlignLeft extends MyAction {
1156                /** for serialization */
1157                private static final long serialVersionUID = -3138642085935519L;
1158
1159                public ActionAlignLeft() {
1160                        super("Align Left", "Align Left", "alignleft", "");
1161                } // c'tor
1162
1163                public void actionPerformed(ActionEvent ae) {
1164                        m_BayesNet.alignLeft(m_Selection.getSelected());
1165                    m_jStatusBar.setText(m_BayesNet.lastActionMsg());
1166                        a_undo.setEnabled(true);
1167                        a_redo.setEnabled(false);
1168                        repaint();
1169                }
1170        } // class ActionAlignLeft
1171       
1172        class ActionAlignRight extends MyAction {
1173                /** for serialization */
1174                private static final long serialVersionUID = -4238642085935519L;
1175
1176                public ActionAlignRight() {
1177                        super("Align Right", "Align Right", "alignright", "");
1178                } // c'tor
1179
1180                public void actionPerformed(ActionEvent ae) {
1181                        m_BayesNet.alignRight(m_Selection.getSelected());
1182                    m_jStatusBar.setText(m_BayesNet.lastActionMsg());
1183                        a_undo.setEnabled(true);
1184                        a_redo.setEnabled(false);
1185                        repaint();
1186                }
1187        } // class ActionAlignRight
1188
1189        class ActionAlignTop extends MyAction {
1190                /** for serialization */
1191                private static final long serialVersionUID = -5338642085935519L;
1192
1193                public ActionAlignTop() {
1194                        super("Align Top", "Align Top", "aligntop", "");
1195                } // c'tor
1196
1197                public void actionPerformed(ActionEvent ae) {
1198                        m_BayesNet.alignTop(m_Selection.getSelected());
1199                    m_jStatusBar.setText(m_BayesNet.lastActionMsg());
1200                        a_undo.setEnabled(true);
1201                        a_redo.setEnabled(false);
1202                        repaint();
1203                }
1204        } // class ActionAlignTop
1205
1206        class ActionAlignBottom extends MyAction {
1207                /** for serialization */
1208                private static final long serialVersionUID = -6438642085935519L;
1209
1210                public ActionAlignBottom() {
1211                        super("Align Bottom", "Align Bottom", "alignbottom", "");
1212                } // c'tor
1213
1214                public void actionPerformed(ActionEvent ae) {
1215                        m_BayesNet.alignBottom(m_Selection.getSelected());
1216                    m_jStatusBar.setText(m_BayesNet.lastActionMsg());
1217                        a_undo.setEnabled(true);
1218                        a_redo.setEnabled(false);
1219                        repaint();
1220                }
1221        } // class ActionAlignBottom
1222
1223        class ActionCenterHorizontal extends MyAction {
1224                /** for serialization */
1225                private static final long serialVersionUID = -7538642085935519L;
1226
1227                public ActionCenterHorizontal() {
1228                        super("Center Horizontal", "Center Horizontal", "centerhorizontal", "");
1229                } // c'tor
1230
1231                public void actionPerformed(ActionEvent ae) {
1232                        m_BayesNet.centerHorizontal(m_Selection.getSelected());
1233                    m_jStatusBar.setText(m_BayesNet.lastActionMsg());
1234                        a_undo.setEnabled(true);
1235                        a_redo.setEnabled(false);
1236                        repaint();
1237                }
1238        } // class ActionCenterHorizontal
1239
1240        class ActionCenterVertical extends MyAction {
1241                /** for serialization */
1242                private static final long serialVersionUID = -8638642085935519L;
1243
1244                public ActionCenterVertical() {
1245                        super("Center Vertical", "Center Vertical", "centervertical", "");
1246                } // c'tor
1247
1248                public void actionPerformed(ActionEvent ae) {
1249                        m_BayesNet.centerVertical(m_Selection.getSelected());
1250                    m_jStatusBar.setText(m_BayesNet.lastActionMsg());
1251                        a_undo.setEnabled(true);
1252                        a_redo.setEnabled(false);
1253                        repaint();
1254                }
1255        } // class ActionCenterVertical
1256
1257        class ActionSpaceHorizontal extends MyAction {
1258                /** for serialization */
1259                private static final long serialVersionUID = -9738642085935519L;
1260
1261                public ActionSpaceHorizontal() {
1262                        super("Space Horizontal", "Space Horizontal", "spacehorizontal", "");
1263                } // c'tor
1264
1265                public void actionPerformed(ActionEvent ae) {
1266                        m_BayesNet.spaceHorizontal(m_Selection.getSelected());
1267                    m_jStatusBar.setText(m_BayesNet.lastActionMsg());
1268                        a_undo.setEnabled(true);
1269                        a_redo.setEnabled(false);
1270                        repaint();
1271                }
1272        } // class ActionSpaceHorizontal
1273
1274        class ActionSpaceVertical extends MyAction {
1275                /** for serialization */
1276                private static final long serialVersionUID = -838642085935519L;
1277
1278                public ActionSpaceVertical() {
1279                        super("Space Vertical", "Space Vertical", "spacevertical", "");
1280                } // c'tor
1281
1282                public void actionPerformed(ActionEvent ae) {
1283                        m_BayesNet.spaceVertical(m_Selection.getSelected());
1284                    m_jStatusBar.setText(m_BayesNet.lastActionMsg());
1285                        a_undo.setEnabled(true);
1286                        a_redo.setEnabled(false);
1287                        repaint();
1288                }
1289        } // class ActionSpaceVertical
1290
1291        class ActionAddArc extends MyAction {
1292                /** for serialization */
1293                private static final long serialVersionUID = -2038913085935519L;
1294
1295                public ActionAddArc() {
1296                        super("Add Arc", "Add Arc", "addarc", "");
1297                } // c'tor
1298
1299                public void actionPerformed(ActionEvent ae) {
1300                        try {
1301                                String[] options = new String[m_BayesNet.getNrOfNodes()];
1302                                for (int i = 0; i < options.length; i++) {
1303                                        options[i] = m_BayesNet.getNodeName(i);
1304                                }
1305                                String sChild = (String) JOptionPane.showInputDialog(null, "Select child node", "Nodes", 0, null,
1306                                                options, options[0]);
1307                                if (sChild == null || sChild.equals("")) {
1308                                        return;
1309                                }
1310                                int iChild = m_BayesNet.getNode(sChild);
1311                                addArcInto(iChild);
1312                        } catch (Exception e) {
1313                                e.printStackTrace();
1314                        }
1315                }
1316        } // class ActionAddArc
1317
1318        class ActionDeleteArc extends MyAction {
1319                /** for serialization */
1320                private static final long serialVersionUID = -2038914085935519L;
1321
1322                public ActionDeleteArc() {
1323                        super("Delete Arc", "Delete Arc", "delarc", "");
1324                } // c'tor
1325
1326                public void actionPerformed(ActionEvent ae) {
1327                        int nEdges = 0;
1328                        for (int iNode = 0; iNode < m_BayesNet.getNrOfNodes(); iNode++) {
1329                                nEdges += m_BayesNet.getNrOfParents(iNode);
1330                        }
1331                        String[] options = new String[nEdges];
1332                        int i = 0;
1333                        for (int iNode = 0; iNode < m_BayesNet.getNrOfNodes(); iNode++) {
1334                                for (int iParent = 0; iParent < m_BayesNet.getNrOfParents(iNode); iParent++) {
1335                                        int nParent = m_BayesNet.getParent(iNode, iParent);
1336                                        String sEdge = m_BayesNet.getNodeName(nParent);
1337                                        sEdge += " -> ";
1338                                        sEdge += m_BayesNet.getNodeName(iNode);
1339                                        options[i++] = sEdge;
1340                                }
1341                               
1342                        }
1343                        deleteArc(options);
1344                }
1345        } // class ActionDeleteArc
1346
1347        class ActionNew extends MyAction {
1348                /** for serialization */
1349                private static final long serialVersionUID = -2038911085935515L;
1350
1351                public ActionNew() {
1352                        super("New", "New Network", "new", "");
1353                } // c'tor
1354
1355                public void actionPerformed(ActionEvent ae) {
1356                        m_sFileName = "";
1357                        m_BayesNet = new EditableBayesNet(true);
1358                        updateStatus();
1359                        layoutGraph();
1360                        a_datagenerator.setEnabled(false);
1361                        m_BayesNet.clearUndoStack();
1362                    m_jStatusBar.setText("New Network");
1363                        m_Selection = new Selection();
1364                        repaint();
1365                }
1366        } // class ActionNew
1367
1368        class ActionLoad extends MyAction {
1369                /** for serialization */
1370                private static final long serialVersionUID = -2038911085935515L;
1371
1372                public ActionLoad() {
1373                        super("Load", "Load Graph", "open", "ctrl O");
1374                } // c'tor
1375
1376                public void actionPerformed(ActionEvent ae) {
1377                        JFileChooser fc = new JFileChooser(System.getProperty("user.dir"));
1378                        ExtensionFileFilter ef1 = new ExtensionFileFilter(".arff", "ARFF files");
1379                        ExtensionFileFilter ef2 = new ExtensionFileFilter(".xml", "XML BIF files");
1380                        fc.addChoosableFileFilter(ef1);
1381                        fc.addChoosableFileFilter(ef2);
1382                        fc.setDialogTitle("Load Graph");
1383                        int rval = fc.showOpenDialog(GUI.this);
1384
1385                        if (rval == JFileChooser.APPROVE_OPTION) {
1386                                String sFileName = fc.getSelectedFile().toString();
1387                                if (sFileName.endsWith(ef1.getExtensions()[0])) {
1388                                        initFromArffFile(sFileName);
1389                                } else {
1390                                        try {
1391                                                readBIFFromFile(sFileName);
1392                                        } catch (Exception e) {
1393                                                e.printStackTrace();
1394                                        }
1395                                }
1396                            m_jStatusBar.setText("Loaded " + sFileName);
1397                            updateStatus();
1398                        }
1399                }
1400        } // class ActionLoad
1401       
1402       
1403        class ActionViewStatusbar extends MyAction {
1404                /** for serialization */
1405                private static final long serialVersionUID = -20389330812354L;
1406
1407                public ActionViewStatusbar() {
1408                        super("View statusbar", "View statusbar", "statusbar", "");
1409                } // c'tor
1410
1411                public void actionPerformed(ActionEvent ae) {
1412                        m_jStatusBar.setVisible(!m_jStatusBar.isVisible());
1413                } // actionPerformed
1414        } // class ActionViewStatusbar
1415
1416        class ActionViewToolbar extends MyAction {
1417                /** for serialization */
1418                private static final long serialVersionUID = -20389110812354L;
1419
1420                public ActionViewToolbar() {
1421                        super("View toolbar", "View toolbar", "toolbar", "");
1422                } // c'tor
1423
1424                public void actionPerformed(ActionEvent ae) {
1425                        m_jTbTools.setVisible(!m_jTbTools.isVisible());
1426                } // actionPerformed
1427        } // class ActionViewToolbar
1428
1429        class ActionSave extends MyAction {
1430                /** for serialization */
1431                private static final long serialVersionUID = -20389110859355156L;
1432
1433                public ActionSave() {
1434                        super("Save", "Save Graph", "save", "ctrl S");
1435                } // c'tor
1436
1437                public ActionSave(String sName, String sToolTipText, String sIcon, String sAcceleratorKey) {
1438                        super(sName, sToolTipText, sIcon, sAcceleratorKey);
1439                } // c'tor
1440
1441                public void actionPerformed(ActionEvent ae) {
1442                        if (!m_sFileName.equals("")) {
1443                                saveFile(m_sFileName);
1444                                m_BayesNet.isSaved();
1445                            m_jStatusBar.setText("Saved as " + m_sFileName);
1446                        } else {
1447                                if (saveAs()) {
1448                                        m_BayesNet.isSaved();
1449                                    m_jStatusBar.setText("Saved as " + m_sFileName);                                   
1450                                }
1451                        }
1452                } // actionPerformed
1453
1454
1455                ExtensionFileFilter ef1 = new ExtensionFileFilter(".xml", "XML BIF files");
1456
1457                boolean saveAs() {
1458                        JFileChooser fc = new JFileChooser(System.getProperty("user.dir"));
1459                        fc.addChoosableFileFilter(ef1);
1460                        fc.setDialogTitle("Save Graph As");
1461                        if (!m_sFileName.equals("")) {
1462                                // can happen on actionQuit
1463                                fc.setSelectedFile(new File(m_sFileName));
1464                        }
1465                        int rval = fc.showSaveDialog(GUI.this);
1466
1467                        if (rval == JFileChooser.APPROVE_OPTION) {
1468                                // System.out.println("Saving to file \""+
1469                                // f.getAbsoluteFile().toString()+"\"");
1470                                String sFileName = fc.getSelectedFile().toString();
1471                                if (!sFileName.endsWith(".xml"))
1472                                        sFileName = sFileName.concat(".xml");
1473                                saveFile(sFileName);
1474                                return true;
1475                        }
1476                        return false;
1477                } // saveAs
1478
1479                protected void saveFile(String sFileName) {
1480                    try {
1481                        FileWriter outfile = new FileWriter(sFileName);
1482                        outfile.write(m_BayesNet.toXMLBIF03());
1483                        outfile.close();
1484                                m_sFileName = sFileName;
1485                            m_jStatusBar.setText("Saved as " + m_sFileName);
1486                      }
1487                      catch(IOException e) { 
1488                          e.printStackTrace(); 
1489                      }
1490                  } // saveFile
1491        } // class ActionSave
1492       
1493        class ActionSaveAs extends ActionSave {
1494                /** for serialization */
1495                private static final long serialVersionUID = -20389110859354L;
1496
1497                public ActionSaveAs() {
1498                        super("Save As", "Save Graph As", "saveas", "");
1499                } // c'tor
1500
1501                public void actionPerformed(ActionEvent ae) {
1502                        saveAs();
1503                } // actionPerformed
1504        } // class ActionSaveAs
1505
1506        class ActionPrint extends ActionSave {
1507                /** for serialization */
1508                private static final long serialVersionUID = -20389001859354L;
1509                boolean m_bIsPrinting = false;
1510                public ActionPrint() {
1511                        super("Print", "Print Graph", "print", "ctrl P");
1512                } // c'tor
1513
1514                public void actionPerformed(ActionEvent ae) {
1515                    PrinterJob printJob = PrinterJob.getPrinterJob();
1516                    printJob.setPrintable(m_GraphPanel);
1517                    if (printJob.printDialog())
1518                      try { 
1519                                m_bIsPrinting = true;
1520                        printJob.print();
1521                                m_bIsPrinting = false;
1522                      } catch(PrinterException pe) {
1523                        m_jStatusBar.setText("Error printing: " + pe);
1524                                m_bIsPrinting = false;
1525                      }
1526                            m_jStatusBar.setText("Print");
1527                } // actionPerformed
1528                public boolean isPrinting() {return m_bIsPrinting;}
1529
1530        } // class ActionPrint
1531
1532        class ActionQuit extends ActionSave {
1533                /** for serialization */
1534                private static final long serialVersionUID = -2038911085935515L;
1535
1536                public ActionQuit() {
1537                        super("Exit", "Exit Program", "exit", "");
1538                } // c'tor
1539
1540                public void actionPerformed(ActionEvent ae) {
1541                        if (m_BayesNet.isChanged()) {
1542                                int result = JOptionPane.showConfirmDialog(null, "Network changed. Do you want to save it?", "Save before closing?", JOptionPane.YES_NO_CANCEL_OPTION);
1543                                if (result == JOptionPane.CANCEL_OPTION) {
1544                                        return;
1545                                }
1546                                if (result == JOptionPane.YES_OPTION) {
1547                                        if (!saveAs()) {
1548                                                return;
1549                                        }
1550                                }
1551                        }
1552                        System.exit(0);
1553                }
1554        } // class ActionQuit
1555
1556        class ActionHelp extends MyAction {
1557                /** for serialization */
1558                private static final long serialVersionUID = -20389110859354L;
1559
1560                public ActionHelp() {
1561                        super("Help", "Bayesian Network Workbench Help", "help", "");
1562                } // c'tor
1563
1564                public void actionPerformed(ActionEvent ae) {
1565                        JOptionPane.showMessageDialog(null, "See Weka Homepage\nhttp://www.cs.waikato.ac.nz/ml", "Help Message",
1566                                        JOptionPane.PLAIN_MESSAGE);
1567                }
1568        } // class ActionHelp
1569
1570        class ActionAbout extends MyAction {
1571                /** for serialization */
1572                private static final long serialVersionUID = -20389110859353L;
1573
1574                public ActionAbout() {
1575                        super("About", "Help about", "about", "");
1576                } // c'tor
1577
1578                public void actionPerformed(ActionEvent ae) {
1579                        JOptionPane.showMessageDialog(null, "Bayesian Network Workbench\nPart of Weka\n2007", "About Message",
1580                                        JOptionPane.PLAIN_MESSAGE);
1581                }
1582        } // class ActionAbout
1583
1584        class ActionZoomIn extends MyAction {
1585                /** for serialization */
1586                private static final long serialVersionUID = -2038911085935515L;
1587
1588                public ActionZoomIn() {
1589                        super("Zoom in", "Zoom in", "zoomin", "+");
1590                } // c'tor
1591
1592                public void actionPerformed(ActionEvent ae) {
1593                        int i = 0, s = (int) (m_fScale * 100);
1594                        if (s < 300)
1595                                i = s / 25;
1596                        else if (s < 700)
1597                                i = 6 + s / 50;
1598                        else
1599                                i = 13 + s / 100;
1600
1601                        if (s >= 999) {
1602                                setEnabled(false);
1603                                return;
1604                        } else if (s >= 10) {
1605                                if (i >= 22) {
1606                                        setEnabled(false);
1607                                }
1608                                if (s == 10 && !a_zoomout.isEnabled()) {
1609                                        a_zoomout.setEnabled(true);
1610                                }
1611                                m_jTfZoom.setText(m_nZoomPercents[i + 1] + "%");
1612                                m_fScale = m_nZoomPercents[i + 1] / 100D;
1613                        } else {
1614                                if (!a_zoomout.isEnabled())
1615                                        a_zoomout.setEnabled(true);
1616                                m_jTfZoom.setText(m_nZoomPercents[0] + "%");
1617                                m_fScale = m_nZoomPercents[0] / 100D;
1618                        }
1619                        setAppropriateSize();
1620                        m_GraphPanel.repaint();
1621                        m_GraphPanel.invalidate();
1622                        m_jScrollPane.revalidate();
1623                    m_jStatusBar.setText("Zooming in");
1624                }
1625        } // class ActionZoomIn
1626
1627        class ActionZoomOut extends MyAction {
1628                /** for serialization */
1629                private static final long serialVersionUID = -203891108593551L;
1630
1631                public ActionZoomOut() {
1632                        super("Zoom out", "Zoom out", "zoomout", "-");
1633                } // c'tor
1634
1635                public void actionPerformed(ActionEvent ae) {
1636                        int i = 0, s = (int) (m_fScale * 100);
1637                        if (s < 300)
1638                                i = (int) Math.ceil(s / 25D);
1639                        else if (s < 700)
1640                                i = 6 + (int) Math.ceil(s / 50D);
1641                        else
1642                                i = 13 + (int) Math.ceil(s / 100D);
1643
1644                        if (s <= 10) {
1645                                setEnabled(false);
1646                        } else if (s < 999) {
1647                                if (i <= 1) {
1648                                        setEnabled(false);
1649                                }
1650                                m_jTfZoom.setText(m_nZoomPercents[i - 1] + "%");
1651                                m_fScale = m_nZoomPercents[i - 1] / 100D;
1652                        } else {
1653                                if (!a_zoomin.isEnabled())
1654                                        a_zoomin.setEnabled(true);
1655                                m_jTfZoom.setText(m_nZoomPercents[22] + "%");
1656                                m_fScale = m_nZoomPercents[22] / 100D;
1657                        }
1658                        setAppropriateSize();
1659                        m_GraphPanel.repaint();
1660                        m_GraphPanel.invalidate();
1661                        m_jScrollPane.revalidate();
1662                    m_jStatusBar.setText("Zooming out");
1663                }
1664        } // class ActionZoomOut
1665
1666        class ActionLayout extends MyAction {
1667                /** for serialization */
1668                private static final long serialVersionUID = -203891108593551L;
1669
1670                public ActionLayout() {
1671                        super("Layout", "Layout Graph", "layout", "ctrl L");
1672                } // c'tor
1673
1674                JDialog dlg = null;
1675
1676                public void actionPerformed(ActionEvent ae) {
1677                        if (dlg == null) {
1678                                dlg = new JDialog();
1679                                dlg.setTitle("Graph Layout Options");
1680                                final JCheckBox jCbCustomNodeSize = new JCheckBox("Custom Node Size");
1681                                final JLabel jLbNodeWidth = new JLabel("Width");
1682                                final JLabel jLbNodeHeight = new JLabel("Height");
1683
1684                                m_jTfNodeWidth.setHorizontalAlignment(JTextField.CENTER);
1685                                m_jTfNodeWidth.setText("" + m_nNodeWidth);
1686                                m_jTfNodeHeight.setHorizontalAlignment(JTextField.CENTER);
1687                                m_jTfNodeHeight.setText("" + m_nNodeHeight);
1688                                jLbNodeWidth.setEnabled(false);
1689                                m_jTfNodeWidth.setEnabled(false);
1690                                jLbNodeHeight.setEnabled(false);
1691                                m_jTfNodeHeight.setEnabled(false);
1692
1693                                jCbCustomNodeSize.addActionListener(new ActionListener() {
1694                                        public void actionPerformed(ActionEvent ae) {
1695                                                if (((JCheckBox) ae.getSource()).isSelected()) {
1696                                                        jLbNodeWidth.setEnabled(true);
1697                                                        m_jTfNodeWidth.setEnabled(true);
1698                                                        jLbNodeHeight.setEnabled(true);
1699                                                        m_jTfNodeHeight.setEnabled(true);
1700                                                } else {
1701                                                        jLbNodeWidth.setEnabled(false);
1702                                                        m_jTfNodeWidth.setEnabled(false);
1703                                                        jLbNodeHeight.setEnabled(false);
1704                                                        m_jTfNodeHeight.setEnabled(false);
1705                                                        setAppropriateSize();
1706                                                        setAppropriateNodeSize();
1707                                                }
1708                                        }
1709                                });
1710                                JButton jBtLayout;
1711                                jBtLayout = new JButton("Layout Graph");
1712                                jBtLayout.setMnemonic('L');
1713
1714                                jBtLayout.addActionListener(new ActionListener() {
1715                                        public void actionPerformed(ActionEvent ae) {
1716                                                int tmpW, tmpH;
1717
1718                                                if (jCbCustomNodeSize.isSelected()) {
1719                                                        try {
1720                                                                tmpW = Integer.parseInt(m_jTfNodeWidth.getText());
1721                                                        } catch (NumberFormatException ne) {
1722                                                                JOptionPane.showMessageDialog(GUI.this.getParent(),
1723                                                                                "Invalid integer entered for node width.", "Error", JOptionPane.ERROR_MESSAGE);
1724                                                                tmpW = m_nNodeWidth;
1725                                                                m_jTfNodeWidth.setText("" + m_nNodeWidth);
1726
1727                                                        }
1728                                                        try {
1729                                                                tmpH = Integer.parseInt(m_jTfNodeHeight.getText());
1730                                                        } catch (NumberFormatException ne) {
1731                                                                JOptionPane.showMessageDialog(GUI.this.getParent(),
1732                                                                                "Invalid integer entered for node height.", "Error", JOptionPane.ERROR_MESSAGE);
1733                                                                tmpH = m_nNodeHeight;
1734                                                                m_jTfNodeWidth.setText("" + m_nNodeHeight);
1735                                                        }
1736
1737                                                        if (tmpW != m_nNodeWidth || tmpH != m_nNodeHeight) {
1738                                                                m_nNodeWidth = tmpW;
1739                                                                m_nPaddedNodeWidth = m_nNodeWidth + PADDING;
1740                                                                m_nNodeHeight = tmpH;
1741                                                        }
1742                                                }
1743                                                // JButton bt = (JButton) ae.getSource();
1744                                                // bt.setEnabled(false);
1745                                                dlg.setVisible(false);
1746                                                updateStatus();
1747                                                layoutGraph();
1748                                            m_jStatusBar.setText("Laying out Bayes net");
1749                                        }
1750                                });
1751                                JButton jBtCancel;
1752                                jBtCancel = new JButton("Cancel");
1753                                jBtCancel.setMnemonic('C');
1754                                jBtCancel.addActionListener(new ActionListener() {
1755                                        public void actionPerformed(ActionEvent ae) {
1756                                                dlg.setVisible(false);
1757                                        }
1758                                });
1759                                GridBagConstraints gbc = new GridBagConstraints();
1760                                dlg.setLayout(new GridBagLayout());
1761                                //dlg.add(m_le.getControlPanel());
1762
1763                                Container c = new Container();
1764                                c.setLayout(new GridBagLayout());
1765
1766                                gbc.gridwidth = 1;
1767                                gbc.insets = new Insets(8, 0, 0, 0);
1768                                gbc.anchor = GridBagConstraints.NORTHWEST;
1769                                gbc.gridwidth = GridBagConstraints.REMAINDER;
1770                                c.add(jCbCustomNodeSize, gbc);
1771                                gbc.gridwidth = GridBagConstraints.RELATIVE;
1772                                c.add(jLbNodeWidth, gbc);
1773                                gbc.gridwidth = GridBagConstraints.REMAINDER;
1774                                c.add(m_jTfNodeWidth, gbc);
1775                                gbc.gridwidth = GridBagConstraints.RELATIVE;
1776                                c.add(jLbNodeHeight, gbc);
1777                                gbc.gridwidth = GridBagConstraints.REMAINDER;
1778                                c.add(m_jTfNodeHeight, gbc);
1779                                gbc.fill = GridBagConstraints.HORIZONTAL;
1780                                dlg.add(c, gbc);
1781                                dlg.add(jBtLayout);
1782                                gbc.gridwidth = GridBagConstraints.REMAINDER;
1783                                dlg.add(jBtCancel);
1784                        }
1785                        dlg.setLocation(100, 100);
1786                        dlg.setVisible(true);
1787                        dlg.setSize(dlg.getPreferredSize());
1788                        dlg.setVisible(false);
1789                        dlg.setVisible(true);
1790                        dlg.repaint();
1791                }
1792        } // class ActionLayout
1793
1794        /**
1795         * Constructor<br>
1796         * Sets up the gui and initializes all the other previously uninitialized
1797         * variables.
1798         */
1799        public GUI() {
1800                m_GraphPanel = new GraphPanel();
1801                m_jScrollPane = new JScrollPane(m_GraphPanel);
1802
1803                // creating a new layout engine and adding this class as its listener
1804                // to receive layoutComplete events
1805       
1806                m_jTfZoom = new JTextField("100%");
1807                m_jTfZoom.setMinimumSize(m_jTfZoom.getPreferredSize());
1808                m_jTfZoom.setHorizontalAlignment(JTextField.CENTER);
1809                m_jTfZoom.setToolTipText("Zoom");
1810
1811                m_jTfZoom.addActionListener(new ActionListener() {
1812                        public void actionPerformed(ActionEvent ae) {
1813                                JTextField jt = (JTextField) ae.getSource();
1814                                try {
1815                                        int i = -1;
1816                                        i = jt.getText().indexOf('%');
1817                                        if (i == -1)
1818                                                i = Integer.parseInt(jt.getText());
1819                                        else
1820                                                i = Integer.parseInt(jt.getText().substring(0, i));
1821
1822                                        if (i <= 999)
1823                                                m_fScale = i / 100D;
1824
1825                                        jt.setText((int) (m_fScale * 100) + "%");
1826                                        if (m_fScale > 0.1) {
1827                                                if (!a_zoomout.isEnabled())
1828                                                        a_zoomout.setEnabled(true);
1829                                        } else
1830                                                a_zoomout.setEnabled(false);
1831                                        if (m_fScale < 9.99) {
1832                                                if (!a_zoomin.isEnabled())
1833                                                        a_zoomin.setEnabled(true);
1834                                        } else
1835                                                a_zoomin.setEnabled(false);
1836                                        setAppropriateSize();
1837                                        // m_GraphPanel.clearBuffer();
1838                                        m_GraphPanel.repaint();
1839                                        m_GraphPanel.invalidate();
1840                                        m_jScrollPane.revalidate();
1841                                } catch (NumberFormatException ne) {
1842                                        JOptionPane.showMessageDialog(GUI.this.getParent(),
1843                                                        "Invalid integer entered for zoom.", "Error", JOptionPane.ERROR_MESSAGE);
1844                                        jt.setText((m_fScale * 100) + "%");
1845                                }
1846                        }
1847                });
1848
1849                GridBagConstraints gbc = new GridBagConstraints();
1850
1851                final JPanel p = new JPanel(new GridBagLayout());
1852                p.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder("ExtraControls"), BorderFactory
1853                                .createEmptyBorder(4, 4, 4, 4)));
1854                p.setPreferredSize(new Dimension(0, 0));
1855
1856                m_jTbTools = new JToolBar();
1857                m_jTbTools.setFloatable(false);
1858                m_jTbTools.setLayout(new GridBagLayout());
1859                gbc.anchor = GridBagConstraints.NORTHWEST;
1860                gbc.gridwidth = GridBagConstraints.REMAINDER;
1861                gbc.insets = new Insets(0, 0, 0, 0);
1862                m_jTbTools.add(p, gbc);
1863                gbc.gridwidth = 1;
1864
1865
1866                m_jTbTools.add(a_new);
1867                m_jTbTools.add(a_save);
1868                m_jTbTools.add(a_load);
1869                m_jTbTools.addSeparator(new Dimension(2, 2));
1870                m_jTbTools.add(a_cutnode);
1871                m_jTbTools.add(a_copynode);
1872                m_jTbTools.add(a_pastenode);
1873                m_jTbTools.addSeparator(new Dimension(2, 2));
1874                m_jTbTools.add(a_undo);
1875                m_jTbTools.add(a_redo);
1876                m_jTbTools.addSeparator(new Dimension(2, 2));
1877                m_jTbTools.add(a_alignleft);
1878                m_jTbTools.add(a_alignright);
1879                m_jTbTools.add(a_aligntop);
1880                m_jTbTools.add(a_alignbottom);
1881                m_jTbTools.add(a_centerhorizontal);
1882                m_jTbTools.add(a_centervertical);
1883                m_jTbTools.add(a_spacehorizontal);
1884                m_jTbTools.add(a_spacevertical);
1885
1886               
1887                m_jTbTools.addSeparator(new Dimension(2, 2));
1888                m_jTbTools.add(a_zoomin);
1889
1890                gbc.fill = GridBagConstraints.VERTICAL;
1891                gbc.weighty = 1;
1892                JPanel p2 = new JPanel(new BorderLayout());
1893                p2.setPreferredSize(m_jTfZoom.getPreferredSize());
1894                p2.setMinimumSize(m_jTfZoom.getPreferredSize());
1895                p2.add(m_jTfZoom, BorderLayout.CENTER);
1896                m_jTbTools.add(p2, gbc);
1897                gbc.weighty = 0;
1898                gbc.fill = GridBagConstraints.NONE;
1899
1900                m_jTbTools.add(a_zoomout);
1901                m_jTbTools.addSeparator(new Dimension(2, 2));
1902
1903                // jTbTools.add(jBtExtraControls, gbc);
1904                m_jTbTools.add(a_layout);
1905                m_jTbTools.addSeparator(new Dimension(4, 2));
1906                gbc.weightx = 1;
1907                gbc.fill = GridBagConstraints.BOTH;
1908                //jTbTools.add(m_layoutEngine.getProgressBar(), gbc);
1909                m_jStatusBar = new JLabel("Status bar");
1910
1911                this.setLayout(new BorderLayout());
1912                this.add(m_jTbTools, BorderLayout.NORTH);
1913                this.add(m_jScrollPane, BorderLayout.CENTER);
1914                this.add(m_jStatusBar, BorderLayout.SOUTH);
1915
1916                updateStatus();
1917                a_datagenerator.setEnabled(false);
1918               
1919                makeMenuBar();
1920        }
1921       
1922        /**
1923         * Get the menu bar for this application.
1924         *
1925         * @return the menu bar
1926         */
1927        public JMenuBar getMenuBar() {
1928          return m_menuBar;
1929        }
1930       
1931        private void makeMenuBar() {
1932          m_menuBar = new JMenuBar();
1933          JMenu fileMenu = new JMenu("File");
1934          fileMenu.setMnemonic('F');
1935
1936          m_menuBar.add(fileMenu);
1937          fileMenu.add(a_new);
1938          fileMenu.add(a_load);
1939          fileMenu.add(a_save);
1940          fileMenu.add(a_saveas);
1941          fileMenu.addSeparator();
1942          fileMenu.add(a_print);
1943          fileMenu.add(a_export);
1944          fileMenu.addSeparator();
1945          fileMenu.add(a_quit);
1946          JMenu editMenu = new JMenu("Edit");
1947          editMenu.setMnemonic('E');
1948          m_menuBar.add(editMenu);
1949          editMenu.add(a_undo);
1950          editMenu.add(a_redo);
1951          editMenu.addSeparator();
1952          editMenu.add(a_selectall);
1953          editMenu.add(a_delnode);
1954          editMenu.add(a_cutnode);
1955          editMenu.add(a_copynode);
1956          editMenu.add(a_pastenode);
1957          editMenu.addSeparator();
1958          editMenu.add(a_addnode);
1959          editMenu.add(a_addarc);
1960          editMenu.add(a_delarc);
1961          editMenu.addSeparator();
1962          editMenu.add(a_alignleft);
1963          editMenu.add(a_alignright);
1964          editMenu.add(a_aligntop);
1965          editMenu.add(a_alignbottom);
1966          editMenu.add(a_centerhorizontal);
1967          editMenu.add(a_centervertical);
1968          editMenu.add(a_spacehorizontal);
1969          editMenu.add(a_spacevertical);
1970
1971          JMenu toolMenu = new JMenu("Tools");
1972          toolMenu.setMnemonic('T');
1973          toolMenu.add(a_networkgenerator);
1974          toolMenu.add(a_datagenerator);
1975          toolMenu.add(a_datasetter);
1976          toolMenu.add(a_learn);
1977          toolMenu.add(a_learnCPT);
1978          toolMenu.addSeparator();
1979          toolMenu.add(a_layout);
1980          toolMenu.addSeparator();
1981          final JCheckBoxMenuItem viewMargins = new JCheckBoxMenuItem("Show Margins", false);
1982          viewMargins.addActionListener(new ActionListener() {
1983                  public void actionPerformed(ActionEvent ae) {
1984                          boolean bPrev = m_bViewMargins; 
1985                          m_bViewMargins = viewMargins.getState();
1986                          if (bPrev == false && viewMargins.getState() == true) {
1987                                  updateStatus();
1988                          }
1989                          repaint();
1990                  }
1991          });
1992          toolMenu.add(viewMargins);
1993          final JCheckBoxMenuItem viewCliques = new JCheckBoxMenuItem("Show Cliques", false);
1994          viewCliques.addActionListener(new ActionListener() {
1995                  public void actionPerformed(ActionEvent ae) {
1996                          boolean bPrev = m_bViewCliques; 
1997                          m_bViewCliques = viewCliques.getState();
1998                          if (bPrev == false && viewCliques.getState() == true) {
1999                                  updateStatus();
2000                          }
2001                          repaint();
2002                  }
2003          });
2004          toolMenu.add(viewCliques);
2005
2006          m_menuBar.add(toolMenu);
2007          JMenu viewMenu = new JMenu("View");
2008          viewMenu.setMnemonic('V');
2009          m_menuBar.add(viewMenu);
2010          viewMenu.add(a_zoomin);
2011          viewMenu.add(a_zoomout);
2012          viewMenu.addSeparator();
2013          viewMenu.add(a_viewtoolbar);
2014          viewMenu.add(a_viewstatusbar);
2015
2016          JMenu helpMenu = new JMenu("Help");
2017          helpMenu.setMnemonic('H');
2018          m_menuBar.add(helpMenu);
2019          helpMenu.add(a_help);
2020          helpMenu.add(a_about);
2021        }
2022
2023        /**
2024         * This method sets the node size that is appropriate considering the
2025         * maximum label size that is present. It is used internally when custom
2026         * node size checkbox is unchecked.
2027         */
2028        protected void setAppropriateNodeSize() {
2029                int strWidth;
2030                FontMetrics fm = this.getFontMetrics(this.getFont());
2031                int nMaxStringWidth = DEFAULT_NODE_WIDTH;
2032                if (nMaxStringWidth == 0)
2033                        for (int iNode = 0; iNode < m_BayesNet.getNrOfNodes(); iNode++) {
2034                                strWidth = fm.stringWidth(m_BayesNet.getNodeName(iNode));
2035                                if (strWidth > nMaxStringWidth)
2036                                        nMaxStringWidth = strWidth;
2037                        }
2038                m_nNodeWidth = nMaxStringWidth + 4;
2039                m_nPaddedNodeWidth = m_nNodeWidth + PADDING;
2040                m_jTfNodeWidth.setText("" + m_nNodeWidth);
2041
2042                m_nNodeHeight = 2 * fm.getHeight();
2043                m_jTfNodeHeight.setText("" + m_nNodeHeight);
2044        }
2045
2046        /**
2047         * Sets the preferred size for m_GraphPanel GraphPanel to the minimum size that is
2048         * neccessary to display the graph.
2049         */
2050        public void setAppropriateSize() {
2051                int maxX = 0, maxY = 0;
2052
2053                m_GraphPanel.setScale(m_fScale, m_fScale);
2054
2055                for (int iNode = 0; iNode < m_BayesNet.getNrOfNodes(); iNode++) {
2056                        int nPosX = m_BayesNet.getPositionX(iNode); 
2057                        int nPosY = m_BayesNet.getPositionY(iNode); 
2058                        if (maxX < nPosX)
2059                                maxX = nPosX + 100;
2060                        if (maxY < nPosY)
2061                                maxY = nPosY;
2062                }
2063                m_GraphPanel.setPreferredSize(new Dimension((int) ((maxX + m_nPaddedNodeWidth + 2) * m_fScale),
2064                                (int) ((maxY + m_nNodeHeight + 2) * m_fScale)));
2065                m_GraphPanel.revalidate();
2066        } // setAppropriateSize
2067
2068        /**
2069         * This method is an implementation for LayoutCompleteEventListener class.
2070         * It sets the size appropriate for m_GraphPanel GraphPanel and and revalidates it's
2071         * container JScrollPane once a LayoutCompleteEvent is received from the
2072         * LayoutEngine. Also, it updates positions of the Bayesian network stored
2073         * in m_BayesNet.
2074         */
2075        public void layoutCompleted(LayoutCompleteEvent le) {
2076                LayoutEngine layoutEngine  = m_layoutEngine; // (LayoutEngine) le.getSource();
2077                FastVector nPosX = new FastVector(m_BayesNet.getNrOfNodes());
2078                FastVector nPosY = new FastVector(m_BayesNet.getNrOfNodes());
2079                for (int iNode = 0; iNode < layoutEngine.getNodes().size(); iNode++) {
2080                        GraphNode gNode = (GraphNode) layoutEngine.getNodes().elementAt(iNode);
2081                        if (gNode.nodeType == GraphNode.NORMAL) {
2082                                nPosX.addElement(gNode.x);
2083                                nPosY.addElement(gNode.y);
2084                        }
2085                }
2086                m_BayesNet.layoutGraph(nPosX, nPosY);
2087                m_jStatusBar.setText("Graph layed out");
2088                a_undo.setEnabled(true);
2089                a_redo.setEnabled(false);
2090                setAppropriateSize();
2091                m_GraphPanel.invalidate();
2092                m_jScrollPane.revalidate();
2093                m_GraphPanel.repaint();
2094        } // layoutCompleted
2095
2096
2097        /**
2098         * BIF reader<br>
2099         * Reads a graph description in XMLBIF03 from an file
2100         * with name sFileName
2101         */
2102        public void readBIFFromFile(String sFileName) throws BIFFormatException, IOException {
2103                m_sFileName = sFileName;
2104                try {
2105
2106                        BIFReader bayesNet = new BIFReader();
2107                        bayesNet.processFile(sFileName);
2108                        m_BayesNet = new EditableBayesNet(bayesNet);
2109                        updateStatus();
2110                        a_datagenerator.setEnabled(m_BayesNet.getNrOfNodes() > 0);
2111                        m_BayesNet.clearUndoStack();
2112                } catch (Exception ex) {
2113                        ex.printStackTrace();
2114                        return;
2115                }
2116
2117                setAppropriateNodeSize();
2118                setAppropriateSize();
2119        } // readBIFFromFile
2120
2121        /* read arff file from file sFileName
2122         * and start new Bayesian network with nodes
2123         * representing attributes in data set.
2124         */
2125        void initFromArffFile(String sFileName) {
2126                try {
2127                        Instances instances = new Instances(new FileReader(sFileName));
2128                        m_BayesNet = new EditableBayesNet(instances);
2129                        m_Instances = instances;
2130                        a_learn.setEnabled(true);
2131                        a_learnCPT.setEnabled(true);
2132                        setAppropriateNodeSize();
2133                        setAppropriateSize();
2134                } catch (Exception ex) {
2135                        ex.printStackTrace();
2136                        return;
2137                }
2138        } // initFromArffFile
2139       
2140        /**
2141         * The panel which contains the actual Bayeian network.
2142         */
2143        private class GraphPanel extends PrintablePanel implements Printable {
2144
2145                /** for serialization */
2146                private static final long serialVersionUID = -3562813603236753173L;
2147
2148                /** node drawing modes */
2149                final static int HIGHLIGHTED = 1;
2150                final static int NORMAL = 0;
2151
2152                public GraphPanel() {
2153                        super();
2154                        this.addMouseListener(new GraphVisualizerMouseListener());
2155                        this.addMouseMotionListener(new GraphVisualizerMouseMotionListener());
2156                        this.setToolTipText("");
2157                } // c'tor
2158
2159                /* For showing instructions when hovering over a node
2160                 *  (non-Javadoc)
2161                 * @see javax.swing.JComponent#getToolTipText(java.awt.event.MouseEvent)
2162                 */
2163                public String getToolTipText(MouseEvent me) {
2164                        int x, y;
2165                        Rectangle r;
2166                        x = y  = 0;
2167
2168                        r = new Rectangle(0, 0, (int) (m_nPaddedNodeWidth * m_fScale), (int) (m_nNodeHeight * m_fScale));
2169                        x += me.getX();
2170                        y += me.getY();
2171                       
2172                        for (int iNode = 0; iNode < m_BayesNet.getNrOfNodes(); iNode++) {
2173                                r.x = (int) (m_BayesNet.getPositionX(iNode) * m_fScale);
2174                                r.y = (int) (m_BayesNet.getPositionY(iNode) * m_fScale);
2175                                if (r.contains(x, y)) {
2176                                        return m_BayesNet.getNodeName(iNode) + " (right click to manipulate this node)";
2177                                }
2178                        }
2179                        return null;
2180                } // getToolTipText
2181
2182                /* Code for showing the graph in the panel.
2183                 *  (non-Javadoc)
2184                 * @see javax.swing.JComponent#paintComponent(java.awt.Graphics)
2185                 */
2186                public void paintComponent(Graphics gr) {
2187                        Graphics2D g = (Graphics2D) gr;
2188                        RenderingHints rh = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
2189                        rh.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
2190                        g.setRenderingHints(rh);
2191                        g.scale(m_fScale, m_fScale);
2192                        Rectangle r = g.getClipBounds();
2193                        g.clearRect(r.x, r.y, r.width, r.height);
2194
2195                        if (m_bViewCliques) {
2196                                m_nClique = 1;
2197                                viewCliques(g, m_marginCalculator.m_root);
2198                        }                       
2199                        for (int iNode = 0; iNode < m_BayesNet.getNrOfNodes(); iNode++) {
2200                                drawNode(g, iNode, NORMAL);
2201                        }
2202                        if (!a_export.isExporting() && !a_print.isPrinting()) {
2203                                m_Selection.draw(g);
2204                        }
2205                        if (m_nSelectedRect != null) {
2206                                g.drawRect((int)(m_nSelectedRect.x/ m_fScale), 
2207                                                (int)(m_nSelectedRect.y/ m_fScale), 
2208                                                (int)(m_nSelectedRect.width/ m_fScale), 
2209                                                (int)(m_nSelectedRect.height/ m_fScale));
2210                        }
2211                } // paintComponent
2212
2213                /** number of the clique being drawn. Used for selecting the color of the clique */
2214                int m_nClique = 1;
2215
2216                /* draws cliques in junction tree.
2217                 *
2218                 */
2219                void viewCliques(Graphics g, JunctionTreeNode node) {
2220                                        int [] nodes = node.m_nNodes;
2221                                        g.setColor(
2222                                                        new Color(m_nClique % 7 * 256 /7, 
2223                                                        (m_nClique % 2 * 256 / 2),
2224                                                        (m_nClique % 3 * 256 / 3))
2225                                                        );
2226                                        int dX = m_nPaddedNodeWidth / 2 + m_nClique;
2227                                        int dY = m_nNodeHeight / 2;
2228                                        int nPosX = 0;
2229                                        int nPosY = 0;
2230                                        String sStr = "";
2231                                        for (int j = 0; j < nodes.length; j++) {
2232                                                nPosX += m_BayesNet.getPositionX(nodes[j]);
2233                                                nPosY += m_BayesNet.getPositionY(nodes[j]);
2234                                                sStr += " " + nodes[j];
2235                                                for (int k = j+1; k < nodes.length; k++) {
2236                                                        g.drawLine(
2237                                                                        m_BayesNet.getPositionX(nodes[j]) + dX,
2238                                                                        m_BayesNet.getPositionY(nodes[j]) + dY,
2239                                                                        m_BayesNet.getPositionX(nodes[k]) + dX,
2240                                                                        m_BayesNet.getPositionY(nodes[k]) + dY
2241                                                                        );
2242                                                }
2243                                        }
2244                                        m_nClique++;
2245                                        nPosX /= nodes.length;
2246                                        nPosY /= nodes.length;
2247                                        g.drawString("Clique " + m_nClique + "("+sStr+")", nPosX, nPosY);
2248                                        for (int iChild = 0; iChild < node.m_children.size(); iChild++) {
2249                                                viewCliques(g, (JunctionTreeNode) node.m_children.elementAt(iChild));
2250                                        }
2251                } // viewCliques
2252               
2253               
2254                /* Draw a node with index iNode on Graphics g at position
2255                 * Drawing mode can be NORMAL or HIGHLIGHTED.
2256                 */
2257                protected void drawNode(Graphics g, int iNode, int mode) {
2258                        int nPosX = m_BayesNet.getPositionX(iNode);
2259                        int nPosY = m_BayesNet.getPositionY(iNode);
2260                        g.setColor(this.getBackground().darker().darker());
2261                        FontMetrics fm = getFontMetrics(getFont());
2262                       
2263                        if (mode == HIGHLIGHTED) {
2264                                g.setXORMode(Color.green); // g.setColor(Color.green);
2265                        }
2266                        g.fillOval(nPosX + m_nPaddedNodeWidth - m_nNodeWidth - (m_nPaddedNodeWidth - m_nNodeWidth) / 2, nPosY,
2267                                        m_nNodeWidth, m_nNodeHeight);
2268                        g.setColor(Color.white);
2269                        if (mode == HIGHLIGHTED) {
2270                                g.setXORMode(Color.red);
2271                        }
2272
2273                        // Draw the node's label if it can fit inside the node's
2274                        // current width otherwise just display its node nr
2275                        // if it can fit in node's current width
2276                        if (fm.stringWidth(m_BayesNet.getNodeName(iNode)) <= m_nNodeWidth) {
2277                                g.drawString(m_BayesNet.getNodeName(iNode), nPosX + m_nPaddedNodeWidth / 2
2278                                                - fm.stringWidth(m_BayesNet.getNodeName(iNode)) / 2, nPosY + m_nNodeHeight / 2
2279                                                + fm.getHeight() / 2 - 2);
2280                        } else if (fm.stringWidth("" + iNode) <= m_nNodeWidth) {
2281                                g.drawString("" + iNode, nPosX + m_nPaddedNodeWidth / 2 - fm.stringWidth("" + iNode) / 2, 
2282                                                nPosY + m_nNodeHeight / 2 + fm.getHeight() / 2 - 2);
2283                        }
2284
2285                        if (mode == HIGHLIGHTED) {
2286                                g.setXORMode(Color.green);
2287                        }
2288
2289                        if (m_bViewMargins) {
2290                                if (m_BayesNet.getEvidence(iNode) < 0) {
2291                                        g.setColor(new Color(0, 128, 0));
2292                                } else {
2293                                        g.setColor(new Color(128, 0, 0));
2294                                }
2295                                double[] P = m_BayesNet.getMargin(iNode);
2296                                for (int iValue = 0; iValue < P.length; iValue++) {
2297                                        String sP = P[iValue] + "";
2298                                        if (sP.charAt(0) == '0') {
2299                                                sP = sP.substring(1);
2300                                        }
2301                                        if (sP.length() > 5) {
2302                                                sP = sP.substring(1, 5);
2303                                        }
2304                                        g.fillRect(nPosX + m_nPaddedNodeWidth, nPosY + iValue * 10 + 2, (int) (P[iValue] * 100), 8);
2305                                        g.drawString(m_BayesNet.getNodeValue(iNode, iValue) + " " + sP, nPosX + m_nPaddedNodeWidth
2306                                                        + (int) (P[iValue] * 100), nPosY + iValue * 10 + 10);
2307
2308                                }
2309                        }
2310                        if (m_bViewCliques) {
2311                                        return;
2312                        }
2313                        g.setColor(Color.black);
2314                        // Drawing all incoming edges into the node,
2315                        for (int iParent = 0; iParent < m_BayesNet.getNrOfParents(iNode); iParent++) {
2316                                int nParent = m_BayesNet.getParent(iNode, iParent);
2317                                int nPosX1 = nPosX + m_nPaddedNodeWidth / 2;
2318                                int nPosY1 = nPosY + m_nNodeHeight;
2319                                int nPosX2 = m_BayesNet.getPositionX(nParent);
2320                                int nPosY2 = m_BayesNet.getPositionY(nParent);
2321                                int nPosX2b = nPosX2 + m_nPaddedNodeWidth / 2;
2322                                int nPosY2b = nPosY2;
2323
2324                                double phi = Math.atan2((nPosX2b - nPosX1 + 0.0) * m_nNodeHeight, (nPosY2b - nPosY1 + 0.0) * m_nNodeWidth);
2325                                nPosX1 = (int) (nPosX + m_nPaddedNodeWidth / 2 + Math.sin(phi) * m_nNodeWidth / 2);
2326                                nPosY1 = (int) (nPosY + m_nNodeHeight / 2 + Math.cos(phi) * m_nNodeHeight / 2);
2327                                nPosX2b = (int) (nPosX2 + m_nPaddedNodeWidth / 2 - Math.sin(phi) * m_nNodeWidth / 2);
2328                                nPosY2b = (int) (nPosY2 + m_nNodeHeight / 2 - Math.cos(phi) * m_nNodeHeight / 2);
2329                                drawArrow(g, nPosX2b, nPosY2b, nPosX1, nPosY1);
2330                        }
2331                        if (mode == HIGHLIGHTED) {
2332                        FastVector children = m_BayesNet.getChildren(iNode);
2333                        for (int iChild = 0; iChild < children.size(); iChild++) {
2334                                int nChild = (Integer) children.elementAt(iChild);
2335                                int nPosX1 = nPosX + m_nPaddedNodeWidth / 2;
2336                                int nPosY1 = nPosY;
2337                                int nPosX2 = m_BayesNet.getPositionX(nChild);
2338                                int nPosY2 = m_BayesNet.getPositionY(nChild);
2339                                int nPosX2b = nPosX2 + m_nPaddedNodeWidth / 2;
2340                                int nPosY2b = nPosY2 + m_nNodeHeight;
2341
2342                                double phi = Math.atan2((nPosX2b - nPosX1 + 0.0) * m_nNodeHeight, (nPosY2b - nPosY1 + 0.0) * m_nNodeWidth);
2343                                nPosX1 = (int) (nPosX + m_nPaddedNodeWidth / 2 + Math.sin(phi) * m_nNodeWidth / 2);
2344                                nPosY1 = (int) (nPosY + m_nNodeHeight / 2 + Math.cos(phi) * m_nNodeHeight / 2);
2345                                nPosX2b = (int) (nPosX2 + m_nPaddedNodeWidth / 2 - Math.sin(phi) * m_nNodeWidth / 2);
2346                                nPosY2b = (int) (nPosY2 + m_nNodeHeight / 2 - Math.cos(phi) * m_nNodeHeight / 2);
2347                                drawArrow(g, nPosX1, nPosY1, nPosX2b, nPosY2b);
2348                        }
2349                        }
2350                } // drawNode
2351
2352               
2353                /**
2354                 * This method draws an arrow on a line from (x1,y1) to (x2,y2). The
2355                 * arrow head is seated on (x2,y2) and is in the direction of the line.
2356                 * If the arrow is needed to be drawn in the opposite direction then
2357                 * simply swap the order of (x1, y1) and (x2, y2) when calling this
2358                 * function.
2359                 */
2360                protected void drawArrow(Graphics g, int nPosX1, int nPosY1, int nPosX2, int nPosY2) {
2361                        g.drawLine(nPosX1, nPosY1, nPosX2, nPosY2);
2362
2363                        if (nPosX1 == nPosX2) {
2364                                if (nPosY1 < nPosY2) {
2365                                        g.drawLine(nPosX2, nPosY2, nPosX2 + 4, nPosY2 - 8);
2366                                        g.drawLine(nPosX2, nPosY2, nPosX2 - 4, nPosY2 - 8);
2367                                } else {
2368                                        g.drawLine(nPosX2, nPosY2, nPosX2 + 4, nPosY2 + 8);
2369                                        g.drawLine(nPosX2, nPosY2, nPosX2 - 4, nPosY2 + 8);
2370                                }
2371                        } else {
2372                                // theta=line's angle from base, beta=angle of arrow's side from
2373                                // line
2374                                double hyp = 0, base = 0, perp = 0, theta, beta;
2375                                int nPosX3 = 0, nPosY3 = 0;
2376
2377                                if (nPosX2 < nPosX1) {
2378                                        base = nPosX1 - nPosX2;
2379                                        hyp = Math.sqrt((nPosX2 - nPosX1) * (nPosX2 - nPosX1) + (nPosY2 - nPosY1) * (nPosY2 - nPosY1));
2380                                        theta = Math.acos(base / hyp);
2381                                } else { // x1>x2 as we already checked x1==x2 before
2382                                        base = nPosX1 - nPosX2;
2383                                        hyp = Math.sqrt((nPosX2 - nPosX1) * (nPosX2 - nPosX1) + (nPosY2 - nPosY1) * (nPosY2 - nPosY1));
2384                                        theta = Math.acos(base / hyp);
2385                                }
2386                                beta = 30 * Math.PI / 180;
2387
2388                                hyp = 8;
2389                                base = Math.cos(theta - beta) * hyp;
2390                                perp = Math.sin(theta - beta) * hyp;
2391
2392                                nPosX3 = (int) (nPosX2 + base);
2393                                if (nPosY1 < nPosY2)
2394                                        nPosY3 = (int) (nPosY2 - perp);
2395                                else
2396                                        nPosY3 = (int) (nPosY2 + perp);
2397
2398                                g.drawLine(nPosX2, nPosY2, nPosX3, nPosY3);
2399
2400                                base = Math.cos(theta + beta) * hyp;
2401                                perp = Math.sin(theta + beta) * hyp;
2402
2403                                nPosX3 = (int) (nPosX2 + base);
2404                                if (nPosY1 < nPosY2)
2405                                        nPosY3 = (int) (nPosY2 - perp);
2406                                else
2407                                        nPosY3 = (int) (nPosY2 + perp);
2408                                g.drawLine(nPosX2, nPosY2, nPosX3, nPosY3);
2409                        }
2410                } // drawArrow
2411
2412                /**
2413                 * This method highlights a given node and all its incoming and outgoing arcs
2414                 */
2415                public void highLight(int iNode) {
2416                        Graphics2D g = (Graphics2D) this.getGraphics();
2417                        RenderingHints rh = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
2418                        rh.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
2419                        g.setRenderingHints(rh);
2420                        g.setPaintMode();
2421                        g.scale(m_fScale, m_fScale);
2422                        drawNode(g, iNode, HIGHLIGHTED);
2423                } // highlight
2424
2425            /** implementation of Printable, used for printing
2426             * @see Printable
2427             */
2428                public int print(Graphics g, PageFormat pageFormat, int pageIndex) {
2429                  if (pageIndex > 0) {
2430                    return(NO_SUCH_PAGE);
2431                  } else {
2432                    Graphics2D g2d = (Graphics2D)g;
2433                    g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
2434                    double fHeight = pageFormat.getImageableHeight();
2435                    double fWidth = pageFormat.getImageableWidth();
2436                    int xMax = 1;
2437                    int yMax = 1;
2438                    for (int iNode = 0; iNode < m_BayesNet.getNrOfNodes(); iNode++) {
2439                        if (xMax < m_BayesNet.getPositionX(iNode)) {
2440                                xMax = m_BayesNet.getPositionX(iNode);
2441                        }
2442                        if (yMax < m_BayesNet.getPositionY(iNode)) {
2443                                yMax = m_BayesNet.getPositionY(iNode);
2444                        }
2445                    }
2446                    double fCurrentScale = m_fScale;
2447                    xMax += m_nPaddedNodeWidth + 100;
2448                    if (fWidth/xMax < fHeight/yMax) {
2449                        m_fScale = fWidth/xMax; 
2450                    } else {
2451                        m_fScale = fHeight/yMax;
2452                    }
2453                   
2454                    // Turn off double buffering
2455                    paint(g2d);
2456                    m_fScale = fCurrentScale;
2457                    // Turn double buffering back on
2458                    return(PAGE_EXISTS);
2459                  }
2460                } // print
2461                               
2462        } // class GraphPanel
2463
2464        /**
2465         * Table Model for the Table for editing CPTs
2466         */
2467        private class GraphVisualizerTableModel extends AbstractTableModel {
2468
2469                /** for serialization */
2470                private static final long serialVersionUID = -4789813491347366596L;
2471                /** labels for the columns */
2472                final String [] m_sColumnNames;
2473                /** probability table data **/
2474                final double [][] m_fProbs;
2475                /** nr of node for currently editted CPT */
2476                int m_iNode;
2477
2478                public GraphVisualizerTableModel(int iNode) {
2479                        m_iNode = iNode;
2480                        double [][] probs = m_BayesNet.getDistribution(iNode);
2481                        m_fProbs = new double[probs.length][probs[0].length];
2482                        for (int i = 0; i < probs.length; i++) {
2483                                for (int j = 0; j < probs[0].length; j++) {
2484                                        m_fProbs[i][j] = probs[i][j];
2485                                }
2486                        }
2487                        m_sColumnNames = m_BayesNet.getValues(iNode);
2488                } // c'tor
2489
2490                /** method that generates random CPTs
2491                 */
2492                public void randomize() {
2493                        int nProbs = m_fProbs[0].length;
2494                        Random random = new Random();
2495                        for (int i = 0; i < m_fProbs.length; i++) {
2496                                // get random nrs
2497                                for (int j = 0; j < nProbs-1; j++) {
2498                                        m_fProbs[i][j] = random.nextDouble();
2499                                }
2500                                // sort
2501                                for (int j = 0; j < nProbs-1; j++) {
2502                                        for (int k = j+1; k < nProbs-1; k++) {
2503                                                if (m_fProbs[i][j] > m_fProbs[i][k]) {
2504                                                        double h = m_fProbs[i][j]; 
2505                                                        m_fProbs[i][j] = m_fProbs[i][k];
2506                                                        m_fProbs[i][k] = h;
2507                                                }
2508                                        }
2509                                }
2510                                double sum = m_fProbs[i][0];
2511                                for (int j = 1; j < nProbs-1; j++) {
2512                                        m_fProbs[i][j] = m_fProbs[i][j] - sum;
2513                                        sum += m_fProbs[i][j]; 
2514                                }
2515                                m_fProbs[i][nProbs - 1] = 1.0 - sum;
2516                        }
2517                } // randomize
2518               
2519                public void setData() {}
2520
2521                /** return nr of colums */
2522                public int getColumnCount() {
2523                        return m_sColumnNames.length;
2524                }
2525
2526                /** return nr of rows */
2527                public int getRowCount() {
2528                        return m_fProbs.length;
2529                }
2530
2531                /** return name of specified colum
2532                 * @param iCol index of the column
2533                 */
2534                public String getColumnName(int iCol) {
2535                        return m_sColumnNames[iCol];
2536                }
2537                /** return data point
2538                 * @param iRow index of row in table
2539                 * @param iCol index of column in table
2540                 */
2541                public Object getValueAt(int iRow, int iCol) {
2542                        return new Double(m_fProbs[iRow][iCol]);
2543                }
2544
2545                /** Set data point, assigns value to CPT entry
2546                 * specified by row and column. The remainder of the
2547                 * CPT is normalized so that the values add up to 1.
2548                 * IF a value below zero of over 1 is given, no changes
2549                 * take place.
2550                 * @param oProb data point
2551                 * @param iRow index of row in table
2552                 * @param iCol index of column in table
2553                 */
2554                public void setValueAt(Object oProb, int iRow, int iCol) {
2555                        Double fProb = (Double) oProb;
2556                        if (fProb < 0 || fProb > 1) {
2557                                return;
2558                        }
2559                        m_fProbs[iRow][iCol] = (double) fProb;
2560                        double sum = 0;
2561                        for (int i = 0; i < m_fProbs[iRow].length; i++) {
2562                                sum += m_fProbs[iRow][i];
2563                        }
2564
2565                        if (sum > 1) {
2566                                // handle overflow
2567                                int i = m_fProbs[iRow].length - 1;
2568                                while (sum > 1) {
2569                                        if (i != iCol) {
2570                                                if (m_fProbs[iRow][i] > sum - 1) {
2571                                                        m_fProbs[iRow][i] -= sum - 1;
2572                                                        sum = 1;
2573                                                } else {
2574                                                        sum -= m_fProbs[iRow][i];
2575                                                        m_fProbs[iRow][i] = 0;
2576                                                }
2577                                        }
2578                                        i--;
2579                                }
2580                        } else {
2581                                // handle underflow
2582                                int i = m_fProbs[iRow].length - 1;
2583                                while (sum < 1) {
2584                                        if (i != iCol) {
2585                                                m_fProbs[iRow][i] += 1 - sum;
2586                                                sum = 1;
2587                                        }
2588                                        i--;
2589                                }
2590
2591                        }
2592                        validate();
2593                } // setData
2594
2595                /*
2596                 * JTable uses this method to determine the default renderer/ editor for
2597                 * each cell.
2598                 */
2599                public Class getColumnClass(int c) {
2600                        return getValueAt(0, c).getClass();
2601                }
2602
2603                /*
2604                 * Implemented this to make sure the table is uneditable.
2605                 */
2606                public boolean isCellEditable(int row, int col) {
2607                        return true;
2608                }
2609        } // class GraphVisualizerTableModel
2610
2611        /**
2612         * Listener class for processing mouseClicked
2613         */
2614        private class GraphVisualizerMouseListener extends MouseAdapter {
2615
2616                /** A left mouseclick on a node adds node to selection (depending
2617                 * on shift and ctrl keys).
2618                 * A right mouseclick on a node pops up menu with actions to be
2619                 * performed on the node.
2620                 * A right mouseclick outside another node pops up menu.
2621                 */
2622                public void mouseClicked(MouseEvent me) {
2623                        int x, y;
2624
2625                        Rectangle r = new Rectangle(0, 0, (int) (m_nPaddedNodeWidth * m_fScale), (int) (m_nNodeHeight * m_fScale));
2626                        x = me.getX();
2627                        y = me.getY();
2628
2629                        for (int iNode = 0; iNode < m_BayesNet.getNrOfNodes(); iNode++) {
2630                                r.x = (int) (m_BayesNet.getPositionX(iNode) * m_fScale);
2631                                r.y = (int) (m_BayesNet.getPositionY(iNode) * m_fScale);
2632                                if (r.contains(x, y)) {
2633                                        m_nCurrentNode = iNode;                                 
2634                                        if (me.getButton() == MouseEvent.BUTTON3) {
2635                                                handleRightNodeClick(me);
2636                                        }
2637                                        if (me.getButton() == MouseEvent.BUTTON1) {
2638                                                if ((me.getModifiersEx() & MouseEvent.CTRL_DOWN_MASK) != 0) {
2639                                                        m_Selection.toggleSelection(m_nCurrentNode);
2640                                                } else if ((me.getModifiersEx() & MouseEvent.SHIFT_DOWN_MASK) != 0) {
2641                                                        m_Selection.addToSelection(m_nCurrentNode);
2642                                                } else {
2643                                                        m_Selection.clear();
2644                                                        m_Selection.addToSelection(m_nCurrentNode);
2645                                                }
2646                                                repaint();
2647                                        }
2648                                        return;
2649                                }
2650                        }
2651                        if (me.getButton() == MouseEvent.BUTTON3) {
2652                                handleRightClick(me, (int)(x/m_fScale), (int)(y/m_fScale));
2653                        }
2654                } // mouseClicked
2655               
2656                /* update selection
2657                 *  (non-Javadoc)
2658                 * @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent)
2659                 */
2660                public void mouseReleased(MouseEvent me) {
2661                if (m_nSelectedRect != null) {
2662                                if ((me.getModifiersEx() & MouseEvent.CTRL_DOWN_MASK) != 0) {
2663                                        m_Selection.toggleSelection(m_nSelectedRect);
2664                                } else if ((me.getModifiersEx() & MouseEvent.SHIFT_DOWN_MASK) != 0) {
2665                                        m_Selection.addToSelection(m_nSelectedRect);
2666                                } else {
2667                                        m_Selection.clear();
2668                                m_Selection.addToSelection(m_nSelectedRect);
2669                                }
2670                        m_nSelectedRect = null;
2671                        repaint();
2672                }
2673            } // mouseReleased
2674
2675                /** position clicked on */
2676            int m_nPosX = 0, m_nPosY = 0;
2677           
2678            /* pop up menu with actions that apply in general or to selection (if any exists)
2679             */
2680            void handleRightClick(MouseEvent me, int nPosX, int nPosY) {
2681       
2682                        ActionListener act = new ActionListener() {
2683                                public void actionPerformed(ActionEvent ae) {
2684                                        if (ae.getActionCommand().equals("Add node")) {
2685                                                a_addnode.addNode(m_nPosX, m_nPosY);
2686                                                return;
2687                                        }
2688                                        repaint();
2689                                }
2690                        };
2691                        JPopupMenu popupMenu = new JPopupMenu("Choose a value");
2692
2693                        JMenuItem addNodeItem = new JMenuItem("Add node");
2694                        addNodeItem.addActionListener(act);
2695                        popupMenu.add(addNodeItem);
2696
2697                        FastVector selected = m_Selection.getSelected();
2698                        JMenu addArcMenu = new JMenu("Add parent");
2699                        popupMenu.add(addArcMenu);
2700                        if (selected.size() == 0) {
2701                                addArcMenu.setEnabled(false);
2702                        } else {
2703                        int nNodes = m_BayesNet.getNrOfNodes();
2704                        boolean[] isNotAllowedAsParent = new boolean[nNodes];
2705                        // prevent it being a parent of itself
2706                        for (int iNode = 0; iNode < selected.size(); iNode++) {
2707                                isNotAllowedAsParent[(Integer) selected.elementAt(iNode)] = true;
2708                        }
2709                        // prevent a descendant being a parent, since it introduces cycles
2710                        for (int i = 0; i < nNodes; i++) {
2711                                for (int iNode = 0; iNode < nNodes; iNode++) {
2712                                        for (int iParent = 0; iParent < m_BayesNet.getNrOfParents(iNode); iParent++) {
2713                                                if (isNotAllowedAsParent[m_BayesNet.getParent(iNode, iParent)]) {
2714                                                        isNotAllowedAsParent[iNode] = true;
2715                                                }
2716                                        }
2717                                }
2718                        }
2719                        // prevent nodes that are already a parent
2720                        for (int iNode = 0; iNode < selected.size(); iNode++) {
2721                                int nNode = (Integer) selected.elementAt(iNode);
2722                                for (int iParent = 0; iParent < m_BayesNet.getNrOfParents(nNode); iParent++) {
2723                                        isNotAllowedAsParent[m_BayesNet.getParent(nNode, iParent)] = true;
2724                                }
2725                        }
2726                        ActionListener addParentAction = new ActionListener() {
2727                                public void actionPerformed(ActionEvent ae) {
2728                                        try {
2729                                                m_BayesNet.addArc(ae.getActionCommand(), m_Selection.getSelected());
2730                                                m_jStatusBar.setText(m_BayesNet.lastActionMsg());
2731                                                updateStatus();
2732                                        } catch (Exception e) {
2733                                                e.printStackTrace();
2734                                        }
2735                                }
2736                        };
2737                        // count nr of remaining candidates
2738                        int nCandidates = 0;
2739                        for (int i = 0; i < nNodes; i++) {
2740                                if (!isNotAllowedAsParent[i]) {
2741                                        JMenuItem item = new JMenuItem(m_BayesNet.getNodeName(i));
2742                                        item.addActionListener(addParentAction);
2743                                        addArcMenu.add(item);
2744                                        nCandidates++;
2745                                }
2746                        }
2747                        if (nCandidates == 0) {
2748                                addArcMenu.setEnabled(false);
2749                        }
2750                        }
2751                        m_nPosX = nPosX;
2752                        m_nPosY = nPosY;
2753                        popupMenu.setLocation(me.getX(), me.getY());
2754                        popupMenu.show(m_GraphPanel, me.getX(), me.getY());
2755            } // handleRightClick
2756               
2757            /* pop up menu with actions that apply to node that was clicked on
2758             */
2759            void handleRightNodeClick(MouseEvent me) {
2760                        m_Selection.clear();
2761                        repaint();
2762                        ActionListener renameValueAction = new ActionListener() {
2763                                public void actionPerformed(ActionEvent ae) {
2764                                        renameValue(m_nCurrentNode, ae.getActionCommand());
2765                                }
2766                        };
2767                        ActionListener delValueAction = new ActionListener() {
2768                                public void actionPerformed(ActionEvent ae) {
2769                                        delValue(m_nCurrentNode, ae.getActionCommand());
2770                                }
2771                        };
2772                        ActionListener addParentAction = new ActionListener() {
2773                                public void actionPerformed(ActionEvent ae) {
2774                                        try {
2775                                                m_BayesNet.addArc(ae.getActionCommand(), m_BayesNet.getNodeName(m_nCurrentNode));
2776                                                m_jStatusBar.setText(m_BayesNet.lastActionMsg());
2777                                                updateStatus();
2778                                        } catch (Exception e) {
2779                                                e.printStackTrace();
2780                                        }
2781                                }
2782                        };
2783                        ActionListener delParentAction = new ActionListener() {
2784                                public void actionPerformed(ActionEvent ae) {
2785                                        deleteArc(m_nCurrentNode, ae.getActionCommand());
2786                                }
2787                        };
2788                        ActionListener delChildAction = new ActionListener() {
2789                                public void actionPerformed(ActionEvent ae) {
2790                                        deleteArc(ae.getActionCommand(), m_nCurrentNode);
2791                                }
2792                        };
2793                        ActionListener setAvidenceAction = new ActionListener() {
2794                                public void actionPerformed(ActionEvent ae) {
2795                                        try {
2796                                                String [] outcomes = m_BayesNet.getValues(m_nCurrentNode);
2797                                                int iValue = 0;
2798                                                while (iValue < outcomes.length && !outcomes[iValue].equals(ae.getActionCommand())) {
2799                                                        iValue++;
2800                                                }
2801
2802                                                if (iValue == outcomes.length) {
2803                                                        iValue = -1;
2804                                                }
2805                                                if (iValue < outcomes.length) {
2806                                                    m_jStatusBar.setText("Set evidence for " + m_BayesNet.getNodeName(m_nCurrentNode));
2807                                                                if (m_BayesNet.getEvidence(m_nCurrentNode) < 0 && iValue >= 0) {
2808                                                                        m_BayesNet.setEvidence(m_nCurrentNode, iValue);
2809                                                                        m_marginCalculatorWithEvidence.setEvidence(m_nCurrentNode, iValue);
2810                                                                } else {
2811                                                                        m_BayesNet.setEvidence(m_nCurrentNode, iValue);
2812                                                                        SerializedObject so = new SerializedObject(m_marginCalculator);
2813                                                                        m_marginCalculatorWithEvidence = (MarginCalculator) so.getObject();
2814                                                                        for (int iNode = 0; iNode < m_BayesNet.getNrOfNodes(); iNode++) {
2815                                                                                if (m_BayesNet.getEvidence(iNode) >= 0) {
2816                                                                                        m_marginCalculatorWithEvidence.setEvidence(iNode, m_BayesNet.getEvidence(iNode));
2817                                                                                }
2818                                                                        }
2819                                                                }
2820                                                        for (int iNode = 0; iNode < m_BayesNet.getNrOfNodes(); iNode++) {
2821                                                                m_BayesNet.setMargin(iNode, m_marginCalculatorWithEvidence.getMargin(iNode));
2822                                                        }
2823                                                }
2824                                                } catch (Exception e) {
2825                                                        e.printStackTrace();
2826                                                }
2827                                                repaint();
2828                                }
2829                        };
2830                       
2831                        ActionListener act = new ActionListener() {
2832                                public void actionPerformed(ActionEvent ae) {
2833                                        if (ae.getActionCommand().equals("Rename")) {
2834                                                renameNode(m_nCurrentNode);
2835                                                return;
2836                                        }
2837                                        if (ae.getActionCommand().equals("Add parent")) {
2838                                                addArcInto(m_nCurrentNode);
2839                                                return;
2840                                        }
2841                                        if (ae.getActionCommand().equals("Add value")) {
2842                                                addValue();
2843                                                return;
2844                                        }
2845                                        if (ae.getActionCommand().equals("Delete node")) {
2846                                                deleteNode(m_nCurrentNode);
2847                                                return;
2848                                        }
2849                                        if (ae.getActionCommand().equals("Edit CPT")) {
2850                                                editCPT(m_nCurrentNode);
2851                                                return;
2852                                        }
2853                                        repaint();
2854                                }
2855                        };
2856                        try {
2857                        JPopupMenu popupMenu = new JPopupMenu("Choose a value");
2858
2859                        JMenu setEvidenceMenu = new JMenu("Set evidence");
2860                        String [] outcomes = m_BayesNet.getValues(m_nCurrentNode);
2861                        for (int iValue = 0; iValue < outcomes.length; iValue++) {
2862                                JMenuItem item = new JMenuItem(outcomes[iValue]);
2863                                item.addActionListener(setAvidenceAction);
2864                                setEvidenceMenu.add(item);
2865                        }
2866                        setEvidenceMenu.addSeparator();
2867                        JMenuItem item = new JMenuItem("Clear");
2868                        item.addActionListener(setAvidenceAction);
2869                        setEvidenceMenu.add(item);
2870                        popupMenu.add(setEvidenceMenu);
2871
2872                        setEvidenceMenu.setEnabled(m_bViewMargins);
2873
2874                        popupMenu.addSeparator();
2875
2876                        JMenuItem renameItem = new JMenuItem("Rename");
2877                        renameItem.addActionListener(act);
2878                        popupMenu.add(renameItem);
2879
2880                        JMenuItem delNodeItem = new JMenuItem("Delete node");
2881                        delNodeItem.addActionListener(act);
2882                        popupMenu.add(delNodeItem);
2883
2884                        JMenuItem editCPTItem = new JMenuItem("Edit CPT");
2885                        editCPTItem.addActionListener(act);
2886                        popupMenu.add(editCPTItem);
2887
2888                        popupMenu.addSeparator();
2889                       
2890                        JMenu addArcMenu = new JMenu("Add parent");
2891                        popupMenu.add(addArcMenu);
2892                        int nNodes = m_BayesNet.getNrOfNodes();
2893                        boolean[] isNotAllowedAsParent = new boolean[nNodes];
2894                        // prevent it being a parent of itself
2895                        isNotAllowedAsParent[m_nCurrentNode] = true;
2896                        // prevent a descendant being a parent, since it introduces cycles
2897                        for (int i = 0; i < nNodes; i++) {
2898                                for (int iNode = 0; iNode < nNodes; iNode++) {
2899                                        for (int iParent = 0; iParent < m_BayesNet.getNrOfParents(iNode); iParent++) {
2900                                                if (isNotAllowedAsParent[m_BayesNet.getParent(iNode, iParent)]) {
2901                                                        isNotAllowedAsParent[iNode] = true;
2902                                                }
2903                                        }
2904                                }
2905                        }
2906                        // prevent nodes that are already a parent
2907                        for (int iParent = 0; iParent < m_BayesNet.getNrOfParents(m_nCurrentNode); iParent++) {
2908                                isNotAllowedAsParent[m_BayesNet.getParent(m_nCurrentNode, iParent)] = true;
2909                        }
2910                        // count nr of remaining candidates
2911                        int nCandidates = 0;
2912                        for (int i = 0; i < nNodes; i++) {
2913                                if (!isNotAllowedAsParent[i]) {
2914                                        item = new JMenuItem(m_BayesNet.getNodeName(i));
2915                                        item.addActionListener(addParentAction);
2916                                        addArcMenu.add(item);
2917                                        nCandidates++;
2918                                }
2919                        }
2920                        if (nCandidates == 0) {
2921                                addArcMenu.setEnabled(false);
2922                        }
2923                                                                       
2924                        JMenu delArcMenu = new JMenu("Delete parent");
2925                        popupMenu.add(delArcMenu);
2926                        if (m_BayesNet.getNrOfParents(m_nCurrentNode) == 0) {
2927                                delArcMenu.setEnabled(false);
2928                        }
2929                        for (int iParent = 0; iParent < m_BayesNet.getNrOfParents(m_nCurrentNode); iParent++) {
2930                                item = new JMenuItem(m_BayesNet.getNodeName(m_BayesNet.getParent(m_nCurrentNode, iParent)));
2931                                item.addActionListener(delParentAction);
2932                                delArcMenu.add(item);
2933                        }
2934                        JMenu delChildMenu = new JMenu("Delete child");
2935                        popupMenu.add(delChildMenu);
2936                        FastVector nChildren = m_BayesNet.getChildren(m_nCurrentNode); 
2937                        if (nChildren.size() == 0) {
2938                                delChildMenu.setEnabled(false);
2939                        }
2940                        for (int iChild = 0; iChild < nChildren.size(); iChild++) {
2941                                item = new JMenuItem(m_BayesNet.getNodeName((Integer) nChildren.elementAt(iChild)));
2942                                item.addActionListener(delChildAction);
2943                                delChildMenu.add(item);
2944                        }
2945
2946                        popupMenu.addSeparator();
2947
2948                        JMenuItem addValueItem = new JMenuItem("Add value");
2949                        addValueItem.addActionListener(act);
2950                        popupMenu.add(addValueItem);
2951
2952                        JMenu renameValue = new JMenu("Rename value");
2953                        popupMenu.add(renameValue);
2954                        for (int iValue = 0; iValue < outcomes.length; iValue++) {
2955                                item = new JMenuItem(outcomes[iValue]);
2956                                item.addActionListener(renameValueAction);
2957                                renameValue.add(item);
2958                        }
2959
2960                        JMenu delValue = new JMenu("Delete value");
2961                        popupMenu.add(delValue);
2962                        if (m_BayesNet.getCardinality(m_nCurrentNode) <= 2) {
2963                                delValue.setEnabled(false);
2964                        }
2965                        for (int iValue = 0; iValue < outcomes.length; iValue++) {
2966                                JMenuItem delValueItem = new JMenuItem(outcomes[iValue]);
2967                                delValueItem.addActionListener(delValueAction);
2968                                delValue.add(delValueItem);
2969                        }
2970                       
2971                        popupMenu.setLocation(me.getX(), me.getY());
2972                        popupMenu.show(m_GraphPanel, me.getX(), me.getY());
2973                        } catch (Exception e) {
2974                                e.printStackTrace();
2975                        }
2976                } // handleRightNodeClick
2977        } // class GraphVisualizerMouseListener
2978
2979        /**
2980         * private class for handling mouseMoved events to highlight nodes if the
2981         * the mouse is moved on one, move it around or move selection around
2982         */
2983        private class GraphVisualizerMouseMotionListener extends MouseMotionAdapter {
2984
2985                /* last node moved over. Used for turning highlight on and off */
2986                int m_nLastNode = -1;
2987                /* current mouse position clicked */
2988                int m_nPosX, m_nPosY;
2989
2990                /* identify the node under the mouse
2991                 * @returns node index of node under mouse, or -1 if there is no such node
2992                 */
2993                int getGraphNode(MouseEvent me) {
2994                        m_nPosX = m_nPosY  = 0;
2995
2996                        Rectangle r = new Rectangle(0, 0, (int) (m_nPaddedNodeWidth * m_fScale), (int) (m_nNodeHeight * m_fScale));
2997                        m_nPosX += me.getX();
2998                        m_nPosY += me.getY();
2999
3000                        for (int iNode = 0; iNode < m_BayesNet.getNrOfNodes(); iNode++) {                               
3001                                r.x = (int) (m_BayesNet.getPositionX(iNode) * m_fScale);
3002                                r.y = (int) (m_BayesNet.getPositionY(iNode) * m_fScale);
3003                                if (r.contains(m_nPosX, m_nPosY)) {
3004                                        return iNode;
3005                                }
3006                        }
3007                        return -1;
3008                } // getGraphNode
3009
3010                /* handle mouse dragging event
3011                 *  (non-Javadoc)
3012                 * @see java.awt.event.MouseMotionListener#mouseDragged(java.awt.event.MouseEvent)
3013                 */
3014                public void mouseDragged(MouseEvent me) {
3015                        if (m_nSelectedRect != null) {
3016                                m_nSelectedRect.width = me.getPoint().x - m_nSelectedRect.x;
3017                                m_nSelectedRect.height = me.getPoint().y - m_nSelectedRect.y;
3018                                repaint();
3019                                return;
3020                        }
3021                        int iNode = getGraphNode(me);
3022                        if (iNode >= 0) {
3023                                if (m_Selection.getSelected().size() > 0) {
3024                                        if (m_Selection.getSelected().contains(iNode)) {
3025                                                m_BayesNet.setPosition(iNode, (int) ((m_nPosX / m_fScale - m_nPaddedNodeWidth / 2)),
3026                                                        (int) ((m_nPosY / m_fScale - m_nNodeHeight / 2)), m_Selection.getSelected());
3027                                        } else {
3028                                                m_Selection.clear();
3029                                                m_BayesNet.setPosition(iNode, (int) ((m_nPosX / m_fScale - m_nPaddedNodeWidth / 2)),
3030                                                                (int) ((m_nPosY / m_fScale - m_nNodeHeight / 2)));
3031                                        }
3032                                        repaint();
3033                                } else {
3034                                        m_BayesNet.setPosition(iNode, (int) ((m_nPosX / m_fScale - m_nPaddedNodeWidth / 2)),
3035                                                (int) ((m_nPosY / m_fScale - m_nNodeHeight / 2)));
3036                                }
3037                            m_jStatusBar.setText(m_BayesNet.lastActionMsg());
3038                                a_undo.setEnabled(true);
3039                                a_redo.setEnabled(false);
3040                                m_GraphPanel.highLight(iNode);
3041                        }
3042                        if (iNode < 0) {
3043                                if (m_nLastNode >= 0) {
3044                                        m_GraphPanel.repaint();
3045                                        m_nLastNode = -1;
3046                                } else {
3047                                        m_nSelectedRect = new Rectangle(me.getPoint().x, me.getPoint().y, 1, 1);
3048                                        m_GraphPanel.repaint();
3049                                }
3050                        }
3051                } // mouseDragged
3052               
3053                /* handles mouse move event
3054                 *  (non-Javadoc)
3055                 * @see java.awt.event.MouseMotionListener#mouseMoved(java.awt.event.MouseEvent)
3056                 */
3057                public void mouseMoved(MouseEvent me) {
3058                        int iNode = getGraphNode(me);
3059                        if (iNode >= 0) {
3060                                if (iNode != m_nLastNode) {
3061                                        m_GraphPanel.highLight(iNode);
3062                                        if (m_nLastNode >= 0) {
3063                                                m_GraphPanel.highLight(m_nLastNode);
3064                                        }
3065                                        m_nLastNode = iNode;
3066                                }
3067                        }
3068                        if (iNode < 0 && m_nLastNode >= 0) {
3069                                m_GraphPanel.repaint();
3070                                m_nLastNode = -1;
3071                        }
3072                } // mouseMoved
3073               
3074        } // class GraphVisualizerMouseMotionListener
3075
3076        /* apply graph layout algorithm to Bayesian network
3077         */
3078        void layoutGraph() {
3079                if (m_BayesNet.getNrOfNodes() == 0) {
3080                        return;
3081                }
3082                try {
3083                        FastVector m_nodes = new FastVector();
3084                        FastVector m_edges = new FastVector();
3085                        BIFParser bp = new BIFParser(m_BayesNet.toXMLBIF03(), m_nodes, m_edges);
3086                        bp.parse();
3087                        updateStatus();
3088                        m_layoutEngine = new HierarchicalBCEngine(m_nodes, m_edges, m_nPaddedNodeWidth, m_nNodeHeight);
3089                        m_layoutEngine.addLayoutCompleteEventListener(this);
3090                        m_layoutEngine.layoutGraph();
3091                } catch (Exception e) {
3092                        e.printStackTrace();
3093                }
3094        } // layoutGraph
3095       
3096        /* Update status of various items that need regular updating
3097         * such as enabled status of some menu items, marginal distributions
3098         * if shown, repainting of graph.
3099         */
3100        void updateStatus() {
3101                a_undo.setEnabled(m_BayesNet.canUndo());
3102                a_redo.setEnabled(m_BayesNet.canRedo());
3103
3104                a_datagenerator.setEnabled(m_BayesNet.getNrOfNodes() > 0);
3105
3106                if (!m_bViewMargins && !m_bViewCliques) {
3107                        repaint();
3108                        return;
3109                }
3110
3111                try {
3112                        m_marginCalculator = new MarginCalculator();
3113                        m_marginCalculator.calcMargins(m_BayesNet);
3114                        SerializedObject so = new SerializedObject(m_marginCalculator);
3115                        m_marginCalculatorWithEvidence = (MarginCalculator) so.getObject();
3116                        for (int iNode = 0; iNode < m_BayesNet.getNrOfNodes(); iNode++) {
3117                                if (m_BayesNet.getEvidence(iNode) >= 0) {
3118                                        m_marginCalculatorWithEvidence.setEvidence(iNode, m_BayesNet.getEvidence(iNode));
3119                                }
3120                        }
3121                        for (int iNode = 0; iNode < m_BayesNet.getNrOfNodes(); iNode++) {
3122                                m_BayesNet.setMargin(iNode, m_marginCalculatorWithEvidence.getMargin(iNode));
3123                        }
3124                } catch (Exception e) {
3125                        e.printStackTrace();
3126                }
3127                repaint();
3128        } // updateStatus
3129
3130        /* add arc with node iChild as child.
3131         * This pops up a selection list with potential parents for the child.
3132         * All decendants and current parents are excluded from the list as is
3133         * the child node itself.
3134         * @param iChild index of the node for which to add an arc
3135         */
3136        void addArcInto(int iChild) {
3137                String sChild = m_BayesNet.getNodeName(iChild);
3138                try {
3139                        int nNodes = m_BayesNet.getNrOfNodes();
3140                        boolean[] isNotAllowedAsParent = new boolean[nNodes];
3141                        // prevent it being a parent of itself
3142                        isNotAllowedAsParent[iChild] = true;
3143                        // prevent a descendant being a parent, since it introduces cycles
3144                        for (int i = 0; i < nNodes; i++) {
3145                                for (int iNode = 0; iNode < nNodes; iNode++) {
3146                                        for (int iParent = 0; iParent < m_BayesNet.getNrOfParents(iNode); iParent++) {
3147                                                if (isNotAllowedAsParent[m_BayesNet.getParent(iNode, iParent)]) {
3148                                                        isNotAllowedAsParent[iNode] = true;
3149                                                }
3150                                        }
3151                                }
3152                        }
3153                        // prevent nodes that are already a parent
3154                        for (int iParent = 0; iParent < m_BayesNet.getNrOfParents(iChild); iParent++) {
3155                                isNotAllowedAsParent[m_BayesNet.getParent(iChild, iParent)] = true;
3156                        }
3157                        // count nr of remaining candidates
3158                        int nCandidates = 0;
3159                        for (int i = 0; i < nNodes; i++) {
3160                                if (!isNotAllowedAsParent[i]) {
3161                                        nCandidates++;
3162                                }
3163                        }
3164                        if (nCandidates == 0) {
3165                                JOptionPane.showMessageDialog(null, "No potential parents available for this node (" + sChild
3166                                                + "). Choose another node as child node.");
3167                                return;
3168                        }
3169                        String[] options = new String[nCandidates];
3170                        int k = 0;
3171                        for (int i = 0; i < nNodes; i++) {
3172                                if (!isNotAllowedAsParent[i]) {
3173                                        options[k++] = m_BayesNet.getNodeName(i);
3174                                }
3175                        }
3176                        String sParent = (String) JOptionPane.showInputDialog(null, "Select parent node for " + sChild, "Nodes", 0,
3177                                        null, options, options[0]);
3178                        if (sParent == null || sParent.equals("")) {
3179                                return;
3180                        }
3181                        // update all data structures
3182                        m_BayesNet.addArc(sParent, sChild);
3183                    m_jStatusBar.setText(m_BayesNet.lastActionMsg());
3184                    updateStatus();
3185                } catch (Exception e) {
3186                        e.printStackTrace();
3187                }
3188        } // addArcInto
3189
3190        /* deletes arc from node with name sParent into child with index iChild
3191         *
3192         */
3193        void deleteArc(int iChild, String sParent) {
3194                try {
3195                        m_BayesNet.deleteArc(m_BayesNet.getNode(sParent), iChild);
3196                    m_jStatusBar.setText(m_BayesNet.lastActionMsg());
3197                } catch (Exception e) {
3198                        e.printStackTrace();
3199                }
3200                updateStatus();
3201        } // deleteArc
3202       
3203        /* deletes arc from node with index iParent into child with name sChild
3204         *
3205         */
3206        void deleteArc(String sChild, int iParent) {
3207                try {
3208                        m_BayesNet.deleteArc(iParent, m_BayesNet.getNode(sChild));
3209                    m_jStatusBar.setText(m_BayesNet.lastActionMsg());
3210                } catch (Exception e) {
3211                        e.printStackTrace();
3212                }
3213                updateStatus();
3214        } // deleteArc
3215
3216        /* deletes arc. Pops up list of arcs listed in 'options' as
3217         * "<Node1> -> <Node2>".
3218         */
3219        void deleteArc(String[] options) {
3220                String sResult = (String) JOptionPane.showInputDialog(null, "Select arc to delete", "Arcs", 0, null, options,
3221                                options[0]);
3222                if (sResult != null && !sResult.equals("")) {
3223                        int nPos = sResult.indexOf(" -> ");
3224                        String sParent = sResult.substring(0, nPos);
3225                        String sChild = sResult.substring(nPos + 4);
3226                        try {
3227                                m_BayesNet.deleteArc(sParent, sChild);
3228                            m_jStatusBar.setText(m_BayesNet.lastActionMsg());
3229                        } catch (Exception e) {
3230                                e.printStackTrace();
3231                        }
3232                        updateStatus();
3233                }
3234        } // deleteArc
3235
3236        /* Rename node with index nTargetNode.
3237         * Pops up window that allwos for entering a new name.
3238         */
3239        void renameNode(int nTargetNode) {
3240                String sName = (String) JOptionPane.showInputDialog(null, m_BayesNet.getNodeName(nTargetNode), "New name for node",
3241                                JOptionPane.OK_CANCEL_OPTION);
3242                if (sName == null || sName.equals("")) {
3243                        return;
3244                }
3245                try {
3246                        while (m_BayesNet.getNode2(sName) >= 0) {
3247                                sName = (String) JOptionPane.showInputDialog(null, "Cannot rename to " + sName
3248                                                + ".\nNode with that name already exists.");
3249                                if (sName == null || sName.equals("")) {
3250                                        return;
3251                                }
3252                        }
3253                        m_BayesNet.setNodeName(nTargetNode, sName);
3254                    m_jStatusBar.setText(m_BayesNet.lastActionMsg());
3255                } catch (Exception e) {
3256                        e.printStackTrace();
3257                }
3258                repaint();
3259        } // renameNode
3260
3261        /* Rename value with name sValeu of a node with index nTargetNode.
3262         * Pops up window that allows entering a new name.
3263         */
3264        void renameValue(int nTargetNode, String sValue) {
3265                String sNewValue = (String) JOptionPane.showInputDialog(null, "New name for value " + sValue, "Node "
3266                                + m_BayesNet.getNodeName(nTargetNode), JOptionPane.OK_CANCEL_OPTION);
3267                if (sNewValue == null || sNewValue.equals("")) {
3268                        return;
3269                }
3270                m_BayesNet.renameNodeValue(nTargetNode, sValue, sNewValue);
3271            m_jStatusBar.setText(m_BayesNet.lastActionMsg());
3272                a_undo.setEnabled(true);
3273                a_redo.setEnabled(false);
3274                repaint();
3275        } // renameValue
3276
3277        /* delete a single node with index iNode */
3278        void deleteNode(int iNode) {
3279                try {
3280                        m_BayesNet.deleteNode(iNode);
3281                    m_jStatusBar.setText(m_BayesNet.lastActionMsg());
3282                } catch (Exception e) {
3283                        e.printStackTrace();
3284                }
3285                updateStatus();
3286        } // deleteNode
3287
3288        /* Add a value to currently selected node.
3289         * Shows window that allows to enter the name of the value.
3290         */
3291        void addValue() {
3292                //GraphNode n = (GraphNode) m_nodes.elementAt(m_nCurrentNode);
3293                String sValue = "Value" + (m_BayesNet.getCardinality(m_nCurrentNode) + 1);
3294                String sNewValue = (String) JOptionPane.showInputDialog(null, "New value " + sValue, "Node " + m_BayesNet.getNodeName(m_nCurrentNode),
3295                                JOptionPane.OK_CANCEL_OPTION);
3296                if (sNewValue == null || sNewValue.equals("")) {
3297                        return;
3298                }
3299                try {
3300                        m_BayesNet.addNodeValue(m_nCurrentNode, sNewValue);
3301                    m_jStatusBar.setText(m_BayesNet.lastActionMsg());
3302                        //n.outcomes = m_BayesNet.getValues(m_nCurrentNode);
3303                        //for (int iNode = 0; iNode < m_BayesNet.getNrOfNodes(); iNode++) {
3304                        //      n = (GraphNode) m_nodes.elementAt(iNode);
3305                        //      n.probs = m_BayesNet.getDistribution(iNode);
3306                        //}
3307                } catch (Exception e) {
3308                        e.printStackTrace();
3309                }
3310                updateStatus();
3311        } // addValue
3312
3313        /* remove value with name sValue from the node with index nTargetNode
3314         */
3315        void delValue(int nTargetNode, String sValue) {
3316                try {
3317                        m_BayesNet.delNodeValue(nTargetNode, sValue);
3318                    m_jStatusBar.setText(m_BayesNet.lastActionMsg());
3319                } catch (Exception e) {
3320                        e.printStackTrace();
3321                }
3322                updateStatus();
3323        } // delValue
3324
3325        /* Edits CPT of node with index nTargetNode.
3326         * Pops up table with probability table that the user can change or just view.
3327         */
3328        void editCPT(int nTargetNode) {
3329                m_nCurrentNode = nTargetNode;
3330                final GraphVisualizerTableModel tm = new GraphVisualizerTableModel(nTargetNode);
3331
3332                JTable jTblProbs = new JTable(tm); 
3333
3334                JScrollPane js = new JScrollPane(jTblProbs);
3335
3336                int nParents = m_BayesNet.getNrOfParents(nTargetNode);
3337                if (nParents > 0) {
3338                        GridBagConstraints gbc = new GridBagConstraints();
3339                        JPanel jPlRowHeader = new JPanel(new GridBagLayout());
3340
3341                        // indices of the parent nodes in the Vector
3342                        int[] idx = new int[nParents];
3343                        // max length of values of each parent
3344                        int[] lengths = new int[nParents];
3345
3346                        // Adding labels for rows
3347                        gbc.anchor = GridBagConstraints.NORTHWEST;
3348                        gbc.fill = GridBagConstraints.HORIZONTAL;
3349                        gbc.insets = new Insets(0, 1, 0, 0);
3350                        int addNum = 0, temp = 0;
3351                        boolean dark = false;
3352                        while (true) {
3353                                gbc.gridwidth = 1;
3354                                for (int k = 0; k < nParents; k++) {
3355                                        int iParent2 = m_BayesNet.getParent(nTargetNode, k); 
3356                                        JLabel lb = new JLabel(m_BayesNet.getValueName(iParent2,idx[k]));
3357                                        lb.setFont(new Font("Dialog", Font.PLAIN, 12));
3358                                        lb.setOpaque(true);
3359                                        lb.setBorder(BorderFactory.createEmptyBorder(1, 2, 1, 1));
3360                                        lb.setHorizontalAlignment(JLabel.CENTER);
3361                                        if (dark) {
3362                                                lb.setBackground(lb.getBackground().darker());
3363                                                lb.setForeground(Color.white);
3364                                        } else
3365                                                lb.setForeground(Color.black);
3366
3367                                        temp = lb.getPreferredSize().width;
3368                                        lb.setPreferredSize(new Dimension(temp, jTblProbs.getRowHeight()));
3369                                        if (lengths[k] < temp)
3370                                                lengths[k] = temp;
3371                                        temp = 0;
3372
3373                                        if (k == nParents - 1) {
3374                                                gbc.gridwidth = GridBagConstraints.REMAINDER;
3375                                                dark = (dark == true) ? false : true;
3376                                        }
3377                                        jPlRowHeader.add(lb, gbc);
3378                                        addNum++;
3379                                }
3380
3381                                for (int k = nParents - 1; k >= 0; k--) {
3382                                        int iParent2 = m_BayesNet.getParent(m_nCurrentNode, k);
3383                                        if (idx[k] == m_BayesNet.getCardinality(iParent2) - 1 && k != 0) {
3384                                                idx[k] = 0;
3385                                                continue;
3386                                        } else {
3387                                                idx[k]++;
3388                                                break;
3389                                        }
3390                                }
3391
3392                                int iParent2 = m_BayesNet.getParent(m_nCurrentNode, 0);
3393                                if (idx[0] == m_BayesNet.getCardinality(iParent2)) {
3394                                        JLabel lb = (JLabel) jPlRowHeader.getComponent(addNum - 1);
3395                                        jPlRowHeader.remove(addNum - 1);
3396                                        lb.setPreferredSize(new Dimension(lb.getPreferredSize().width, jTblProbs
3397                                                        .getRowHeight()));
3398                                        gbc.gridwidth = GridBagConstraints.REMAINDER;
3399                                        gbc.weighty = 1;
3400                                        jPlRowHeader.add(lb, gbc);
3401                                        gbc.weighty = 0;
3402                                        break;
3403                                }
3404                        }
3405
3406                        gbc.gridwidth = 1;
3407                        // The following panel contains the names of the
3408                        // parents
3409                        // and is displayed above the row names to identify
3410                        // which value belongs to which parent
3411                        JPanel jPlRowNames = new JPanel(new GridBagLayout());
3412                        for (int j = 0; j < nParents; j++) {
3413                                JLabel lb2;
3414                                JLabel lb1 = new JLabel(m_BayesNet.getNodeName(m_BayesNet.getParent(nTargetNode, j)));
3415                                lb1.setBorder(BorderFactory.createEmptyBorder(1, 2, 1, 1));
3416                                Dimension tempd = lb1.getPreferredSize();
3417                                if (tempd.width < lengths[j]) {
3418                                        lb1.setPreferredSize(new Dimension(lengths[j], tempd.height));
3419                                        lb1.setHorizontalAlignment(JLabel.CENTER);
3420                                        lb1.setMinimumSize(new Dimension(lengths[j], tempd.height));
3421                                } else if (tempd.width > lengths[j]) {
3422                                        lb2 = (JLabel) jPlRowHeader.getComponent(j);
3423                                        lb2.setPreferredSize(new Dimension(tempd.width, lb2.getPreferredSize().height));
3424                                }
3425                                jPlRowNames.add(lb1, gbc);
3426                        }
3427                        js.setRowHeaderView(jPlRowHeader);
3428                        js.setCorner(JScrollPane.UPPER_LEFT_CORNER, jPlRowNames);
3429                }
3430
3431                final JDialog dlg = new JDialog((Frame) GUI.this.getTopLevelAncestor(),
3432                                "Probability Distribution Table For " + m_BayesNet.getNodeName(nTargetNode), true);
3433                dlg.setSize(500, 400);
3434                dlg.setLocation(GUI.this.getLocation().x + GUI.this.getWidth() / 2
3435                                - 250, GUI.this.getLocation().y + GUI.this.getHeight() / 2
3436                                - 200);
3437
3438                dlg.getContentPane().setLayout(new BorderLayout());
3439                dlg.getContentPane().add(js, BorderLayout.CENTER);
3440
3441                JButton jBtRandomize = new JButton("Randomize");
3442                jBtRandomize.setMnemonic('R');
3443                jBtRandomize.addActionListener(new ActionListener() {
3444                        public void actionPerformed(ActionEvent ae) {
3445                                tm.randomize();
3446                                dlg.repaint();
3447                        }
3448                });
3449               
3450                JButton jBtOk = new JButton("Ok");
3451                jBtOk.setMnemonic('O');
3452                jBtOk.addActionListener(new ActionListener() {
3453                        public void actionPerformed(ActionEvent ae) {
3454                                tm.setData();
3455                                try {
3456                                        m_BayesNet.setDistribution(m_nCurrentNode, tm.m_fProbs);
3457                                    m_jStatusBar.setText(m_BayesNet.lastActionMsg());
3458                                        updateStatus();
3459                                } catch (Exception e) {
3460                                        e.printStackTrace();
3461                                }
3462                                dlg.setVisible(false);
3463                        }
3464                });
3465                JButton jBtCancel = new JButton("Cancel");
3466                jBtCancel.setMnemonic('C');
3467                jBtCancel.addActionListener(new ActionListener() {
3468                        public void actionPerformed(ActionEvent ae) {
3469                                dlg.setVisible(false);
3470                        }
3471                });
3472                Container c = new Container();
3473                c.setLayout(new GridBagLayout());
3474                c.add(jBtRandomize);
3475                c.add(jBtOk);
3476                c.add(jBtCancel);
3477
3478                dlg.getContentPane().add(c, BorderLayout.SOUTH);
3479                dlg.setVisible(true);
3480        } // editCPT
3481
3482        /**
3483         * Main method. Builds up menus and reads from file if one is specified.
3484         */
3485        public static void main(String[] args) {
3486
3487                weka.core.logging.Logger.log(weka.core.logging.Logger.Level.INFO, "Logging started");
3488           
3489                LookAndFeel.setLookAndFeel();
3490               
3491                JFrame jf = new JFrame("Bayes Network Editor");
3492                final GUI g = new GUI();
3493                JMenuBar menuBar = g.getMenuBar();
3494
3495                if (args.length>0) {
3496                        try {
3497                                g.readBIFFromFile(args[0]);
3498                        } catch (IOException ex) {
3499                                ex.printStackTrace();
3500                        } catch (BIFFormatException bf) {
3501                                bf.printStackTrace();
3502                                System.exit(-1);
3503                        }
3504                }
3505
3506
3507
3508
3509                jf.setJMenuBar(menuBar);               
3510                jf.getContentPane().add(g);
3511                jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
3512                jf.setSize(800, 600);
3513                jf.setVisible(true);
3514                g.m_Selection.updateGUI();
3515                GenericObjectEditor.registerEditors();
3516        } // main
3517       
3518} // end of class
Note: See TracBrowser for help on using the repository browser.