2
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
6
* The contents of this file are subject to the terms of either the GNU
7
* General Public License Version 2 only ("GPL") or the Common
8
* Development and Distribution License("CDDL") (collectively, the
9
* "License"). You may not use this file except in compliance with the
10
* License. You can obtain a copy of the License at
11
* http://www.netbeans.org/cddl-gplv2.html
12
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
* specific language governing permissions and limitations under the
14
* License. When distributing the software, include this License Header
15
* Notice in each file and include the License file at
16
* nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
17
* particular file as subject to the "Classpath" exception as provided
18
* by Sun in the GPL Version 2 section of the License file that
19
* accompanied this code. If applicable, add the following below the
20
* License Header, with the fields enclosed by brackets [] replaced by
21
* your own identifying information:
22
* "Portions Copyrighted [year] [name of copyright owner]"
26
* The Original Software is NetBeans. The Initial Developer of the Original
27
* Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
28
* Microsystems, Inc. All Rights Reserved.
30
* If you wish your version of this file to be governed by only the CDDL
31
* or only the GPL Version 2, indicate your decision by adding
32
* "[Contributor] elects to include this software in this distribution
33
* under the [CDDL or GPL Version 2] license." If you do not indicate a
34
* single choice of license, a recipient has the option to distribute
35
* your version of this file under either the CDDL, the GPL Version 2 or
36
* to extend the choice of license to its licensees as provided above.
37
* However, if you add GPL Version 2 code and therefore, elected the GPL
38
* Version 2 license, then the option applies only if the new code is
39
* made subject to such option by the copyright holder.
41
package org.netbeans.modules.refactoring.java.ui;
43
import com.sun.source.tree.ClassTree;
44
import com.sun.source.tree.Tree;
45
import com.sun.source.tree.VariableTree;
46
import com.sun.source.util.TreePath;
47
import java.awt.Component;
48
import java.awt.Dimension;
49
import java.io.IOException;
50
import java.util.ArrayList;
51
import java.util.Collections;
52
import java.util.Comparator;
53
import java.util.List;
55
import javax.lang.model.element.Element;
56
import javax.lang.model.element.ElementKind;
57
import javax.lang.model.element.ExecutableElement;
58
import javax.lang.model.element.Modifier;
59
import javax.lang.model.element.VariableElement;
60
import javax.lang.model.type.TypeMirror;
61
import javax.swing.Icon;
62
import javax.swing.JPanel;
63
import javax.swing.JTable;
64
import javax.swing.UIManager;
65
import javax.swing.event.ChangeListener;
66
import javax.swing.event.DocumentEvent;
67
import javax.swing.event.DocumentListener;
68
import javax.swing.table.AbstractTableModel;
69
import javax.swing.table.DefaultTableCellRenderer;
70
import org.netbeans.api.java.source.CancellableTask;
71
import org.netbeans.api.java.source.CompilationController;
72
import org.netbeans.api.java.source.ElementHandle;
73
import org.netbeans.api.java.source.JavaSource;
74
import org.netbeans.api.java.source.TreePathHandle;
75
import org.netbeans.api.java.source.TypeMirrorHandle;
76
import org.netbeans.api.java.source.UiUtils;
77
import org.netbeans.api.java.source.UiUtils.PrintPart;
78
import org.netbeans.modules.refactoring.java.api.ExtractInterfaceRefactoring;
79
import org.netbeans.modules.refactoring.spi.ui.CustomRefactoringPanel;
80
import org.openide.filesystems.FileObject;
81
import org.openide.util.NbBundle;
83
/** UI panel for collecting refactoring parameters.
85
* @author Martin Matula, Jan Becicka, Jan Pokorsky
87
public final class ExtractInterfacePanel extends JPanel implements CustomRefactoringPanel {
88
// helper constants describing columns in the table of members
89
private static final String[] COLUMN_NAMES = {"LBL_Selected", "LBL_ExtractInterface_Member"}; // NOI18N
90
private static final Class[] COLUMN_CLASSES = {Boolean.class, TreePathHandle.class};
92
// refactoring this panel provides parameters for
93
private final ExtractInterfaceRefactoring refactoring;
94
// table model for the table of members
95
private final TableModel tableModel;
96
// data for the members table (first dimension - rows, second dimension - columns)
97
// the columns are: 0 = Selected (true/false), 1 = ExtractInterfaceInfo (Java element)
98
private Object[][] members = new Object[0][0];
100
/** Creates new form ExtractInterfacePanel
101
* @param refactoring The refactoring this panel provides parameters for.
103
public ExtractInterfacePanel(ExtractInterfaceRefactoring refactoring, final ChangeListener parent) {
104
this.refactoring = refactoring;
105
this.tableModel = new TableModel();
107
setPreferredSize(new Dimension(420, 380));
108
String defaultName = "NewInterface"; //NOI18N
109
nameText.setText(defaultName);
110
nameText.setSelectionStart(0);
111
nameText.setSelectionEnd(defaultName.length());
112
nameText.getDocument().addDocumentListener(new DocumentListener() {
113
public void changedUpdate(DocumentEvent event) {
114
parent.stateChanged(null);
116
public void insertUpdate(DocumentEvent event) {
117
parent.stateChanged(null);
119
public void removeUpdate(DocumentEvent event) {
120
parent.stateChanged(null);
125
public void requestFocus() {
126
super.requestFocus();
127
nameText.requestFocus();
131
/** Initialization of the panel (called by the parent window).
133
public void initialize() {
134
// *** initialize table
135
// set renderer for the second column ("Member") to display name of the feature
136
membersTable.setDefaultRenderer(COLUMN_CLASSES[1], new DefaultTableCellRenderer() {
137
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
138
super.getTableCellRendererComponent(table, extractText(value), isSelected, hasFocus, row, column);
139
if (value instanceof ExtractInterfaceInfo) {
140
setIcon(((ExtractInterfaceInfo) value).icon);
144
protected String extractText(Object value) {
146
if (value instanceof ExtractInterfaceInfo) {
147
displayValue = ((ExtractInterfaceInfo) value).htmlText;
149
displayValue = String.valueOf(value);
154
// set background color of the scroll pane to be the same as the background
156
scrollPane.setBackground(membersTable.getBackground());
157
scrollPane.getViewport().setBackground(membersTable.getBackground());
158
// set default row height
159
membersTable.setRowHeight(18);
160
// set grid color to be consistent with other netbeans tables
161
if (UIManager.getColor("control") != null) { // NOI18N
162
membersTable.setGridColor(UIManager.getColor("control")); // NOI18N
164
// compute and set the preferred width for the first and the third column
165
UIUtilities.initColumnWidth(membersTable, 0, Boolean.TRUE, 4);
168
// --- GETTERS FOR REFACTORING PARAMETERS ----------------------------------
170
/** stores data collected via the panel.
172
public void storeSettings() {
173
List<ElementHandle<VariableElement>> fields = new ArrayList<ElementHandle<VariableElement>>();
174
List<ElementHandle<ExecutableElement>> methods = new ArrayList<ElementHandle<ExecutableElement>>();
175
List<TypeMirrorHandle<TypeMirror>> implementz = new ArrayList<TypeMirrorHandle<TypeMirror>>();
177
List<TreePathHandle> list = new ArrayList<TreePathHandle>();
178
// go through all rows of a table and collect selected members
179
for (int i = 0; i < members.length; i++) {
180
if (members[i][0].equals(Boolean.TRUE)) {
181
ExtractInterfaceInfo info = (ExtractInterfaceInfo) members[i][1];
183
case FIELD: fields.add((ElementHandle<VariableElement>) info.handle); break;
184
case METHOD: methods.add((ElementHandle<ExecutableElement>) info.handle); break;
185
case IMPLEMENTS: implementz.add((TypeMirrorHandle<TypeMirror>) info.handle); break;
190
refactoring.setFields(fields);
191
refactoring.setImplements(implementz);
192
refactoring.setMethods(methods);
193
refactoring.setInterfaceName(nameText.getText());
196
// --- GENERATED CODE ------------------------------------------------------
198
/** This method is called from within the constructor to
199
* initialize the form.
200
* WARNING: Do NOT modify this code. The content of this method is
201
* always regenerated by the Form Editor.
203
// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
204
private void initComponents() {
206
namePanel = new javax.swing.JPanel();
207
nameLabel = new javax.swing.JLabel();
208
chooseLabel = new javax.swing.JLabel();
209
nameText = new javax.swing.JTextField();
210
scrollPane = new javax.swing.JScrollPane();
211
membersTable = new javax.swing.JTable();
213
setBorder(javax.swing.BorderFactory.createEmptyBorder(12, 12, 11, 11));
214
setLayout(new java.awt.BorderLayout());
216
namePanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 1, 1));
217
namePanel.setLayout(new java.awt.BorderLayout(12, 0));
219
nameLabel.setLabelFor(nameText);
220
org.openide.awt.Mnemonics.setLocalizedText(nameLabel, org.openide.util.NbBundle.getMessage(ExtractInterfacePanel.class, "LBL_ExtractInterface_Name")); // NOI18N
221
namePanel.add(nameLabel, java.awt.BorderLayout.WEST);
222
nameLabel.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(ExtractInterfacePanel.class, "ACSD_InterfaceName")); // NOI18N
223
nameLabel.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(ExtractInterfacePanel.class, "ACSD_InterfaceNameDescription")); // NOI18N
225
chooseLabel.setLabelFor(membersTable);
226
org.openide.awt.Mnemonics.setLocalizedText(chooseLabel, org.openide.util.NbBundle.getMessage(ExtractInterfacePanel.class, "LBL_ExtractInterfaceLabel")); // NOI18N
227
chooseLabel.setBorder(javax.swing.BorderFactory.createEmptyBorder(6, 0, 0, 0));
228
namePanel.add(chooseLabel, java.awt.BorderLayout.SOUTH);
229
chooseLabel.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(ExtractInterfacePanel.class, "ExtractInterfacePanel.chooseLabel.AccessibleContext.accessibleDescription")); // NOI18N
231
namePanel.add(nameText, java.awt.BorderLayout.CENTER);
233
add(namePanel, java.awt.BorderLayout.NORTH);
235
membersTable.setModel(tableModel);
236
membersTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_NEXT_COLUMN);
237
scrollPane.setViewportView(membersTable);
238
membersTable.getAccessibleContext().setAccessibleName(null);
239
membersTable.getAccessibleContext().setAccessibleDescription(null);
241
add(scrollPane, java.awt.BorderLayout.CENTER);
242
}// </editor-fold>//GEN-END:initComponents
245
// Variables declaration - do not modify//GEN-BEGIN:variables
246
private javax.swing.JLabel chooseLabel;
247
private javax.swing.JTable membersTable;
248
private javax.swing.JLabel nameLabel;
249
private javax.swing.JPanel namePanel;
250
private javax.swing.JTextField nameText;
251
private javax.swing.JScrollPane scrollPane;
252
// End of variables declaration//GEN-END:variables
254
// --- MODELS --------------------------------------------------------------
256
/** Model for the members table.
258
private class TableModel extends AbstractTableModel {
263
public int getColumnCount() {
264
return COLUMN_NAMES.length;
267
public String getColumnName(int column) {
268
return UIUtilities.getColumnName(NbBundle.getMessage(ExtractInterfacePanel.class, COLUMN_NAMES[column]));
271
public Class getColumnClass(int columnIndex) {
272
return COLUMN_CLASSES[columnIndex];
275
public int getRowCount() {
276
return members.length;
279
public Object getValueAt(int rowIndex, int columnIndex) {
280
return members[rowIndex][columnIndex];
283
public void setValueAt(Object value, int rowIndex, int columnIndex) {
284
members[rowIndex][columnIndex] = value;
287
public boolean isCellEditable(int rowIndex, int columnIndex) {
288
// column 0 is always editable, column 1 is never editable
289
return columnIndex == 0;
293
private void initialize() {
294
final TreePathHandle sourceType = refactoring.getSourceType();
295
if (sourceType == null) return;
297
FileObject fo = sourceType.getFileObject();
298
JavaSource js = JavaSource.forFileObject(fo);
300
js.runUserActionTask(new CancellableTask<CompilationController>() {
301
public void cancel() {
304
public void run(CompilationController javac) throws Exception {
305
javac.toPhase(JavaSource.Phase.RESOLVED);
306
initializeInTransaction(javac, sourceType);
310
} catch (IOException ex) {
311
new IllegalStateException(ex);
315
private void initializeInTransaction(CompilationController javac, TreePathHandle sourceType) {
316
TreePath sourceTreePath = sourceType.resolve(javac);
317
ClassTree sourceTree = (ClassTree) sourceTreePath.getLeaf();
318
List result = new ArrayList();
320
for (Tree implTree : sourceTree.getImplementsClause()) {
321
TreePath implPath = javac.getTrees().getPath(javac.getCompilationUnit(), implTree);
322
TypeMirror implMirror = javac.getTrees().getTypeMirror(implPath);
323
result.add(new ExtractInterfaceInfo<TypeMirrorHandle>(
324
TypeMirrorHandle.create(implMirror),
325
"implements " + implTree.toString(), // NOI18N
326
UiUtils.getElementIcon(ElementKind.INTERFACE, null),
332
for (Tree member : sourceTree.getMembers()) {
333
TreePath memberTreePath = javac.getTrees().getPath(javac.getCompilationUnit(), member);
334
if (javac.getTreeUtilities().isSynthetic(memberTreePath))
337
Element memberElm = javac.getTrees().getElement(memberTreePath);
339
if (memberElm == null || !(mods = memberElm.getModifiers()).contains(Modifier.PUBLIC))
343
String format = PrintPart.NAME;
344
if (memberElm.getKind() == ElementKind.FIELD) {
345
if (!mods.contains(Modifier.STATIC) || !mods.contains(Modifier.FINAL)
346
|| ((VariableTree) member).getInitializer() == null)
349
format += " : " + PrintPart.TYPE; // NOI18N
350
// XXX see ExtractInterfaceRefactoringPlugin class description
351
// } else if (member.getKind() == Tree.Kind.CLASS) {
352
// if (!mods.contains(Modifier.STATIC))
355
} else if (memberElm.getKind() == ElementKind.METHOD) {
356
if (mods.contains(Modifier.STATIC))
358
group = Group.METHOD;
359
format += PrintPart.PARAMETERS + " : " + PrintPart.TYPE; // NOI18N
363
result.add(new ExtractInterfaceInfo<ElementHandle>(
364
ElementHandle.create(memberElm),
365
UiUtils.getHeader(memberElm, javac, format),
366
UiUtils.getElementIcon(memberElm.getKind(), mods),
367
memberElm.getSimpleName().toString(),
372
// the members are collected
373
// now, create a tree map (to sort them) and create the table data
374
Collections.sort(result, new Comparator() {
375
public int compare(Object o1, Object o2) {
376
ExtractInterfaceInfo i1 = (ExtractInterfaceInfo) o1;
377
ExtractInterfaceInfo i2 = (ExtractInterfaceInfo) o2;
378
int result = i1.group.compareTo(i2.group);
381
result = i1.name.compareTo(i2.name);
387
members = new Object[result.size()][2];
388
for (int i = 0; i < members.length; i++) {
389
members[i][0] = Boolean.FALSE;
390
members[i][1] = result.get(i);
392
// fire event to repaint the table
393
this.fireTableDataChanged();
397
public Component getComponent() {
401
private static final class ExtractInterfaceInfo<H> {
403
final String htmlText;
408
public ExtractInterfaceInfo(H handle, String htmlText, Icon icon, String name, Group group) {
409
this.handle = handle;
410
this.htmlText = htmlText;
418
IMPLEMENTS, METHOD, FIELD;