Package edu.brown.gui

Source Code of edu.brown.gui.CatalogViewer

/***************************************************************************
*   Copyright (C) 2008 by H-Store Project                                 *
*   Brown University                                                      *
*   Massachusetts Institute of Technology                                 *
*   Yale University                                                       *
*                                                                         *
*   Permission is hereby granted, free of charge, to any person obtaining *
*   a copy of this software and associated documentation files (the       *
*   "Software"), to deal in the Software without restriction, including   *
*   without limitation the rights to use, copy, modify, merge, publish,   *
*   distribute, sublicense, and/or sell copies of the Software, and to    *
*   permit persons to whom the Software is furnished to do so, subject to *
*   the following conditions:                                             *
*                                                                         *
*   The above copyright notice and this permission notice shall be        *
*   included in all copies or substantial portions of the Software.       *
*                                                                         *
*   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       *
*   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    *
*   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*
*   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR     *
*   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
*   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
*   OTHER DEALINGS IN THE SOFTWARE.                                       *
***************************************************************************/
package edu.brown.gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import javax.swing.BoxLayout;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;

import org.voltdb.catalog.Catalog;
import org.voltdb.catalog.CatalogType;
import org.voltdb.catalog.Cluster;
import org.voltdb.catalog.Database;
import org.voltdb.catalog.Host;
import org.voltdb.catalog.Procedure;
import org.voltdb.catalog.Table;
import org.voltdb.utils.Pair;

import edu.brown.catalog.conflicts.ConflictGraph;
import edu.brown.graphs.GraphvizExport;
import edu.brown.gui.catalog.AttributesNode;
import edu.brown.gui.catalog.CatalogAttributeText;
import edu.brown.gui.catalog.CatalogMapTreeNode;
import edu.brown.gui.catalog.CatalogSummaryUtil;
import edu.brown.gui.catalog.CatalogTreeModel;
import edu.brown.gui.catalog.PlanTreeCatalogNode;
import edu.brown.gui.catalog.ProcedureConflictGraphNode;
import edu.brown.gui.catalog.WrapperNode;
import edu.brown.utils.ArgumentsParser;
import edu.brown.utils.FileUtil;
import edu.brown.utils.IOFileFilter;
import edu.brown.utils.StringUtil;

/**
* Graphical Catalog Viewer Tool
* @author pavlo
*/
public class CatalogViewer extends AbstractViewer {
    private static final long serialVersionUID = -7566054105094378095L;

    protected static final String WINDOW_TITLE = "H-Store Catalog Browser";
   
    // ----------------------------------------------
    // CONTROL OPTIONS
    // ----------------------------------------------   
    protected static final int SEARCH_MIN_LENGTH = 4;
   
    // ----------------------------------------------
    // CATALOG ELEMENTS
    // ----------------------------------------------
    protected Catalog catalog;
    protected File catalog_file_path;
    protected String catalog_path;
   
    protected boolean text_mode = true;
   
    // ----------------------------------------------
    // GUI ELEMENTS
    // ----------------------------------------------
    protected CatalogTreeModel catalogTreeModel;
    protected JTree catalogTree;
    protected JTextField searchField;
    protected JTextArea textInfoTextArea;
    protected JScrollPane textInfoScroller;
    protected JPanel textInfoPanel;
    protected JPanel mainPanel;

    protected CatalogSummaryUtil summaryUtil;
    protected CatalogAttributeText attributeText;
   
    // ----------------------------------------------
    // MENU OPTIONS
    // ----------------------------------------------
    public enum MenuOptions {
        CATALOG_OPEN_FILE,
        CATALOG_OPEN_JAR,
        CATALOG_SAVE,
        CONFLICTGRAPH_EXPORT,
        QUIT,
    };
   
    /**
     *
     * @param catalog
     * @param catalog_path
     */
    public CatalogViewer(ArgumentsParser args) {
        super(args,
              String.format("%s [%s]", WINDOW_TITLE, args.catalog_path),
              DEFAULT_WINDOW_WIDTH,
              DEFAULT_WINDOW_HEIGHT);
        this.catalog = args.catalog;
        this.catalog_file_path = args.catalog_path;
        this.catalog_path = args.catalog_path.getAbsolutePath();
        this.menuHandler = new CatalogViewer.MenuHandler();
        this.init();
    }
   
    /**
     *
     * @param catalog
     * @param catalog_path
     */
    public CatalogViewer(Catalog catalog, String catalog_path) {
        super(new ArgumentsParser(), WINDOW_TITLE);
        this.catalog = catalog;
        this.catalog_path = catalog_path;
        this.menuHandler = new CatalogViewer.MenuHandler();
        this.init();
    }

    public static void show(final Catalog catalog, final String catalog_path) {
        CatalogViewer viewer = new CatalogViewer(catalog, catalog_path);
        viewer.setVisible(true);
    }
   
    /**
     * @param args
     */
    public static void main(final String[] vargs) throws Exception {
        final ArgumentsParser args = ArgumentsParser.load(vargs);
        args.require(ArgumentsParser.PARAM_CATALOG);
       
//        Procedure catalog_proc = args.catalog_db.getProcedures().get("slev");
//        Statement catalog_stmt = catalog_proc.getStatements().get("GetStockCount");
//        String jsonString = Encoder.hexDecodeToString(catalog_stmt.getMs_fullplan());
//        JSONObject jsonObject = new JSONObject(jsonString);
//        System.err.println(jsonObject.toString(2));
       
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                CatalogViewer viewer = new CatalogViewer(args);
                viewer.setVisible(true);
            } // RUN
         });
    }
   
    private void generateCatalogTree(Catalog catalog, String catalog_path) {
        this.catalogTreeModel = new CatalogTreeModel(this.args, catalog, catalog_path);
        this.catalogTree.setModel(this.catalogTreeModel);
        this.catalog = catalog;
        this.catalog_path = catalog_path;
       
        //
        // Expand clusters and databases
        //
        this.catalogTree.expandPath(new TreePath(this.catalogTreeModel.getTablesNode().getPath()));
        this.catalogTree.expandPath(new TreePath(this.catalogTreeModel.getProceduresNode().getPath()));
    }
   
    /**
     *
     */
    protected void viewerInit() {
        this.summaryUtil = new CatalogSummaryUtil(this.catalog);
        this.attributeText = new CatalogAttributeText(this.catalog);
       
        // ----------------------------------------------
        // MENU
        // ----------------------------------------------
        JMenu menu;
        JMenuItem menuItem;
   
        //
        // File Menu
        //
        menu = new JMenu("File");
        menu.getPopupMenu().setLightWeightPopupEnabled(false);
        menu.setMnemonic(KeyEvent.VK_F);
        menu.getAccessibleContext().setAccessibleDescription("File Menu");
        menuBar.add(menu);
   
        menuItem = new JMenuItem("Open Catalog From File");
        menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK));
        menuItem.getAccessibleContext().setAccessibleDescription("Open Catalog From File");
        menuItem.addActionListener(this.menuHandler);
        menuItem.putClientProperty(MenuHandler.MENU_ID, MenuOptions.CATALOG_OPEN_FILE);
        menu.add(menuItem);
       
        menuItem = new JMenuItem("Open Catalog From Jar");
        menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK | ActionEvent.SHIFT_MASK));
        menuItem.getAccessibleContext().setAccessibleDescription("Open Catalog From Project Jar");
        menuItem.addActionListener(this.menuHandler);
        menuItem.putClientProperty(MenuHandler.MENU_ID, MenuOptions.CATALOG_OPEN_JAR);
        menu.add(menuItem);
        
        menu.addSeparator();
       
        menuItem = new JMenuItem("Export ConflictGraph");
        // menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK | ActionEvent.SHIFT_MASK));
        menuItem.getAccessibleContext().setAccessibleDescription("Export ConflictGraph to a Graphviz Dot File");
        menuItem.addActionListener(this.menuHandler);
        menuItem.putClientProperty(MenuHandler.MENU_ID, MenuOptions.CONFLICTGRAPH_EXPORT);
        menu.add(menuItem);
        
        menu.addSeparator();
         
        menuItem = new JMenuItem("Quit", KeyEvent.VK_Q);
        menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, ActionEvent.CTRL_MASK));
        menuItem.getAccessibleContext().setAccessibleDescription("Quit Program");
        menuItem.addActionListener(this.menuHandler);
        menuItem.putClientProperty(MenuHandler.MENU_ID, MenuOptions.QUIT);
        menu.add(menuItem);
       
        // ----------------------------------------------
        // CATALOG TREE PANEL
        // ----------------------------------------------
        this.catalogTree = new JTree();
        this.catalogTree.setEditable(false);
        this.catalogTree.setCellRenderer(new CatalogViewer.CatalogTreeRenderer());
        this.catalogTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
        this.catalogTree.addTreeSelectionListener(new CatalogTreeSeleciontListener());
        this.generateCatalogTree(this.catalog, this.catalog_file_path.getName());

        // ----------------------------------------------
        // TEXT INFORMATION PANEL
        // ----------------------------------------------
        this.textInfoPanel = new JPanel();
        this.textInfoPanel.setLayout(new BorderLayout());
        this.textInfoTextArea = new JTextArea();
        this.textInfoTextArea.setEditable(false);
        this.textInfoTextArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
        this.textInfoTextArea.setText(StringUtil.header("CATALOG SUMMARY", "-", 50) + // HACK
                                      "\n\n" + this.summaryUtil.getSummaryText());
        this.textInfoTextArea.addFocusListener(new FocusListener() {
            @Override
            public void focusLost(FocusEvent e) {
                // TODO Auto-generated method stub
            }
           
            @Override
            public void focusGained(FocusEvent e) {
                CatalogViewer.this.scrollTextInfoToTop();
            }
        });
        this.textInfoScroller = new JScrollPane(this.textInfoTextArea);
        this.textInfoPanel.add(this.textInfoScroller, BorderLayout.CENTER);
        this.mainPanel = new JPanel(new BorderLayout());
        this.mainPanel.add(textInfoPanel, BorderLayout.CENTER);
       
        // ----------------------------------------------
        // SEARCH TOOLBAR
        // ----------------------------------------------
        JPanel searchPanel = new JPanel();
        searchPanel.setLayout(new BorderLayout());
        JPanel innerSearchPanel = new JPanel();
        innerSearchPanel.setLayout(new BoxLayout(innerSearchPanel, BoxLayout.X_AXIS));
        innerSearchPanel.add(new JLabel("Search: "));
        this.searchField = new JTextField(30);
        innerSearchPanel.add(this.searchField);
        searchPanel.add(innerSearchPanel, BorderLayout.EAST);
       
        this.searchField.addKeyListener(new KeyListener() {
            private String last = null;
           
            @Override
            public void keyReleased(KeyEvent e) {
                String value = CatalogViewer.this.searchField.getText().toLowerCase().trim();
                if (!value.isEmpty() && (this.last == null || !this.last.equals(value))) {
                    CatalogViewer.this.search(value);
                }
                this.last = value;
            }
            @Override
            public void keyTyped(KeyEvent e) {
                // Do nothing...
            }
            @Override
            public void keyPressed(KeyEvent e) {
                // Do nothing...
            }
        });
       
        // Putting it all together
        JScrollPane scrollPane = new JScrollPane(this.catalogTree);
        JPanel topPanel = new JPanel();
        topPanel.setLayout(new BorderLayout());
        topPanel.add(searchPanel, BorderLayout.NORTH);
        topPanel.add(scrollPane, BorderLayout.CENTER);
       
        JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, topPanel, this.mainPanel);
        splitPane.setDividerLocation(400);

        this.add(splitPane, BorderLayout.CENTER);
    }
   
    protected void replaceMainPanel(JPanel newPanel) {
        this.mainPanel.remove(0);
        this.mainPanel.add(newPanel, BorderLayout.CENTER);
        this.mainPanel.validate();
        this.mainPanel.repaint();
    }
   
    protected void search(String value) {
        LOG.debug("Searching based on keyword '" + value + "'...");
       
        Set<DefaultMutableTreeNode> found = new HashSet<DefaultMutableTreeNode>();

        Integer guid = null;

        // If it starts with "guid=", then that's a PlanColumn!
        if (value.startsWith("guid=")) {
            try {
                guid = Integer.valueOf(value.split("guid=")[1]);
                if (this.catalogTreeModel.getPlanNodeGuidNodeXref().containsKey(guid)) {
                    found.addAll(this.catalogTreeModel.getPlanNodeGuidNodeXref().get(guid));
                } else {
                    guid = null;
                }
            } catch (Exception ex) {
                // Ignore...
            }
           
        } else {
           
            // Check if it's a digit, which means that they are searching by Catalog guid
            try {
                guid = Integer.parseInt(value);
                if (this.catalogTreeModel.getGuidNodeXref().containsKey(guid)) {
                    found.add(this.catalogTreeModel.getGuidNodeXref().get(guid));
                } else {
                    guid = null;
                }
            } catch (Exception ex) {
                // Ignore...
            }
        }
       
        // Otherwise search by name...
        if (guid == null && value.length() >= SEARCH_MIN_LENGTH) {
            LOG.debug("Searching for matching name '" + value + "'");
            for (String name : this.catalogTreeModel.getNameNodeXref().keySet()) {
                if (name.indexOf(value) != -1) {
                    found.addAll(this.catalogTreeModel.getNameNodeXref().get(name));
                }
            } // FOR
        }
       
        // Display found matches
        if (!found.isEmpty()) {
            this.highlight(found);
            this.searchField.requestFocus();
        }
    }
   
    protected void highlight(Collection<DefaultMutableTreeNode> nodes) {
        // Collapse everything and then show the paths to each node
        for (int ctr = this.catalogTree.getRowCount(); ctr >= 0; ctr--) {
            if (this.catalogTree.isExpanded(ctr)) {
                this.catalogTree.collapseRow(ctr);             
            }
        } // FOR
        this.catalogTree.getSelectionModel().clearSelection();
       
        for (DefaultMutableTreeNode node : nodes) {
            TreePath path = new TreePath(node.getPath());
            this.catalogTree.setSelectionPath(path);
            this.catalogTree.expandPath(path);
        } // FOR
    }
   
    /**
     * Scroll the attributes pane to the top
     */
    protected void scrollTextInfoToTop() {
        JScrollBar verticalScrollBar = this.textInfoScroller.getVerticalScrollBar();
        JScrollBar horizontalScrollBar = this.textInfoScroller.getHorizontalScrollBar();
        verticalScrollBar.setValue(verticalScrollBar.getMinimum());
        horizontalScrollBar.setValue(horizontalScrollBar.getMinimum());
        // System.err.println("VERTICAL=" + verticalScrollBar.getValue() + ", HORIZONTAL=" + horizontalScrollBar.getValue());
    }
   
    public class CatalogTreeRenderer extends DefaultTreeCellRenderer {
        private static final long serialVersionUID = 1L;

        /**
         *
         */
        @Override
        public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
            super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
            if (value instanceof DefaultMutableTreeNode) {
                DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
                Object obj = node.getUserObject();
                if (obj instanceof WrapperNode) {
                    CatalogType catalog_obj = ((WrapperNode)node.getUserObject()).getCatalogType();
                    this.setFont(this.getFont().deriveFont(Font.BOLD));
                   
                    //
                    // Cluster
                    //
                    if (catalog_obj instanceof Cluster) {
                        this.setIcon(UIManager.getIcon("FileView.computerIcon"));
                    //
                    // Database
                    //
                    } else if (catalog_obj instanceof Database) {
                        this.setIcon(UIManager.getIcon("FileView.hardDriveIcon"));
                    }
                }
                else if (obj instanceof ProcedureConflictGraphNode) {
                    this.setForeground(new Color(0, 0, 200));
                    this.setFont(this.getFont().deriveFont(Font.BOLD | Font.ITALIC));
                    this.setIcon(UIManager.getIcon("FileChooser.listViewIcon"));
                }
                else {
                    this.setFont(this.getFont().deriveFont(Font.PLAIN));
                }
            }
            if (CatalogViewer.this.catalogTreeModel != null) {
                //
                // Root Node
                //
                Object root_node = CatalogViewer.this.catalogTreeModel.getRoot();
                if (root_node != null && root_node == value) {
                    this.setIcon(UIManager.getIcon("FileView.floppyDriveIcon"));
                    this.setFont(this.getFont().deriveFont(Font.BOLD));
                }
            }
            /*
            if (leaf) {
                this.setIcon(UIManager.getIcon("FileChooser.detailsViewIcon"));
            }
            */
            return (this);
        }
    } // END CLASS
   
   
    protected String exportConflictGraph() {
        IOFileFilter filter = new IOFileFilter("Graphviz Dot File", "dot");
        File defaultFile = new File(String.format("%s-conflict.dot", args.catalogContext.database.getProject()));
        String path = null;
        try {
            path = showSaveDialog("Export ConflictGraph", ".", filter, defaultFile);
            if (path != null) {
                ConflictGraph graph = this.catalogTreeModel.getProcedureConflictGraphNode().getConflictGraph();
                assert(graph != null) : "Unexpected null ConflictGraph";
                String serialized = GraphvizExport.export(graph, args.catalogContext.database.getProject());
                FileUtil.writeStringToFile(new File(path), serialized);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            showErrorDialog("Failed to export ConflictGraph file", ex.getMessage());
        }
        return (path);
    }
   
    private class CatalogTreeSeleciontListener implements TreeSelectionListener {
       
        public void valueChanged(TreeSelectionEvent e) {
            DefaultMutableTreeNode node = (DefaultMutableTreeNode)CatalogViewer.this.catalogTree.getLastSelectedPathComponent();
            if (node == null) return;

            Object user_obj = node.getUserObject();
            String new_header = null;
            String new_text = null;
            boolean text_mode = true;
            if (user_obj instanceof WrapperNode) {
                CatalogType catalog_obj  = ((WrapperNode)user_obj).getCatalogType();
                new_text = CatalogViewer.this.attributeText.getAttributesText(catalog_obj);
            }
            else if (user_obj instanceof AttributesNode) {
                AttributesNode wrapper = (AttributesNode)user_obj;
                new_text = wrapper.getAttributes();
            }
            else if (user_obj instanceof ProcedureConflictGraphNode) {
                ProcedureConflictGraphNode wrapper = (ProcedureConflictGraphNode)user_obj;
                CatalogViewer.this.replaceMainPanel(wrapper.getVisualization());
                text_mode = false;
            }
            else if (user_obj instanceof PlanTreeCatalogNode) {
                final PlanTreeCatalogNode wrapper = (PlanTreeCatalogNode)user_obj;
                text_mode = false;
               
                CatalogViewer.this.replaceMainPanel(wrapper.getPanel());
               
                if (SwingUtilities.isEventDispatchThread() == false) {
                    SwingUtilities.invokeLater(new Runnable() {
                        public void run() {
                            wrapper.centerOnRoot();
                        }
                    });
                } else {
                    wrapper.centerOnRoot();
                }
               
            }
            // SUMMARY NODES
            else if (node instanceof CatalogMapTreeNode) {
                Class<? extends CatalogType> catalogType = ((CatalogMapTreeNode)node).getCatalogType();
                if (catalogType.equals(Procedure.class)) {
                    new_text = StringUtil.formatMaps(summaryUtil.getProceduresInfo(true));
                }
                else if (catalogType.equals(Table.class)) {
                    new_text = StringUtil.formatMaps(summaryUtil.getTablesInfo(true));
                }
                else if (catalogType.equals(Host.class)) {
                    new_text = StringUtil.formatMaps(summaryUtil.getHostsInfo(true));
                }
                if (new_text != null) {
                    new_header = catalogType.getSimpleName() + "s Summary";
                }
               
               
            }
            // EVERYTHING ELSE
            if (text_mode && new_text == null) {
                new_header = "Catalog Summary";
                new_text = CatalogViewer.this.summaryUtil.getSummaryText();
            }

            // Text Mode
            if (text_mode) {
                if (CatalogViewer.this.text_mode == false) {
                    CatalogViewer.this.replaceMainPanel(CatalogViewer.this.textInfoPanel);
                }
                if (new_header != null) {
                    new_text = StringUtil.header(new_header.toUpperCase(), "-", 50) +
                               "\n\n" + new_text;
                }
                CatalogViewer.this.textInfoTextArea.setText(new_text);
               
                // Scroll to top
                CatalogViewer.this.textInfoTextArea.grabFocus();
            }
           
            CatalogViewer.this.text_mode = text_mode;
        }
    } // END CLASS
   
    protected class MenuHandler extends AbstractMenuHandler {
        /**
         *
         */
        @Override
        public void actionPerformed(ActionEvent e) {
            JMenuItem source = (JMenuItem)(e.getSource());
            //
            // Process the event
            //
            MenuOptions opt = MenuOptions.valueOf(source.getClientProperty(MENU_ID).toString());
            switch (opt) {
                // --------------------------------------------------------
                // OPEN CATALOG FILE
                // --------------------------------------------------------
                case CATALOG_OPEN_FILE: {
                    Pair<Catalog, String> result = openCatalogFile();
                    if (result != null) {
                        generateCatalogTree(result.getFirst(), result.getSecond());
                    }
                    break;
                }
                // --------------------------------------------------------
                // OPEN CATALOG JAR
                // --------------------------------------------------------
                case CATALOG_OPEN_JAR: {
                    Pair<Catalog, String> result = openCatalogJar();
                    if (result != null) {
                        generateCatalogTree(result.getFirst(), result.getSecond());
                    }
                    break;
                }
                // --------------------------------------------------------
                // EXPORT CONFLICT GRAPH
                // --------------------------------------------------------
                case CONFLICTGRAPH_EXPORT: {
                    String path = exportConflictGraph();
                    if (path != null) {
                        LOG.info("Exported ConflictGraph to '" + path + "'");
                    }
                    break;
                }
               
                // --------------------------------------------------------
                // QUIT
                // --------------------------------------------------------
                case QUIT: {
                    quit();
                    break;
                }
                // --------------------------------------------------------
                // UNKNOWN
                // --------------------------------------------------------
                default:
                    System.err.println("Invalid Menu Action: " + source.getName());
            } // SWITCH
        }
    } // END CLASS
}
TOP

Related Classes of edu.brown.gui.CatalogViewer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.