001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.refactoring.java.ui;
042:
043: import com.sun.source.util.TreePath;
044: import java.util.HashSet;
045: import java.util.Set;
046: import javax.lang.model.element.Element;
047: import javax.lang.model.element.TypeElement;
048: import javax.swing.event.ChangeListener;
049: import org.netbeans.api.java.source.CompilationInfo;
050: import org.netbeans.api.java.source.SourceUtils;
051: import org.netbeans.api.java.source.TreePathHandle;
052: import org.netbeans.api.java.source.UiUtils;
053: import org.netbeans.modules.refactoring.api.AbstractRefactoring;
054: import org.netbeans.modules.refactoring.api.Problem;
055: import org.netbeans.modules.refactoring.java.api.MemberInfo;
056: import org.netbeans.modules.refactoring.java.api.PullUpRefactoring;
057: import org.netbeans.modules.refactoring.spi.ui.CustomRefactoringPanel;
058: import org.netbeans.modules.refactoring.spi.ui.RefactoringUI;
059: import org.openide.util.HelpCtx;
060: import org.openide.util.NbBundle;
061: import org.openide.util.lookup.Lookups;
062:
063: /** Refactoring UI object for Pull Up refactoring.
064: *
065: * @author Martin Matula
066: */
067: public class PullUpRefactoringUI implements RefactoringUI {
068: // reference to pull up refactoring this UI object corresponds to
069: private final PullUpRefactoring refactoring;
070: // initially selected members
071: private final Set initialMembers;
072: // UI panel for collecting parameters
073: private PullUpPanel panel;
074:
075: private String description;
076:
077: /** Creates a new instance of PullUpRefactoringUI
078: * @param selectedElements Elements the refactoring action was invoked on.
079: */
080: public PullUpRefactoringUI(TreePathHandle[] selectedElements,
081: CompilationInfo info) {
082: initialMembers = new HashSet();
083: initialMembers.add(MemberInfo.create(selectedElements[0]
084: .resolveElement(info), info));
085: // compute source type and members that should be pre-selected from the
086: // set of elements the action was invoked on
087:
088: // create an instance of pull up refactoring object
089: Element selected = selectedElements[0].resolveElement(info);
090: if (!(selected instanceof TypeElement))
091: selected = SourceUtils.getEnclosingTypeElement(selected);
092: TreePath tp = info.getTrees().getPath(selected);
093: TreePathHandle sourceType = TreePathHandle.create(tp, info);
094: description = UiUtils.getHeader(tp, info,
095: UiUtils.PrintPart.NAME);
096: refactoring = new PullUpRefactoring(sourceType);
097: refactoring.getContext().add(info.getClasspathInfo());
098:
099: }
100:
101: // --- IMPLEMENTATION OF RefactoringUI INTERFACE ---------------------------
102:
103: public boolean isQuery() {
104: return false;
105: }
106:
107: public CustomRefactoringPanel getPanel(ChangeListener parent) {
108: if (panel == null) {
109: panel = new PullUpPanel(refactoring, initialMembers, parent);
110: }
111: return panel;
112: }
113:
114: public Problem setParameters() {
115: captureParameters();
116: return refactoring.checkParameters();
117: }
118:
119: public Problem checkParameters() {
120: captureParameters();
121: return refactoring.fastCheckParameters();
122: }
123:
124: public AbstractRefactoring getRefactoring() {
125: return refactoring;
126: }
127:
128: public String getDescription() {
129: return NbBundle.getMessage(PullUpAction.class, "DSC_PullUp",
130: description); // NOI18N
131: }
132:
133: public String getName() {
134: return NbBundle.getMessage(PullUpAction.class, "LBL_PullUp"); // NOI18N
135: }
136:
137: public boolean hasParameters() {
138: return true;
139: }
140:
141: public HelpCtx getHelpCtx() {
142: return new HelpCtx(PullUpRefactoringUI.class.getName());
143: }
144:
145: // --- PRIVATE HELPER METHODS ----------------------------------------------
146:
147: /** Gets parameters from the refactoring panel and sets them
148: * to the refactoring object.
149: */
150: private void captureParameters() {
151: refactoring.setTargetType(panel.getTargetType()
152: .getElementHandle());
153: refactoring.setMembers(panel.getMembers());
154: }
155:
156: // /** Method that computes the source type and initially selected members from
157: // * elements the refactoring action was invoked on.
158: // * It tries to find a common parent class for the elements to return it as the
159: // * the source type. If not all elements
160: // * have a common parent class, then the class that is a parent class for majority
161: // * of the elements is chosen. The parent JavaClass, Field, Method or MultipartId that
162: // * is part of interface names of a class is taken as the pre-selected member.
163: // * @elements The elements the refactoring was invoked on.
164: // * @initialMembers Should be an empty set that this method will add the members
165: // * that should be selected.
166: // * @return Source type.
167: // */
168: // private static JavaClass getSourceType(Element[] elements, Set initialMembers) {
169: // JavaClass result = null;
170: // // map that will be used to compute final source type and pre-selected members
171: // // maps suggested source type to a set of its suggested pre-selected members
172: // HashMap elementsByClass = new HashMap();
173: //
174: // for (int i = 0; i < elements.length; i++) {
175: // Element element = null;
176: // Element temp = elements[i];
177: // // iterate through the containers of the element (until we get to null
178: // // or a resource)
179: // while (temp != null && !(temp instanceof Resource)) {
180: // if ((temp instanceof JavaClass) || (temp instanceof Field) || (temp instanceof Method)) {
181: // // if the current element is a class, field or a method, exit
182: // // the loop - we have an element that will likely be the member
183: // // to be initially selected
184: // break;
185: // } else if (temp instanceof MultipartId) {
186: // // if the current element is a MultipartId, remember it, but
187: // // go further to find the top-most MultipartId
188: // // if the MultipartId is part of interface names of a class,
189: // // then its direct parent should be JavaClass, so when
190: // // we exit the loop, "element" variable will contain the MultipartId
191: // // and the "temp" variable will contain its parent class.
192: // element = temp;
193: // }
194: // temp = (Element) temp.refImmediateComposite();
195: // }
196: // // if temp is null, the element is not in a resource -> ignore it
197: // if (temp == null) continue;
198: // // if element is a resource, find the primary class in it
199: // // (the class with the same name as the resource)
200: // if (temp instanceof Resource) {
201: // element = null;
202: // String name = ((Resource) temp).getName();
203: // int start = name.lastIndexOf('/') + 1;
204: // int end = name.indexOf('.', start);
205: // if (end < 0) end = name.length();
206: // name = name.substring(start, end);
207: // for (Iterator it = ((Resource) temp).getClassifiers().iterator(); it.hasNext();) {
208: // JavaClass cls = (JavaClass) it.next();
209: // temp = cls;
210: // // if the class of a same name is found, exit the loop
211: // if (name.equals(cls.getSimpleName())) break;
212: // }
213: // // if no class of the same name is found, then the last class in
214: // // the resource is taken as the selected one
215: // }
216: // if (temp instanceof JavaClass) {
217: // // if the found element is a class, check whether element is not null
218: // // and is part of the interface names in class implements clause
219: // if (element == null || !((JavaClass) temp).getInterfaceNames().contains(element)) {
220: // // if not, add the class as a suggested source type (i.e. in place of a key in the map)
221: // addToMap(elementsByClass, (JavaClass) temp, null);
222: // } else {
223: // // if so, the selected element is the interface name
224: // // put the class into element variable (which will later be added as a key
225: // // - i.e. as the suggested source type - into the map) and
226: // // the interface name into the temp variable (which will later be added
227: // // as a value to the map - i.e. as a suggested pre-selected member)
228: // Element cls = temp;
229: // temp = element;
230: // element = cls;
231: // }
232: // }
233: // if (temp instanceof Feature) {
234: // // if the element found is a feature (i.e. either JavaClass, or Field or a Method)
235: // // store its declaring class in element variable (as a suggested source type)
236: // element = ((Feature) temp).getDeclaringClass();
237: // }
238: // // if the thing in the element variable (i.e. the suggested source type)
239: // // is of a correct type (i.e. JavaClass) add the type and the member to the
240: // // map that will be used to compute final source type and pre-selected members
241: // if (element instanceof JavaClass) {
242: // addToMap(elementsByClass, (JavaClass) element, temp);
243: // }
244: // }
245: //
246: // // now go through the map and find the suggested source type corresponding
247: // // to the highest number of the pre-selected members
248: // Set maxMembers = Collections.EMPTY_SET;
249: // for (Iterator it = elementsByClass.entrySet().iterator(); it.hasNext();) {
250: // Map.Entry entry = (Map.Entry) it.next();
251: // Set value = (Set) entry.getValue();
252: // // if the number of members for this source type
253: // // is higher than the last max., take it as max
254: // // note that even when the number is equal, but the set of members contains
255: // // null, it takes a precedence - this is to correctly handle the case when the
256: // // only selected element is an inner class (the map will contain two records:
257: // // 1 - outer->inner, 2 - inner->null). In this case the algorithm chooses the inner class
258: // // to be the source type with no members pre-selected.
259: // if ((maxMembers.size() < value.size()) || ((maxMembers.size() == value.size()) && value.contains(null))) {
260: // maxMembers = value;
261: // result = (JavaClass) entry.getKey();
262: // }
263: // }
264: // initialMembers.addAll(maxMembers);
265: //
266: // return result;
267: // }
268:
269: // /** Helper method that simplifies adding members to the map of
270: // * suggested source types to the set of members.
271: // * @param map Map to add a new record to.
272: // * @param parentClass Map key - suggested source type.
273: // * @param member A new value for the key - pre-selected member.
274: // */
275: // private static void addToMap(Map map, JavaClass parentClass, Element member) {
276: // Set value = (Set) map.get(parentClass);
277: // if (value == null) {
278: // value = new HashSet();
279: // map.put(parentClass, value);
280: // }
281: // value.add(member);
282: // }
283: }
|