0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041: package org.netbeans.modules.refactoring.spi.impl;
0042:
0043: import java.awt.*;
0044: import java.awt.event.ActionEvent;
0045: import java.awt.event.ActionListener;
0046: import java.lang.ref.WeakReference;
0047: import java.util.*;
0048: import java.util.Collection;
0049: import javax.swing.*;
0050: import javax.swing.ImageIcon;
0051: import javax.swing.border.EmptyBorder;
0052: import javax.swing.text.Position;
0053: import javax.swing.tree.DefaultTreeModel;
0054: import javax.swing.tree.TreePath;
0055: import org.netbeans.api.progress.ProgressHandle;
0056: import org.netbeans.api.progress.ProgressHandleFactory;
0057: import org.netbeans.api.project.*;
0058: import org.netbeans.modules.refactoring.api.*;
0059: import org.netbeans.modules.refactoring.api.impl.APIAccessor;
0060: import org.netbeans.modules.refactoring.spi.RefactoringElementImplementation;
0061: import org.netbeans.modules.refactoring.spi.ui.RefactoringCustomUI;
0062: import org.netbeans.modules.refactoring.spi.ui.RefactoringUI;
0063: import org.netbeans.modules.refactoring.spi.ui.TreeElement;
0064: import org.netbeans.modules.refactoring.spi.ui.TreeElementFactory;
0065: import org.netbeans.modules.refactoring.spi.ui.TreeElementFactoryImplementation;
0066: import org.netbeans.modules.refactoring.spi.ui.UI;
0067: import org.openide.DialogDescriptor;
0068: import org.openide.DialogDisplayer;
0069: import org.openide.ErrorManager;
0070: import org.openide.LifecycleManager;
0071: import org.openide.awt.Actions;
0072: import org.openide.awt.Mnemonics;
0073: import org.openide.text.CloneableEditorSupport;
0074: import org.openide.text.PositionBounds;
0075: import org.openide.util.Lookup;
0076: import org.openide.util.NbBundle;
0077: import org.openide.util.RequestProcessor;
0078: import org.openide.util.Utilities;
0079: import org.openide.windows.TopComponent;
0080:
0081: /**
0082: * Panel for showing proposed changes (refactoring elements) of any refactoring.
0083: *
0084: * @author Pavel Flaska, Martin Matula
0085: */
0086: public class RefactoringPanel extends JPanel implements
0087: InvalidationListener {
0088:
0089: // PRIVATE FIELDS
0090: /* tree contains elements which will be changed by refactoring action */
0091: private transient JTree tree = null;
0092: /* toolbar button causing refresh of the data */
0093: private transient JButton refreshButton = null;
0094: /* button lying in the toolbar allows expansion of all nodes in a tree */
0095: private transient JToggleButton expandButton = null;
0096: private JToolBar toolBar = null;
0097:
0098: private transient JButton refactorButton = null;
0099: private transient JButton cancelButton = null;
0100: private transient ButtonL buttonListener = null;
0101: private transient JButton rerunButton = null;
0102:
0103: private final RefactoringUI ui;
0104: private final boolean isQuery;
0105:
0106: private transient boolean isVisible = false;
0107: private transient RefactoringSession session = null;
0108: private transient ParametersPanel parametersPanel = null;
0109: private transient JScrollPane scrollPane = null;
0110: private transient JPanel southPanel;
0111: public JSplitPane splitPane;
0112: private JPanel left;
0113: private Action callback = null;
0114:
0115: private static final int MAX_ROWS = 50;
0116:
0117: private transient JToggleButton logicalViewButton = null;
0118: private transient JToggleButton physicalViewButton = null;
0119: private transient JToggleButton customViewButton = null;
0120: private transient ProgressListener progressListener;
0121:
0122: private transient JButton prevMatch = null;
0123: private transient JButton nextMatch = null;
0124: private WeakReference refCallerTC;
0125: private boolean inited = false;
0126: private Component customComponent;
0127:
0128: static Image PACKAGE_BADGE = Utilities
0129: .loadImage("org/netbeans/spi/java/project/support/ui/packageBadge.gif"); // NOI18N
0130:
0131: public RefactoringPanel(RefactoringUI ui) {
0132: this (ui, null);
0133: }
0134:
0135: public RefactoringPanel(RefactoringUI ui, TopComponent caller) {
0136: if (caller != null)
0137: refCallerTC = new WeakReference(caller);
0138: this .ui = ui;
0139: this .isQuery = ui.isQuery();
0140: refresh(true);
0141: }
0142:
0143: public RefactoringPanel(RefactoringUI ui,
0144: RefactoringSession session, Action callback) {
0145: this .session = session;
0146: this .ui = ui;
0147: this .isQuery = ui.isQuery();
0148: this .callback = callback;
0149: initialize();
0150: refresh(false);
0151: }
0152:
0153: public static void checkEventThread() {
0154: if (!SwingUtilities.isEventDispatchThread()) {
0155: ErrorManager.getDefault().notify(
0156: ErrorManager.INFORMATIONAL,
0157: new IllegalStateException(
0158: "This must happen in event thread!")); //NOI18N
0159: }
0160: }
0161:
0162: /* initializes all the ui */
0163: private void initialize() {
0164: if (inited)
0165: return;
0166: checkEventThread();
0167: setFocusCycleRoot(true);
0168: splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
0169: left = new JPanel();
0170: splitPane.setLeftComponent(left);
0171: left.setLayout(new BorderLayout());
0172: setLayout(new BorderLayout());
0173: add(splitPane, BorderLayout.CENTER);
0174: if (!isQuery) {
0175: splitPane.setRightComponent(new JLabel(
0176: org.openide.util.NbBundle.getMessage(
0177: RefactoringPanel.class,
0178: "LBL_Preview_not_Available"),
0179: SwingConstants.CENTER));
0180: }
0181: // add panel with buttons
0182: JButton[] buttons = getButtons();
0183: //if (buttons.length != 0) {
0184: // there will be at least one button on panel
0185: southPanel = new JPanel(new GridBagLayout());
0186: for (int i = 0; i < buttons.length; i++) {
0187: GridBagConstraints c = new GridBagConstraints();
0188: c.gridy = 0;
0189: c.insets = new Insets(5, 5, 5, 0);
0190: southPanel.add(buttons[i], c);
0191: }
0192: JPanel pp = new JPanel(new BorderLayout());
0193: GridBagConstraints c = new GridBagConstraints();
0194: c.gridy = 0;
0195: c.insets = new Insets(5, 5, 5, 5);
0196: c.weightx = 1;
0197: c.fill = c.HORIZONTAL;
0198: southPanel.add(pp, c);
0199:
0200: if (!isQuery || callback != null) {
0201: left.add(southPanel, BorderLayout.SOUTH);
0202: }
0203: //}
0204: // put the toolbar to the panel. If the getToolBar() returns null,
0205: // suppose the toolbar does not exist.
0206: JToolBar toolBar = getToolBar();
0207: if (toolBar != null)
0208: left.add(toolBar, BorderLayout.WEST);
0209: validate();
0210: inited = true;
0211: }
0212:
0213: /**
0214: * Returns the toolbar. In this default implementation, toolbar is
0215: * oriented vertically in the west and contains 'expand tree' toggle
0216: * button and refresh button.
0217: * Override this method and return null if you do not want toolbar
0218: * in your panel.
0219: *
0220: * @return toolBar with actions for refactoring panel
0221: */
0222: private JToolBar getToolBar() {
0223: checkEventThread();
0224: refreshButton = new JButton(
0225: new ImageIcon(
0226: Utilities
0227: .loadImage("org/netbeans/modules/refactoring/api/resources/refresh.png")) // NOI18N
0228: );
0229: Dimension dim = new Dimension(24, 24);
0230: refreshButton.setMaximumSize(dim);
0231: refreshButton.setMinimumSize(dim);
0232: refreshButton.setPreferredSize(dim);
0233: refreshButton.setToolTipText(NbBundle.getMessage(
0234: RefactoringPanel.class, "HINT_refresh") // NOI18N
0235: );
0236: refreshButton.setMnemonic(NbBundle.getMessage(
0237: RefactoringPanel.class, "MNEM_refresh").charAt(0));
0238: refreshButton.addActionListener(getButtonListener());
0239: // expand button settings
0240: expandButton = new JToggleButton(
0241: new ImageIcon(
0242: Utilities
0243: .loadImage("org/netbeans/modules/refactoring/api/resources/expandTree.png")) // NOI18N
0244: );
0245: expandButton
0246: .setSelectedIcon(new ImageIcon(
0247: Utilities
0248: .loadImage("org/netbeans/modules/refactoring/api/resources/colapseTree.png")) // NOI18N
0249: );
0250: expandButton.setMaximumSize(dim);
0251: expandButton.setMinimumSize(dim);
0252: expandButton.setPreferredSize(dim);
0253: expandButton.setSelected(true);
0254: expandButton.setToolTipText(NbBundle.getMessage(
0255: RefactoringPanel.class, "HINT_expandAll") // NOI18N
0256: );
0257: expandButton.setMnemonic(NbBundle.getMessage(
0258: RefactoringPanel.class, "MNEM_expandAll").charAt(0) // NOI18N
0259: );
0260: expandButton.addActionListener(getButtonListener());
0261: // create toolbar
0262: toolBar = new JToolBar(JToolBar.VERTICAL);
0263: toolBar.setFloatable(false);
0264:
0265: logicalViewButton = new JToggleButton(
0266: new ImageIcon(
0267: Utilities
0268: .loadImage("org/netbeans/modules/refactoring/api/resources/logical_view.png")) // NOI18N
0269: );
0270:
0271: logicalViewButton.setMaximumSize(dim);
0272: logicalViewButton.setMinimumSize(dim);
0273: logicalViewButton.setPreferredSize(dim);
0274: logicalViewButton.setSelected(currentView == LOGICAL);
0275: logicalViewButton.setToolTipText(NbBundle.getMessage(
0276: RefactoringPanel.class, "HINT_logicalView") // NOI18N
0277: );
0278: logicalViewButton.setMnemonic(NbBundle.getMessage(
0279: RefactoringPanel.class, "MNEM_logicalView").charAt(0) // NOI18N
0280: );
0281: logicalViewButton.addActionListener(getButtonListener());
0282:
0283: physicalViewButton = new JToggleButton(
0284: new ImageIcon(
0285: Utilities
0286: .loadImage("org/netbeans/modules/refactoring/api/resources/file_view.png")) // NOI18N
0287: );
0288:
0289: physicalViewButton.setMaximumSize(dim);
0290: physicalViewButton.setMinimumSize(dim);
0291: physicalViewButton.setPreferredSize(dim);
0292: physicalViewButton.setSelected(currentView == PHYSICAL);
0293: physicalViewButton.setToolTipText(NbBundle.getMessage(
0294: RefactoringPanel.class, "HINT_physicalView") // NOI18N
0295: );
0296: physicalViewButton.setMnemonic(NbBundle.getMessage(
0297: RefactoringPanel.class, "MNEM_physicalView").charAt(0) // NOI18N
0298: );
0299: physicalViewButton.addActionListener(getButtonListener());
0300:
0301: if (ui instanceof RefactoringCustomUI) {
0302: customViewButton = new JToggleButton(
0303: ((RefactoringCustomUI) ui).getCustomIcon());
0304: customViewButton.setMaximumSize(dim);
0305: customViewButton.setMinimumSize(dim);
0306: customViewButton.setPreferredSize(dim);
0307: customViewButton.setSelected(currentView == GRAPHICAL);
0308: customViewButton.setToolTipText(((RefactoringCustomUI) ui)
0309: .getCustomToolTip());
0310: customViewButton.addActionListener(getButtonListener());
0311: }
0312:
0313: nextMatch = new JButton(
0314: new ImageIcon(
0315: Utilities
0316: .loadImage("org/netbeans/modules/refactoring/api/resources/nextmatch.png")) // NOI18N
0317: );
0318:
0319: nextMatch.setMaximumSize(dim);
0320: nextMatch.setMinimumSize(dim);
0321: nextMatch.setPreferredSize(dim);
0322: nextMatch.setToolTipText(NbBundle.getMessage(
0323: RefactoringPanel.class, "HINT_nextMatch") // NOI18N
0324: );
0325: nextMatch.addActionListener(getButtonListener());
0326:
0327: prevMatch = new JButton(
0328: new ImageIcon(
0329: Utilities
0330: .loadImage("org/netbeans/modules/refactoring/api/resources/prevmatch.png")) // NOI18N
0331: );
0332:
0333: prevMatch.setMaximumSize(dim);
0334: prevMatch.setMinimumSize(dim);
0335: prevMatch.setPreferredSize(dim);
0336: prevMatch.setToolTipText(NbBundle.getMessage(
0337: RefactoringPanel.class, "HINT_prevMatch") // NOI18N
0338: );
0339: prevMatch.addActionListener(getButtonListener());
0340:
0341: toolBar.add(refreshButton);
0342: toolBar.add(expandButton);
0343: toolBar.add(logicalViewButton);
0344: toolBar.add(physicalViewButton);
0345: if (ui instanceof RefactoringCustomUI) {
0346: toolBar.add(customViewButton);
0347: }
0348: toolBar.add(prevMatch);
0349: toolBar.add(nextMatch);
0350:
0351: return toolBar;
0352: }
0353:
0354: /**
0355: * Returns array of available buttons. Initially, it returns only
0356: * basic "do refactoring/cancel refactoring" button. Override this method,
0357: * if you want to provide any other buttons with different action to be
0358: * performed.
0359: *
0360: * @return array of avasilable buttons.
0361: */
0362: private JButton[] getButtons() {
0363: checkEventThread();
0364: if (isQuery) {
0365: refactorButton = null;
0366: if (callback == null) {
0367: return new JButton[] {};
0368: } else {
0369: rerunButton = new JButton((String) callback
0370: .getValue(callback.NAME)); // NOI18N
0371: rerunButton.addActionListener(getButtonListener());
0372: return new JButton[] { rerunButton };
0373: }
0374: } else {
0375: refactorButton = new JButton(); // NOI18N
0376: Mnemonics.setLocalizedText(refactorButton, NbBundle
0377: .getMessage(RefactoringPanel.class,
0378: "LBL_DoRefactor"));
0379: refactorButton.setToolTipText(NbBundle.getMessage(
0380: RefactoringPanel.class, "HINT_DoRefactor")); // NOI18N
0381: refactorButton.addActionListener(getButtonListener());
0382: cancelButton = new JButton(NbBundle.getMessage(
0383: RefactoringPanel.class, "LBL_CancelRefactor")); // NOI18N
0384: Mnemonics.setLocalizedText(cancelButton, NbBundle
0385: .getMessage(RefactoringPanel.class,
0386: "LBL_CancelRefactor"));
0387: cancelButton.setToolTipText(NbBundle.getMessage(
0388: RefactoringPanel.class, "HINT_CancelRefactor")); // NOI18N
0389: cancelButton.addActionListener(getButtonListener());
0390: return new JButton[] { refactorButton, cancelButton };
0391: }
0392: }
0393:
0394: private static final byte LOGICAL = 0;
0395: private static final byte PHYSICAL = 1;
0396: private static final byte GRAPHICAL = 2;
0397:
0398: private byte currentView = PHYSICAL;
0399:
0400: void switchToLogicalView() {
0401: logicalViewButton.setSelected(true);
0402: if (currentView == LOGICAL)
0403: return;
0404: currentView = LOGICAL;
0405: physicalViewButton.setSelected(false);
0406: if (customViewButton != null) {
0407: customViewButton.setSelected(false);
0408: prevMatch.setEnabled(true);
0409: nextMatch.setEnabled(true);
0410: expandButton.setEnabled(true);
0411: }
0412: refresh(false);
0413: }
0414:
0415: void switchToPhysicalView() {
0416: physicalViewButton.setSelected(true);
0417: if (currentView == PHYSICAL)
0418: return;
0419: currentView = PHYSICAL;
0420: logicalViewButton.setSelected(false);
0421: if (customViewButton != null) {
0422: customViewButton.setSelected(false);
0423: prevMatch.setEnabled(true);
0424: nextMatch.setEnabled(true);
0425: expandButton.setEnabled(true);
0426: }
0427: refresh(false);
0428: }
0429:
0430: void switchToCustomView() {
0431: customViewButton.setSelected(true);
0432: if (currentView == GRAPHICAL)
0433: return;
0434: currentView = GRAPHICAL;
0435: logicalViewButton.setSelected(false);
0436: physicalViewButton.setSelected(false);
0437: prevMatch.setEnabled(false);
0438: nextMatch.setEnabled(false);
0439: expandButton.setEnabled(false);
0440: refresh(false);
0441: }
0442:
0443: private CheckNode createNode(TreeElement representedObject,
0444: HashMap nodes, CheckNode root) {
0445: //checkEventThread();
0446: boolean isLogical = currentView == LOGICAL;
0447:
0448: CheckNode node = null;
0449: if (representedObject instanceof SourceGroup) {
0450: //workaround for issue 52541
0451: node = (CheckNode) nodes
0452: .get(((SourceGroup) representedObject)
0453: .getRootFolder());
0454: } else {
0455: node = (CheckNode) nodes.get(representedObject);
0456: }
0457: if (node != null) {
0458: return node;
0459: }
0460:
0461: TreeElement parent = representedObject.getParent(isLogical);
0462: String displayName = representedObject.getText(isLogical);
0463: Icon icon = representedObject.getIcon();
0464:
0465: node = new CheckNode(representedObject, displayName, icon);
0466: CheckNode parentNode = parent == null ? root : createNode(
0467: parent, nodes, root);
0468: parentNode.add(node);
0469:
0470: if (representedObject instanceof SourceGroup) {
0471: //workaround for issue 52541
0472: nodes.put(
0473: ((SourceGroup) representedObject).getRootFolder(),
0474: node);
0475: } else {
0476: nodes.put(representedObject, node);
0477: }
0478: return node;
0479: }
0480:
0481: private static final String getString(String key) {
0482: return NbBundle.getMessage(RefactoringPanel.class, key);
0483: }
0484:
0485: /**
0486: * Overrides default ExplorerPanel behaviour. Does nothing now.
0487: */
0488: protected void updateTitle() {
0489: }
0490:
0491: /**
0492: * Method is responsible for making changes in sources.
0493: */
0494: private void refactor() {
0495: checkEventThread();
0496: disableComponents(RefactoringPanel.this );
0497: progressListener = new ProgressL();
0498: RequestProcessor.getDefault().post(new Runnable() {
0499: public void run() {
0500: try {
0501: session.addProgressListener(progressListener);
0502: session.doRefactoring(true);
0503: } finally {
0504: session.removeProgressListener(progressListener);
0505: progressListener = null;
0506: SwingUtilities.invokeLater(new Runnable() {
0507: public void run() {
0508: RefactoringPanel.this .close();
0509: }
0510: });
0511: }
0512: }
0513: });
0514: }
0515:
0516: /**
0517: * Cancel refactor action. This default implementation is closing window
0518: * only. It can return result state. In this implementation it returns
0519: * everytime 0.
0520: *
0521: * @return result of cancel operation. Zero represent successful cancel.
0522: */
0523: private int cancel() {
0524: checkEventThread();
0525: this .close();
0526: return 0;
0527: }
0528:
0529: void close() {
0530: if (isQuery) {
0531: RefactoringPanelContainer.getUsagesComponent().removePanel(
0532: this );
0533: } else {
0534: RefactoringPanelContainer.getRefactoringComponent()
0535: .removePanel(this );
0536: }
0537: closeNotify();
0538: }
0539:
0540: /*
0541: * Initializes button listener. The subclasses must not need this listener.
0542: * This is the reason of lazy initialization.
0543: */
0544: private ButtonL getButtonListener() {
0545: if (buttonListener == null)
0546: buttonListener = new ButtonL();
0547:
0548: return buttonListener;
0549: }
0550:
0551: RequestProcessor rp = new RequestProcessor();
0552:
0553: /* expandAll nodes in the tree */
0554: public void expandAll() {
0555: checkEventThread();
0556: final Cursor old = getCursor();
0557: expandButton.setEnabled(false);
0558: scrollPane.getViewport().remove(tree);
0559: setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
0560: rp.post(new Runnable() {
0561: public void run() {
0562: int row = 0;
0563: while (row < tree.getRowCount()) {
0564: tree.expandRow(row);
0565: row++;
0566: }
0567: SwingUtilities.invokeLater(new Runnable() {
0568: public void run() {
0569: scrollPane.setViewportView(tree);
0570: setCursor(old);
0571: expandButton.setEnabled(true);
0572: expandButton.setToolTipText(NbBundle
0573: .getMessage(RefactoringPanel.class,
0574: "HINT_collapseAll") // NOI18N
0575: );
0576: requestFocus();
0577: }
0578: });
0579: }
0580: });
0581: }
0582:
0583: /* collapseAll nodes in the tree */
0584: public void collapseAll() {
0585: checkEventThread();
0586: expandButton.setEnabled(false);
0587: final Cursor old = getCursor();
0588: scrollPane.getViewport().remove(tree);
0589: setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
0590: rp.post(new Runnable() {
0591: public void run() {
0592: int row = tree.getRowCount() - 1;
0593: while (row > 0) {
0594: tree.collapseRow(row);
0595: row--;
0596: }
0597: SwingUtilities.invokeLater(new Runnable() {
0598: public void run() {
0599: scrollPane.setViewportView(tree);
0600: setCursor(old);
0601: expandButton.setEnabled(true);
0602: expandButton.setToolTipText(NbBundle
0603: .getMessage(RefactoringPanel.class,
0604: "HINT_expandAll") // NOI18N
0605: );
0606: requestFocus();
0607: }
0608: });
0609: }
0610: });
0611: }
0612:
0613: public void invalidateObject() {
0614: if (isQuery) {
0615: return;
0616: }
0617: Runnable invalidate = new Runnable() {
0618: public void run() {
0619: setRefactoringEnabled(false, false);
0620: }
0621: };
0622: if (SwingUtilities.isEventDispatchThread()) {
0623: invalidate.run();
0624: } else {
0625: SwingUtilities.invokeLater(invalidate);
0626: }
0627: }
0628:
0629: private void refresh(final boolean showParametersPanel) {
0630: checkEventThread();
0631: if (!isQuery)
0632: LifecycleManager.getDefault().saveAll();
0633:
0634: if (showParametersPanel) {
0635: // create parameters panel for refactoring
0636: if (parametersPanel == null) {
0637: parametersPanel = new ParametersPanel(ui);
0638: }
0639: // show parameters dialog
0640: RefactoringSession tempSession = parametersPanel
0641: .showDialog();
0642: // if no elements were returned, action was either cancelled or preview
0643: // was skipped -> finish
0644: if (tempSession == null) {
0645: return;
0646: }
0647:
0648: session = tempSession;
0649: }
0650:
0651: initialize();
0652:
0653: final String description = ui.getDescription();
0654: setToolTipText("<html>" + description + "</html>"); // NOI18N
0655: final Collection elements = session.getRefactoringElements();
0656: setName(ui.getName());
0657: if (ui instanceof RefactoringCustomUI) {
0658: if (customComponent == null)
0659: customComponent = ((RefactoringCustomUI) ui)
0660: .getCustomComponent(elements);
0661: this .left.remove(customComponent);
0662: }
0663: final ProgressHandle progressHandle = ProgressHandleFactory
0664: .createHandle(NbBundle.getMessage(
0665: RefactoringPanel.class,
0666: isQuery ? "LBL_PreparingUsagesTree"
0667: : "LBL_PreparingRefactoringTree"));
0668: if (currentView == GRAPHICAL) {
0669: assert ui instanceof RefactoringCustomUI;
0670: assert customComponent != null;
0671: RefactoringCustomUI cui = (RefactoringCustomUI) ui;
0672: this .left.remove(scrollPane);
0673: this .left.add(customComponent, BorderLayout.CENTER);
0674: UI.setComponentForRefactoringPreview(null);
0675: this .splitPane.validate();
0676: this .repaint();
0677: tree = null;
0678: } else {
0679: RequestProcessor.getDefault().post(new Runnable() {
0680: public void run() {
0681: HashSet editorSupports = new HashSet();
0682: int errorsNum = 0;
0683: if (!isQuery) {
0684: for (Iterator iter = elements.iterator(); iter
0685: .hasNext();) {
0686: RefactoringElement elem = (RefactoringElement) iter
0687: .next();
0688: if (elem.getStatus() == RefactoringElement.GUARDED
0689: || elem.getStatus() == RefactoringElement.READ_ONLY) {
0690: errorsNum++;
0691: }
0692: }
0693: }
0694: int occurencesNum = elements.size();
0695: StringBuffer errorsDesc = new StringBuffer();
0696: errorsDesc.append(" [" + occurencesNum); // NOI18N
0697: errorsDesc.append(' ');
0698: errorsDesc.append(occurencesNum == 1 ? NbBundle
0699: .getMessage(RefactoringPanel.class,
0700: "LBL_Occurence") : NbBundle
0701: .getMessage(RefactoringPanel.class,
0702: "LBL_Occurences"));
0703: if (errorsNum > 0) {
0704: errorsDesc.append(',');
0705: errorsDesc.append(' ');
0706: errorsDesc.append("<font color=#CC0000>"
0707: + errorsNum); // NOI18N
0708: errorsDesc.append(' ');
0709: errorsDesc.append(errorsNum == 1 ? NbBundle
0710: .getMessage(RefactoringPanel.class,
0711: "LBL_Error") : NbBundle
0712: .getMessage(RefactoringPanel.class,
0713: "LBL_Errors"));
0714: errorsDesc.append("</font>"); // NOI18N
0715: }
0716: errorsDesc.append(']');
0717: final CheckNode root = new CheckNode(
0718: null,
0719: description + errorsDesc.toString(),
0720: new ImageIcon(
0721: Utilities
0722: .loadImage("org/netbeans/modules/refactoring/api/resources/"
0723: + (isQuery ? "findusages.png"
0724: : "refactoring.gif"))));
0725: HashMap nodes = new HashMap();
0726:
0727: final Cursor old = getCursor();
0728: setCursor(Cursor
0729: .getPredefinedCursor(Cursor.WAIT_CURSOR));
0730:
0731: progressHandle.start(elements.size() / 10);
0732: int i = 0;
0733: try {
0734: //[retouche] JavaModel.getJavaRepository().beginTrans(false);
0735: try {
0736: // ui.getRefactoring().setClassPath();
0737: for (Iterator it = elements.iterator(); it
0738: .hasNext(); i++) {
0739: RefactoringElement e = (RefactoringElement) it
0740: .next();
0741: createNode(TreeElementFactory
0742: .getTreeElement(e), nodes, root);
0743: PositionBounds pb = e.getPosition();
0744: if (pb != null) {
0745: CloneableEditorSupport ces = pb
0746: .getBegin()
0747: .getCloneableEditorSupport();
0748: editorSupports.add(ces);
0749: }
0750:
0751: if (i % 10 == 0)
0752: progressHandle.progress(i / 10);
0753: }
0754: } finally {
0755: //[retouche] JavaModel.getJavaRepository().endTrans();
0756: }
0757: UndoManager.getDefault().watch(editorSupports,
0758: RefactoringPanel.this );
0759: } catch (RuntimeException t) {
0760: cleanupTreeElements();
0761: throw t;
0762: } catch (Error e) {
0763: cleanupTreeElements();
0764: throw e;
0765: } finally {
0766: progressHandle.finish();
0767: setCursor(old);
0768: }
0769:
0770: SwingUtilities.invokeLater(new Runnable() {
0771: public void run() {
0772: if (tree == null) {
0773: // add panel with appropriate content
0774: tree = new JTree(root);
0775: ToolTipManager.sharedInstance()
0776: .registerComponent(tree);
0777: tree.setCellRenderer(new CheckRenderer(
0778: isQuery));
0779: String s = NbBundle.getMessage(
0780: RefactoringPanel.class,
0781: "ACSD_usagesTree"); // NOI18N
0782: tree.getAccessibleContext()
0783: .setAccessibleDescription(s);
0784: tree.getAccessibleContext()
0785: .setAccessibleName(s);
0786: CheckNodeListener l = new CheckNodeListener(
0787: isQuery);
0788: tree.addMouseListener(l);
0789: tree.addKeyListener(l);
0790: tree.setToggleClickCount(0);
0791: scrollPane = new JScrollPane(tree);
0792: RefactoringPanel.this .left
0793: .add(scrollPane,
0794: BorderLayout.CENTER);
0795: RefactoringPanel.this .validate();
0796: } else {
0797: tree
0798: .setModel(new DefaultTreeModel(
0799: root));
0800: }
0801: tree
0802: .setRowHeight((int) ((CheckRenderer) tree
0803: .getCellRenderer())
0804: .getPreferredSize()
0805: .getHeight());
0806:
0807: if (showParametersPanel) {
0808: splitPane.setDividerLocation(0.3);
0809: if (elements.size() < MAX_ROWS) {
0810: expandAll();
0811: if (!isQuery)
0812: selectNextUsage();
0813: } else
0814: expandButton.setSelected(false);
0815: } else {
0816: if (expandButton.isSelected()) {
0817: expandAll();
0818: if (!isQuery)
0819: selectNextUsage();
0820: } else
0821: expandButton.setSelected(false);
0822: }
0823:
0824: tree.setSelectionRow(0);
0825: requestFocus();
0826: setRefactoringEnabled(true, true);
0827: }
0828: });
0829: }
0830: });
0831: }
0832: if (!isVisible) {
0833: // dock it into output window area and display
0834: RefactoringPanelContainer cont = isQuery ? RefactoringPanelContainer
0835: .getUsagesComponent()
0836: : RefactoringPanelContainer
0837: .getRefactoringComponent();
0838: cont.open();
0839: cont.requestActive();
0840: cont.addPanel(this );
0841: isVisible = true;
0842: }
0843: setRefactoringEnabled(false, true);
0844: }
0845:
0846: public void requestFocus() {
0847: super .requestFocus();
0848: if (refactorButton != null) {
0849: refactorButton.requestFocus();
0850: } else {
0851: if (tree != null)
0852: tree.requestFocus();
0853: }
0854: }
0855:
0856: void setRefactoringEnabled(boolean enabled, boolean isRefreshing) {
0857: checkEventThread();
0858: if (tree != null) {
0859: if (!enabled) {
0860: CheckNode c = (CheckNode) tree.getModel().getRoot();
0861: if (!isRefreshing) {
0862: c.setNeedsRefresh();
0863: } else {
0864: c.setDisabled();
0865: }
0866: tree.setModel(new DefaultTreeModel(c, false));
0867: }
0868: // tree.validate();
0869: tree.setEnabled(enabled);
0870: if (refactorButton != null) {
0871: refactorButton.setEnabled(enabled);
0872: }
0873: }
0874: }
0875:
0876: // disables all components in a given container
0877: private static void disableComponents(Container c) {
0878: checkEventThread();
0879: Component children[] = c.getComponents();
0880: for (int i = 0; i < children.length; i++) {
0881: if (children[i].isEnabled()) {
0882: children[i].setEnabled(false);
0883: }
0884: if (children[i] instanceof Container) {
0885: disableComponents((Container) children[i]);
0886: }
0887: }
0888: }
0889:
0890: void selectNextUsage() {
0891: selectNextPrev(true);
0892: }
0893:
0894: void selectPrevUsage() {
0895: selectNextPrev(false);
0896: }
0897:
0898: private int location;
0899:
0900: public void storeDividerLocation() {
0901: if (splitPane.getRightComponent() != null)
0902: location = splitPane.getDividerLocation();
0903: }
0904:
0905: public void restoreDeviderLocation() {
0906: if (splitPane.getRightComponent() != null)
0907: splitPane.setDividerLocation(location);
0908: }
0909:
0910: private void selectNextPrev(final boolean next) {
0911: int newRow = getSelectedRow();
0912: int maxcount = tree.getRowCount();
0913: CheckNode node;
0914: do {
0915: if (next) {
0916: newRow++;
0917: if (newRow >= maxcount)
0918: newRow = 0;
0919: } else {
0920: newRow--;
0921: if (newRow < 0)
0922: newRow = maxcount - 1;
0923: }
0924: TreePath path = tree.getPathForRow(newRow);
0925: node = (CheckNode) path.getLastPathComponent();
0926: if (!node.isLeaf()) {
0927: tree.expandRow(newRow);
0928: maxcount = tree.getRowCount();
0929: }
0930: } while (!node.isLeaf());
0931: tree.setSelectionRow(newRow);
0932: tree.scrollRowToVisible(newRow);
0933: if (isQuery) {
0934: CheckNodeListener.findInSource(node);
0935: } else {
0936: CheckNodeListener.openDiff(node);
0937: }
0938: }
0939:
0940: private int getSelectedRow() {
0941: int[] rows = tree.getSelectionRows();
0942: if (rows == null || rows.length == 0)
0943: return 0;
0944: return rows[0];
0945: }
0946:
0947: ////////////////////////////////////////////////////////////////////////////
0948: // INNER CLASSES
0949: ////////////////////////////////////////////////////////////////////////////
0950:
0951: private class ButtonL implements ActionListener {
0952: public void actionPerformed(ActionEvent event) {
0953: Object o = event.getSource();
0954: // Cancel button pressed, remove refactoring panel
0955: if (o == cancelButton) {
0956: cancel();
0957: } else if (o == refactorButton) {
0958: refactor();
0959: } else if (o == rerunButton) {
0960: close();
0961: callback.actionPerformed(event);
0962: }
0963: // expandAll button selected/deselected
0964: else if (o == expandButton && tree != null) {
0965: if (expandButton.isSelected())
0966: expandAll();
0967: else
0968: collapseAll();
0969: } else if (o == refreshButton) {
0970: if (callback != null) {
0971: close();
0972: callback.actionPerformed(event);
0973: } else {
0974: refresh(true);
0975: }
0976: } else if (o == physicalViewButton) {
0977: switchToPhysicalView();
0978: } else if (o == logicalViewButton) {
0979: switchToLogicalView();
0980: } else if (o == customViewButton) {
0981: switchToCustomView();
0982: } else if (o == nextMatch) {
0983: selectNextUsage();
0984: } else if (o == prevMatch) {
0985: selectPrevUsage();
0986: }
0987: }
0988: } // end ButtonL
0989:
0990: ////////////////////////////////////////////////////////////////////////////
0991:
0992: private static String normalize(String input) {
0993: int size = input.length();
0994: char[] c = new char[size];
0995: input.getChars(0, size, c, 0);
0996: boolean wb = false;
0997: int pos = 0;
0998: char[] nc = new char[size];
0999:
1000: for (int i = 0; i < size; i++) {
1001: if (Character.isWhitespace(c[i])) {
1002: if (!wb) {
1003: nc[pos++] = ' ';
1004:
1005: wb = true;
1006: }
1007: } else {
1008: nc[pos++] = c[i];
1009: wb = false;
1010: }
1011: }
1012: return new String(nc, 0, pos);
1013: }
1014:
1015: /** Processes returned problems from refactoring operations and notifies
1016: * user (in case of non-fatal problems gives user a chance to continue or cancel).
1017: * @param problem Problems returned from a refactoring operation.
1018: * @return <code>true</code> if no fatal problems were found and user decided
1019: * to continue in case of non-fatal problems; <code>false</code> if there was at
1020: * least one fatal problem or at least one non-fatal problem in response to which
1021: * user decided to cancel the operation.
1022: */
1023: /* public static boolean confirmProblems(Problem problem) {
1024: while (problem != null) {
1025: int result;
1026: if (problem.isFatal()) {
1027: JOptionPane.showMessageDialog(null, problem.getMessage(), NbBundle.getMessage(ParametersPanel.class, "LBL_Error"), JOptionPane.ERROR_MESSAGE);
1028: return false;
1029: } else {
1030: if (JOptionPane.showConfirmDialog(
1031: null,
1032: problem.getMessage() + ' ' + NbBundle.getMessage(ParametersPanel.class, "QST_Continue"),
1033: NbBundle.getMessage(ParametersPanel.class, "LBL_Warning"),
1034: JOptionPane.YES_NO_OPTION,
1035: JOptionPane.WARNING_MESSAGE
1036: ) != JOptionPane.YES_OPTION) {
1037: return false;
1038: }
1039: }
1040: problem = problem.getNext();
1041: }
1042: return true;
1043: } */
1044:
1045: protected void closeNotify() {
1046: UndoWatcher.stopWatching(this );
1047: if (tree != null) {
1048: ToolTipManager.sharedInstance().unregisterComponent(tree);
1049: scrollPane.getViewport().remove(tree);
1050: }
1051: if (scrollPane != null)
1052: scrollPane.setViewport(null);
1053: if (refCallerTC != null) {
1054: TopComponent tc = (TopComponent) refCallerTC.get();
1055: if (tc != null && tc.isShowing()) {
1056: tc.requestActive();
1057: }
1058: }
1059: cleanupTreeElements();
1060: PreviewManager.getDefault().clean(this );
1061: tree = null;
1062: session = null;
1063: parametersPanel = null;
1064: //super.closeNotify();
1065: }
1066:
1067: private void cleanupTreeElements() {
1068: for (TreeElementFactoryImplementation tefi : Lookup
1069: .getDefault().lookupAll(
1070: TreeElementFactoryImplementation.class)) {
1071: tefi.cleanUp();
1072: }
1073: }
1074:
1075: private static class ProgressL implements ProgressListener {
1076:
1077: private ProgressHandle handle;
1078: private Dialog d;
1079: private int counter;
1080:
1081: public void start(final ProgressEvent event) {
1082: SwingUtilities.invokeLater(new Runnable() {
1083: public void run() {
1084: counter = 0;
1085: final String lab = NbBundle.getMessage(
1086: RefactoringPanel.class,
1087: "LBL_RefactorProgressLabel");
1088: handle = ProgressHandleFactory.createHandle(lab);
1089: JComponent progress = ProgressHandleFactory
1090: .createProgressComponent(handle);
1091: JPanel component = new JPanel();
1092: component.setLayout(new BorderLayout());
1093: component
1094: .setBorder(new EmptyBorder(12, 12, 11, 11));
1095: JLabel label = new JLabel(lab);
1096: label.setBorder(new EmptyBorder(0, 0, 6, 0));
1097: component.add(label, BorderLayout.NORTH);
1098: component.add(progress, BorderLayout.CENTER);
1099: DialogDescriptor desc = new DialogDescriptor(
1100: component, NbBundle.getMessage(
1101: RefactoringPanel.class,
1102: "LBL_RefactoringInProgress"), true,
1103: new Object[] {}, null, 0, null, null);
1104: desc.setLeaf(true);
1105: d = DialogDisplayer.getDefault().createDialog(desc);
1106: ((JDialog) d)
1107: .setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
1108:
1109: handle.start(event.getCount());
1110: d.show();
1111: }
1112: });
1113: }
1114:
1115: public void step(ProgressEvent event) {
1116: SwingUtilities.invokeLater(new Runnable() {
1117: public void run() {
1118: try {
1119: handle.progress(++counter);
1120: } catch (Throwable e) {
1121: ErrorManager.getDefault().notify(
1122: ErrorManager.INFORMATIONAL, e);
1123: }
1124: }
1125: });
1126: }
1127:
1128: public void stop(ProgressEvent event) {
1129: SwingUtilities.invokeLater(new Runnable() {
1130: public void run() {
1131: handle.finish();
1132: d.hide();
1133: }
1134: });
1135: }
1136: }
1137: } // end Refactor Panel
|