alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun
 * Microsystems, Inc. All Rights Reserved.
 */
package org.netbeans.modules.refactoring.ui;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import javax.jmi.reflect.RefObject;
import javax.swing.*;
import javax.swing.text.Position;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import org.netbeans.jmi.javamodel.*;
import org.netbeans.modules.javacore.internalapi.InvalidationListener;
import org.netbeans.modules.javacore.internalapi.JavaMetamodel;
import org.netbeans.modules.javacore.internalapi.ProgressEvent;
import org.netbeans.modules.javacore.internalapi.ProgressListener;
import org.netbeans.modules.refactoring.RefactoringSupportImpl;
import org.netbeans.modules.refactoring.api.RefactoringElement;
import org.netbeans.modules.refactoring.api.RefactoringSupport;
import org.netbeans.modules.refactoring.api.ui.ParametersPanel;
import org.netbeans.modules.refactoring.api.ui.RefactoringUI;
import org.openide.ErrorManager;
import org.openide.explorer.ExplorerPanel;
import org.openide.text.CloneableEditorSupport;
import org.openide.text.PositionBounds;
import org.openide.util.NbBundle;
import org.openide.util.RequestProcessor;
import org.openide.util.Utilities;
import org.openide.windows.Mode;
import org.openide.windows.WindowManager;
import org.openide.windows.Workspace;



/**
 * Panel for showing proposed changes (refactoring elements) of any refactoring.
 *
 * @author  Pavel Flaska, Martin Matula
 */
public class RefactoringPanel extends JPanel implements InvalidationListener, ProgressListener {
    
    // PRIVATE FIELDS
    /* tree contains elements which will be changed by refactoring action */
    private transient JTree tree = null;
    /* toolbar button causing refresh of the data */
    private transient JButton refreshButton = null;
    /* button lying in the toolbar allows expansion of all nodes in a tree */
    private transient JToggleButton expandButton = null;
    /* progress bar */
    private transient JProgressBar progressBar = null;

    private transient JButton refactorButton = null;
    private transient JButton cancelButton = null;
    private transient ButtonL buttonListener = null;

    private final RefactoringUI ui;
    private final boolean isQuery;
    
    private transient boolean isVisible = false;
    private transient Collection elements = null;
    private transient ParametersPanel parametersPanel = null;
    private transient JScrollPane scrollPane = null; 
    private transient JPanel southPanel;
    
    private static final int MAX_ROWS = 50;
    
    public RefactoringPanel(RefactoringUI ui) {
        this.ui = ui;
        this.isQuery = ui.isQuery();
        initialize();
        refresh();
    }
    
    public static void checkEventThread() {
        if (!SwingUtilities.isEventDispatchThread()) {
            ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, new IllegalStateException("This must happen in event thread!")); //NOI18N
        }
    }
    
    /* initializes all the ui */
    private void initialize() {
        checkEventThread();
        setLayout(new BorderLayout());
        // add panel with buttons
        JButton[] buttons = getButtons();
        //if (buttons.length != 0) {
            // there will be at least one button on panel
            southPanel = new JPanel(new GridBagLayout());
            for (int i = 0; i < buttons.length; i++) {
                GridBagConstraints c = new GridBagConstraints();
                c.gridy = 0;
                c.insets = new Insets(5, 5, 5, 0);
                southPanel.add(buttons[i], c);
            }
            JPanel pp = new JPanel(new BorderLayout());
            GridBagConstraints c = new GridBagConstraints();
            c.gridy = 0;
            c.insets = new Insets(5, 5, 5, 5);
            c.weightx = 1;
            c.fill = c.HORIZONTAL;
            southPanel.add(pp, c);
            
            progressBar = new JProgressBar();
            progressBar.setVisible(false);
            pp.add(progressBar, BorderLayout.CENTER);
            
            if (!isQuery) {
                add(southPanel, BorderLayout.SOUTH);
            }
        //}
        // put the toolbar to the panel. If the getToolBar() returns null,
        // suppose the toolbar does not exist.
        JToolBar toolBar = getToolBar();
        if (toolBar != null)
            add(toolBar, BorderLayout.WEST);
    }

    /**
     * Returns the toolbar. In this default implementation, toolbar is
     * oriented vertically in the west and contains 'expand tree' toggle
     * button and refresh button.
     * Override this method and return null if you do not want toolbar
     * in your panel.
     * 
     * @return  toolBar with actions for refactoring panel
     */
    private JToolBar getToolBar() {
        checkEventThread();
        refreshButton = new JButton(
            new ImageIcon(Utilities.loadImage(
            "org/netbeans/modules/refactoring/resources/refresh.gif")) // NOI18N
        );
        Dimension dim = new Dimension(24, 24);
        refreshButton.setMaximumSize(dim);
        refreshButton.setMinimumSize(dim);
        refreshButton.setPreferredSize(dim);
        refreshButton.setToolTipText(
            NbBundle.getMessage(RefactoringPanel.class, "HINT_refresh") // NOI18N
        );
        refreshButton.addActionListener(getButtonListener());
        // expand button settings
        expandButton = new JToggleButton(
            new ImageIcon(Utilities.loadImage(
            "org/netbeans/modules/refactoring/resources/expandTree.gif")) // NOI18N
        );
        expandButton.setMaximumSize(dim);
        expandButton.setMinimumSize(dim);
        expandButton.setPreferredSize(dim);
        expandButton.setSelected(true);
        expandButton.setToolTipText(
            NbBundle.getMessage(RefactoringPanel.class, "HINT_expandAll") // NOI18N
        );
        expandButton.addActionListener(getButtonListener());
        // create toolbar
        JToolBar toolBar = new JToolBar(JToolBar.VERTICAL);
        toolBar.setFloatable(false); 
        toolBar.add(refreshButton);
        toolBar.add(expandButton);
        
        return toolBar;
    }
    
    /**
     * Returns array of available buttons. Initially, it returns only
     * basic "do refactoring/cancel refactoring" button. Override this method, 
     * if you want to provide any other buttons with different action to be 
     * performed.
     *
     * @return  array of avasilable buttons.
     */
    private JButton[] getButtons() {
        checkEventThread();
        if (isQuery) {
            refactorButton = null;
//            cancelButton = new JButton(NbBundle.getMessage(RefactoringPanel.class, "LBL_CloseRefactor")); // NOI18N
//            cancelButton.setToolTipText(NbBundle.getMessage(RefactoringPanel.class, "HINT_CloseRefactor")); // NOI18N
//            cancelButton.addActionListener(getButtonListener());
//            return new JButton[] {cancelButton};
              return new JButton[] {};
        } else {
            refactorButton = new JButton(NbBundle.getMessage(RefactoringPanel.class, "LBL_DoRefactor")); // NOI18N
            refactorButton.setToolTipText(NbBundle.getMessage(RefactoringPanel.class, "HINT_DoRefactor")); // NOI18N
            refactorButton.setMnemonic(NbBundle.getMessage(RefactoringPanel.class, "MNEM_DoRefactor").charAt(0));
            refactorButton.addActionListener(getButtonListener());
//            cancelButton = new JButton(NbBundle.getMessage(RefactoringPanel.class, "LBL_CancelRefactor")); // NOI18N
//            cancelButton.setToolTipText(NbBundle.getMessage(RefactoringPanel.class, "HINT_CancelRefactor")); // NOI18N
//            cancelButton.addActionListener(getButtonListener());
//            return new JButton[] {refactorButton, cancelButton};
              return new JButton[] {refactorButton};
        }
    }

    private CheckNode createNode(Object representedObject, HashMap nodes, CheckNode root) {
        //checkEventThread();
        CheckNode node = (CheckNode) nodes.get(representedObject);
        if (node != null) {
            return node;
        }
        
        Object parent = null;
        String resourceID = null;
        String displayName = null;
        
        boolean cannotEnable = false;

        if (representedObject instanceof RefactoringElement) {
            RefactoringElement re = (RefactoringElement) representedObject;
            displayName = re.getDisplayText();
            if (!isQuery && re.getStatus() == RefactoringElement.GUARDED) {
                displayName = displayName + " [" + // NOI18N
                    NbBundle.getMessage(RefactoringPanel.class, "LBL_InGuardedBlock") + "]";
                cannotEnable = true;
            }
            displayName = normalize(displayName);
            
            parent = re.getJavaElement();
            resourceID = null;
        } else if (representedObject instanceof NamedElement) {
            if (representedObject instanceof Feature) {
                parent = ((NamedElement) representedObject).refImmediateComposite();
                displayName = ((NamedElement) representedObject).getName();
                if (representedObject instanceof JavaClass) {
                    resourceID = IconStrings.CLASS;
                } else if (representedObject instanceof Field) {
                    resourceID = IconStrings.FIELD_PUBLIC;
                } else if (representedObject instanceof Method) {
                    resourceID = IconStrings.METHOD_PUBLIC;
                } else if (representedObject instanceof Constructor) {
                    resourceID = IconStrings.CONSTRUCTOR_PUBLIC;
                    displayName = ((JavaClass)((Constructor) representedObject).getDeclaringClass()).getName();
                } else if (representedObject instanceof Initializer) {
                    resourceID = IconStrings.CONSTRUCTOR_PUBLIC;
                    displayName = "<initializer>"; // NOI18N
                }
            } else if (representedObject instanceof JavaPackage) {
                resourceID = IconStrings.JAVA_PACKAGE;
                displayName = ((JavaPackage) representedObject).getName();
                if ("".equals(displayName))
                    displayName = NbBundle.getMessage(RefactoringPanel.class, "LBL_DefaultPackage");
                parent = null;
            } else if (representedObject instanceof ClassDefinition) {
                displayName = "<anonymous class>"; // NOI18N
                parent = representedObject;
                do {
                    parent = ((RefObject)parent).refImmediateComposite();
                } while (parent!=null && !(parent instanceof Feature));
            } else if (representedObject instanceof Resource) {
                resourceID = IconStrings.SOURCE_OPTIONS;
                String relativeName = ((Resource) representedObject).getName();
                displayName = relativeName.substring(relativeName.lastIndexOf('/') + 1);
                parent = ((Resource) representedObject).refImmediateComposite();
            }
        }

        node = new CheckNode(representedObject, displayName, resourceID == null ? null : new ImageIcon(Utilities.loadImage(resourceID + ".gif")));
        if (cannotEnable)
            node.setDisabled();
        //if (isQuery)
           // node.getPosition();
        CheckNode parentNode = parent == null ? root : createNode(parent, nodes, root);
        parentNode.add(node);
        nodes.put(representedObject, node);

        return node;
    }
    
    /**
     * Overrides default ExplorerPanel behaviour. Does nothing now.
     */
    protected void updateTitle() {
    }
    
    /**
     * Method is responsible for making changes in sources.
     */
    private void refactor() {
        checkEventThread();
        disableComponents(RefactoringPanel.this);
        RequestProcessor.getDefault().post(new Runnable() {
            public void run() {
                RefactoringSupport.getDefault().doRefactoring(elements, ui.getName(), RefactoringPanel.this);
                JavaMetamodel.getUndoManager().saveAll();
                SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                        progressBar.setValue(progressBar.getMaximum());
                        RefactoringPanel.this.close();
                    }
                });
            }
        });
    }

    /**
     * Cancel refactor action. This default implementation is closing window
     * only. It can return result state. In this implementation it returns
     * everytime 0.
     *
     * @return  result of cancel operation. Zero represent successful cancel.
     */
    private int cancel() {
        checkEventThread();
        this.close();
        return 0;
    }
    
    void close() {
        if (isQuery) {
            RefactoringPanelContainer.getUsagesComponent().removePanel(this);
        } else {
            RefactoringPanelContainer.getRefactoringComponent().removePanel(this);
        }
        closeNotify();
    }
    
    
    /*
     * Initializes button listener. The subclasses must not need this listener.
     * This is the reason of lazy initialization.
     */
    private ButtonL getButtonListener() {
        if (buttonListener == null)
            buttonListener = new ButtonL();
        
        return buttonListener;
    }

    RequestProcessor rp = new RequestProcessor();

    /* expandAll nodes in the tree */
    public void expandAll() { 
        checkEventThread();
        final Cursor old = getCursor();
        expandButton.setEnabled(false);
        scrollPane.getViewport().remove(tree);
        setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
        rp.post(new Runnable() {
            public void run() {
                int row = 0;
                while (row < tree.getRowCount()) {
                    tree.expandRow(row);
                    row++;
                }
                SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                        scrollPane.setViewportView(tree);
                        setCursor(old);
                        expandButton.setEnabled(true);
                    }
                });
            }});
    } 

    /* collapseAll nodes in the tree */
    public void collapseAll() {
        checkEventThread();
        expandButton.setEnabled(false);
        final Cursor old = getCursor();
        scrollPane.getViewport().remove(tree);
        setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
        rp.post(new Runnable() {
            public void run() {
                int row = tree.getRowCount() - 1;
                while (row > 0) {
                    tree.collapseRow(row);
                    row--;
                }
                SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                        scrollPane.setViewportView(tree);
                        setCursor(old);
                        expandButton.setEnabled(true);
                    }
                });
            }});
    }
    
    public void invalidateObject() {
        if (isQuery) {
            return;
        }
        Runnable invalidate = new Runnable() {
            public void run() {
                setRefactoringEnabled(false);
            }
        };
        if (SwingUtilities.isEventDispatchThread()) {
            invalidate.run();
        } else {
            SwingUtilities.invokeLater(invalidate);
        }
    }
    
    private void refresh() {
        checkEventThread();
        JavaMetamodel.getUndoManager().saveAll();

        // create parameters panel for refactoring
        if (parametersPanel == null) {
            parametersPanel = new ParametersPanel(ui);
        }
        // show parameters dialog
        Collection tempElements = parametersPanel.showDialog();
        // if no elements were returned, action was either cancelled or preview
        // was skipped -> finish
        if (tempElements == null) {
            return;
        }
        
        elements = tempElements;

        final String description = ui.getDescription();
        setName(ui.getName());
       
        RequestProcessor.getDefault().post(new Runnable() {
            public void run() {
                HashSet editorSupports = new HashSet();

                int errorsNum = 0;
                if (!isQuery) {
                    for (Iterator iter = elements.iterator(); iter.hasNext(); ) {
                        RefactoringElement elem = (RefactoringElement) iter.next();
                        if (elem.getStatus() == RefactoringElement.GUARDED) {
                            errorsNum++;
                        }
                    }
                }
                int occurencesNum = elements.size();
                StringBuffer errorsDesc = new StringBuffer();
                errorsDesc.append(" [" + occurencesNum); // NOI18N
                errorsDesc.append(' ');
                errorsDesc.append(occurencesNum == 1 ? 
                    NbBundle.getMessage(RefactoringPanel.class, "LBL_Occurence") :
                    NbBundle.getMessage(RefactoringPanel.class, "LBL_Occurences")
                );
                if (errorsNum > 0) {
                    errorsDesc.append(',');
                    errorsDesc.append(' ');
                    errorsDesc.append("" + errorsNum); // NOI18N
                    errorsDesc.append(' ');
                    errorsDesc.append(errorsNum == 1 ? 
                        NbBundle.getMessage(RefactoringPanel.class, "LBL_Error") :
                        NbBundle.getMessage(RefactoringPanel.class, "LBL_Errors")
                    );
                    errorsDesc.append(""); // NOI18N
                }
                errorsDesc.append(']');
                final CheckNode root = new CheckNode(null, description + errorsDesc.toString(), new ImageIcon(Utilities.loadImage("org/netbeans/modules/refactoring/resources/" + (isQuery ? "query.gif" : "refactoring.gif"))));
                HashMap nodes = new HashMap();
                
                start(new ProgressEvent(this, ProgressEvent.START, 0, elements.size()/10));
                int i=0;
                JavaMetamodel.getDefaultRepository().beginTrans(false);
                try {
                    for (Iterator it = elements.iterator(); it.hasNext();i++) {
                        RefactoringElement e = (RefactoringElement) it.next();
                        createNode(e, nodes, root);

                        PositionBounds pb = e.getPosition();
                        if (pb != null) {
                            CloneableEditorSupport ces = pb.getBegin().getCloneableEditorSupport();
                            editorSupports.add(ces);
                        }

                        if (i % 10 == 0) 
                            step(new ProgressEvent(this,ProgressEvent.STEP));
                    }
                } finally {
                    JavaMetamodel.getDefaultRepository().endTrans();
                }
                JavaMetamodel.getUndoManager().watch(editorSupports, RefactoringPanel.this);
                stop(new ProgressEvent(this, ProgressEvent.STOP));
                
                SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                        if (tree == null) {
                            // add panel with appropriate content
                            tree = new JTree(root) {
                                 public TreePath getNextMatch(String prefix, int startingRow, Position.Bias bias) {
                                     try {
                                         return super.getNextMatch(prefix,startingRow, bias);
                                     } catch (NullPointerException e) {
                                         //Work around for 43112 
                                     }
                                     return null;
                                 }
                            };
                            tree.setCellRenderer(new CheckRenderer(isQuery));
                            CheckNodeListener l = new CheckNodeListener(isQuery);
                            tree.addMouseListener(l);
                            tree.addKeyListener(l);
                            tree.setToggleClickCount(0);
                            scrollPane = new JScrollPane(tree);
                            RefactoringPanel.this.add(scrollPane, BorderLayout.CENTER);
                        } else {
                            tree.setModel(new DefaultTreeModel(root));
                        }
                        
                        tree.setRowHeight((int) ((CheckRenderer) tree.getCellRenderer()).getPreferredSize().getHeight());
                        
                        if (elements.size() < MAX_ROWS)
                            expandAll();
                        else
                            expandButton.setSelected(false);

                        setRefactoringEnabled(true);
                    }
                });
            }
        });
        
        if (!isVisible) {
            // dock it into output window area and display
            RefactoringPanelContainer cont = isQuery ? RefactoringPanelContainer.getUsagesComponent() : RefactoringPanelContainer.getRefactoringComponent();
            cont.requestActive();
            cont.addPanel(this);
            isVisible = true;
        }
        setRefactoringEnabled(false);
    }
    
    void setRefactoringEnabled(boolean enabled) {
        checkEventThread();
        if (tree != null) {
            if (!enabled) {
                CheckNode c = (CheckNode) tree.getModel().getRoot();
                c.setNeedsRefresh();
                tree.setModel(new DefaultTreeModel(c, false));
            }
//            tree.validate();
            tree.setEnabled(enabled);
            if (refactorButton != null) {
                refactorButton.setEnabled(enabled);
            }
        }
    }

    // disables all components in a given container
    private static void disableComponents(Container c) {
        checkEventThread();
        Component children[] = c.getComponents();
        for (int i = 0; i < children.length; i++) {
            if (children[i].isEnabled()) {
                children[i].setEnabled(false);
            }
            if (children[i] instanceof Container) {
                disableComponents((Container) children[i]);
            }
        }
    }
    
    ////////////////////////////////////////////////////////////////////////////
    // INNER CLASSES
    ////////////////////////////////////////////////////////////////////////////
    private class ButtonL implements ActionListener {
        public void actionPerformed(ActionEvent event) {
            Object o = event.getSource();
            // Cancel button pressed, remove refactoring panel
            if (o == cancelButton) {
                cancel();
            } else if (o == refactorButton) {
                refactor();
            }
            // expandAll button selected/deselected
            else if (o == expandButton && tree != null) {
                if (expandButton.isSelected())
                    expandAll();
                else
                    collapseAll();
            } else if (o == refreshButton) {
                refresh();
            }
        }
    } // end ButtonL
    ////////////////////////////////////////////////////////////////////////////

    private static String normalize(String input) {
        int size = input.length();
        char[] c = new char[size];
        input.getChars(0, size, c, 0);
        boolean wb = false;
        int pos = 0;
        char[] nc = new char[size];
        
        for (int i = 0; i < size; i++) {
            if (Character.isWhitespace(c[i])) {
                if (!wb) {
                    nc[pos++] = ' ';
                    wb = true;
                }
            }
            else {
                nc[pos++] = c[i];
                wb = false;
            }
        }
        return new String(nc, 0, pos);
    }

    /** Processes returned problems from refactoring operations and notifies
     * user (in case of non-fatal problems gives user a chance to continue or cancel).
     * @param problem Problems returned from a refactoring operation.
     * @return true if no fatal problems were found and user decided
     * to continue in case of non-fatal problems; false if there was at
     * least one fatal problem or at least one non-fatal problem in response to which
     * user decided to cancel the operation.
     */
    /* public static boolean confirmProblems(Problem problem) {
        while (problem != null) {
            int result;
            if (problem.isFatal()) {
                JOptionPane.showMessageDialog(null, problem.getMessage(), NbBundle.getMessage(ParametersPanel.class, "LBL_Error"), JOptionPane.ERROR_MESSAGE);
                return false;
            } else {
                if (JOptionPane.showConfirmDialog(
                    null, 
                    problem.getMessage() + ' ' + NbBundle.getMessage(ParametersPanel.class, "QST_Continue"),
                    NbBundle.getMessage(ParametersPanel.class, "LBL_Warning"),
                    JOptionPane.YES_NO_OPTION,
                    JOptionPane.WARNING_MESSAGE
                ) != JOptionPane.YES_OPTION) {
                    return false;
                }
            }
            problem = problem.getNext();
        }
        return true;
    } */
    
    protected void closeNotify() {
        ((RefactoringSupportImpl) RefactoringSupport.getDefault()).stopWatching(this);
        //super.closeNotify();
    }
    
    public void start(final ProgressEvent event) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                if (isQuery) {
                    add(southPanel, BorderLayout.SOUTH); 
                }
                progressBar.setMaximum(event.getCount() + 1);
                progressBar.setValue(0);
                progressBar.setVisible(true);
            }
        });
    }
    
    public void step(ProgressEvent event) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                progressBar.setValue(progressBar.getValue() + 1);
            }
        });
    }
    
    public void stop(ProgressEvent event) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                progressBar.setVisible(false);
                if (isQuery) {
                    remove(southPanel);
                }
            }
        });
    }
} // end Refactor Panel
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.