| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.netbeans.modules.refactoring.java.ui; |
| |
| import java.awt.Component; |
| import java.awt.Dimension; |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Set; |
| import javax.lang.model.element.Element; |
| import javax.lang.model.element.ElementKind; |
| import javax.lang.model.element.Modifier; |
| import javax.lang.model.element.TypeElement; |
| import javax.lang.model.type.TypeMirror; |
| import javax.swing.JPanel; |
| import javax.swing.JTable; |
| import javax.swing.UIManager; |
| import javax.swing.event.ChangeListener; |
| import javax.swing.table.AbstractTableModel; |
| import org.netbeans.api.java.source.*; |
| import org.netbeans.modules.refactoring.java.RefactoringUtils; |
| import org.netbeans.modules.refactoring.java.api.MemberInfo; |
| import org.netbeans.modules.refactoring.java.api.PushDownRefactoring; |
| import org.netbeans.modules.refactoring.spi.ui.CustomRefactoringPanel; |
| import org.openide.util.NbBundle; |
| |
| /** |
| * |
| * @author Pavel Flaska |
| */ |
| public class PushDownPanel extends JPanel implements CustomRefactoringPanel { |
| |
| // helper constants describing columns in the table of members |
| private static final String[] COLUMN_NAMES = {"LBL_PullUp_Selected", "LBL_PullUp_Member", "LBL_PushDown_KeepAbstract"}; // NOI18N |
| private static final Class[] COLUMN_CLASSES = {Boolean.class, MemberInfo.class, Boolean.class}; |
| |
| // refactoring this panel provides parameters for |
| private final PushDownRefactoring refactoring; |
| // table model for the table of members |
| private final TableModel tableModel; |
| // pre-selected members (comes from the refactoring action - the elements |
| // that should be pre-selected in the table of members) |
| private final Set selectedMembers; |
| // data for the members table (first dimension - rows, second dimension - columns) |
| // the columns are: 0 = Selected (true/false), 1 = Member (Java element), 2 = Make Abstract (true/false) |
| private Object[][] members = new Object[0][0]; |
| |
| private ChangeListener parent; |
| |
| private boolean initialized = false; |
| |
| |
| /** Creates new form PushDownPanel |
| * @param refactoring The refactoring this panel provides parameters for. |
| * @param selectedMembers Members that should be pre-selected in the panel |
| * (determined by which nodes the action was invoked on - e.g. if it was |
| * invoked on a method, the method will be pre-selected to be pulled up) |
| */ |
| public PushDownPanel(PushDownRefactoring refactoring, Set selectedMembers, ChangeListener parent) { |
| this.refactoring = refactoring; |
| this.tableModel = new TableModel(); |
| this.selectedMembers = selectedMembers; |
| initComponents(); |
| setPreferredSize(new Dimension(420, 380)); |
| this.parent = parent; |
| } |
| |
| @Override |
| public void initialize() { |
| if (initialized) { |
| return; |
| } |
| final TreePathHandle handle = refactoring.getSourceType(); |
| JavaSource source = JavaSource.forFileObject(handle.getFileObject()); |
| try { |
| source.runUserActionTask(new InitialisationTask(handle), true); |
| } catch (IOException ioe) { |
| throw new RuntimeException(ioe); |
| } |
| parent.stateChanged(null); |
| initialized = true; |
| } |
| |
| public MemberInfo[] getMembers() { |
| List list = new ArrayList(); |
| // go through all rows of a table and collect selected members |
| for (int i = 0; i < members.length; i++) { |
| // if the current row is selected, create MemberInfo for it and |
| // add it to the list of selected members |
| if (members[i][0].equals(Boolean.TRUE)) { |
| Object element = members[i][1]; |
| MemberInfo member; |
| member = (MemberInfo) element; |
| if (members[i][2]!=null) { |
| member.setMakeAbstract((Boolean)members[i][2]); |
| } |
| list.add(member); |
| } |
| } |
| // return the array of selected members |
| return (MemberInfo[]) list.toArray(new MemberInfo[list.size()]); |
| } |
| |
| /** This method is called from within the constructor to |
| * initialize the form. |
| * WARNING: Do NOT modify this code. The content of this method is |
| * always regenerated by the Form Editor. |
| */ |
| // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents |
| private void initComponents() { |
| |
| membersScrollPane = new javax.swing.JScrollPane(); |
| membersTable = new javax.swing.JTable(); |
| chooseLabel = new javax.swing.JLabel(); |
| |
| setLayout(new java.awt.BorderLayout()); |
| |
| membersScrollPane.setToolTipText(""); |
| |
| membersTable.setModel(tableModel); |
| membersScrollPane.setViewportView(membersTable); |
| membersTable.getAccessibleContext().setAccessibleName(null); |
| membersTable.getAccessibleContext().setAccessibleDescription(null); |
| |
| add(membersScrollPane, java.awt.BorderLayout.CENTER); |
| |
| chooseLabel.setLabelFor(membersTable); |
| org.openide.awt.Mnemonics.setLocalizedText(chooseLabel, org.openide.util.NbBundle.getMessage(PushDownPanel.class, "LBL_PushDownLabel")); // NOI18N |
| add(chooseLabel, java.awt.BorderLayout.NORTH); |
| }// </editor-fold>//GEN-END:initComponents |
| // </editor-fold> |
| //GEN-FIRST:event_jComboBox1ActionPerformed |
| //GEN-LAST:event_jComboBox1ActionPerformed |
| // Variables declaration - do not modify//GEN-BEGIN:variables |
| private javax.swing.JLabel chooseLabel; |
| private javax.swing.JScrollPane membersScrollPane; |
| private javax.swing.JTable membersTable; |
| // End of variables declaration//GEN-END:variables |
| private class TableModel extends AbstractTableModel { |
| |
| @Override |
| public int getColumnCount() { |
| return COLUMN_NAMES.length; |
| } |
| |
| @Override |
| public String getColumnName(int column) { |
| return UIUtilities.getColumnName(NbBundle.getMessage(PushDownPanel.class, COLUMN_NAMES[column])); |
| } |
| |
| @Override |
| public Class getColumnClass(int columnIndex) { |
| return COLUMN_CLASSES[columnIndex]; |
| } |
| |
| @Override |
| public int getRowCount() { |
| return members.length; |
| } |
| |
| @Override |
| public Object getValueAt(int rowIndex, int columnIndex) { |
| return members[rowIndex][columnIndex]; |
| } |
| |
| @Override |
| public void setValueAt(Object value, int rowIndex, int columnIndex) { |
| members[rowIndex][columnIndex] = value; |
| parent.stateChanged(null); |
| } |
| |
| @Override |
| public boolean isCellEditable(int rowIndex, int columnIndex) { |
| if (columnIndex == 2) { |
| // column 2 is editable only in case of non-static methods |
| if (members[rowIndex][2] == null) { |
| return false; |
| } |
| Object element = members[rowIndex][1]; |
| |
| return !(((MemberInfo) element).getModifiers().contains(Modifier.STATIC)); |
| } else { |
| // column 0 is always editable, column 1 is never editable |
| return columnIndex == 0; |
| } |
| } |
| } |
| |
| @Override |
| public Component getComponent() { |
| return this; |
| } |
| |
| private class InitialisationTask implements CancellableTask<CompilationController> { |
| |
| private final TreePathHandle handle; |
| |
| public InitialisationTask(TreePathHandle handle) { |
| this.handle = handle; |
| } |
| |
| @Override |
| public void cancel() { |
| } |
| |
| @Override |
| public void run(CompilationController controller) throws Exception { |
| controller.toPhase(JavaSource.Phase.RESOLVED); |
| List<MemberInfo<? extends ElementHandle<? extends Element>>> l = new ArrayList(); |
| TypeElement sourceTypeElement = (TypeElement) handle.resolveElement(controller); |
| for (TypeMirror tm:sourceTypeElement.getInterfaces()) { |
| l.add(MemberInfo.create(RefactoringUtils.typeToElement(tm, controller), controller, MemberInfo.Group.IMPLEMENTS)); |
| } |
| for (Element m: sourceTypeElement.getEnclosedElements()) { |
| if (m.getKind() == ElementKind.CONSTRUCTOR || m.getKind() == ElementKind.STATIC_INIT || m.getKind() == ElementKind.INSTANCE_INIT) { |
| continue; |
| } |
| if (m instanceof TypeElement && controller.getTypes().isSubtype(m.asType(), sourceTypeElement.asType())) { |
| continue; |
| } |
| l.add(MemberInfo.create(m,controller)); |
| } |
| |
| Object[][] allMembers = new Object[l.size()][3]; |
| int i = 0; |
| for (Iterator<MemberInfo<? extends ElementHandle<? extends Element>>> it = l.iterator(); it.hasNext(); ) { |
| MemberInfo<? extends ElementHandle<? extends Element>> o = it.next(); |
| allMembers[i][0] = selectedMembers.contains(o) ? Boolean.TRUE : Boolean.FALSE; |
| allMembers[i][1] = o; |
| allMembers[i][2] = o.getElementHandle().getKind()==ElementKind.METHOD? Boolean.FALSE : null; |
| i++; |
| } |
| members = new Object[i][3]; |
| if (i > 0) { |
| System.arraycopy(allMembers, 0, members, 0, i); |
| } |
| |
| // set renderer for the second column ("Member") do display name of the feature |
| membersTable.setDefaultRenderer(COLUMN_CLASSES[1], new UIUtilities.JavaElementTableCellRenderer() { |
| // override the extractText method to add "implements " prefix to the text |
| // in case the value is instance of MultipartId (i.e. it represents an interface |
| // name from implements clause) |
| @Override |
| protected String extractText(Object value) { |
| String displayValue = super.extractText(value); |
| |
| if (value instanceof MemberInfo && ((MemberInfo) value).getGroup()==MemberInfo.Group.IMPLEMENTS) { |
| displayValue = "implements " + displayValue; // NOI18N |
| } |
| return displayValue; |
| } |
| }); |
| // send renderer for the third column ("Make Abstract") to make the checkbox: |
| // 1. hidden for elements that are not methods |
| // 2. be disabled for static methods |
| // 3. be disabled and checked for methods if the target type is an interface |
| membersTable.getColumnModel().getColumn(2).setCellRenderer(new UIUtilities.BooleanTableCellRenderer(membersTable) { |
| @Override |
| public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { |
| // make the checkbox checked (even if "Make Abstract" is not set) |
| // for non-static methods if the target type is an interface |
| MemberInfo<ElementHandle> object = (MemberInfo) table.getModel().getValueAt(row, |
| 1); |
| // the super method automatically makes sure the checkbox is not visible if the |
| // "Make Abstract" value is null (which holds for non-methods) |
| // and that the checkbox is disabled if the cell is not editable (which holds for |
| // static methods all the time and for all methods in case the target type is an interface |
| // - see the table model) |
| return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); |
| } |
| }); |
| // set background color of the scroll pane to be the same as the background |
| // of the table |
| membersScrollPane.setBackground(membersTable.getBackground()); |
| membersScrollPane.getViewport().setBackground(membersTable.getBackground()); |
| // set default row height |
| membersTable.setRowHeight(18); |
| // set grid color to be consistent with other netbeans tables |
| if (UIManager.getColor("control") != null) { // NOI18N |
| membersTable.setGridColor(UIManager.getColor("control")); // NOI18N |
| } |
| // compute and set the preferred width for the first and the third column |
| UIUtilities.initColumnWidth(membersTable, 0, Boolean.TRUE, 4); |
| UIUtilities.initColumnWidth(membersTable, 2, Boolean.TRUE, 4);} |
| } |
| } |