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:
042: package org.netbeans.modules.java.editor.imports;
043:
044: import com.sun.source.tree.CompilationUnitTree;
045: import com.sun.source.tree.ImportTree;
046: import com.sun.source.tree.Tree;
047: import com.sun.source.util.TreePath;
048: import java.awt.Color;
049: import java.awt.Component;
050: import java.awt.Font;
051: import java.awt.event.InputEvent;
052: import java.awt.event.KeyEvent;
053: import java.io.IOException;
054: import java.io.IOException;
055: import java.util.ArrayList;
056: import java.util.Collections;
057: import java.util.List;
058: import java.util.ListIterator;
059: import javax.lang.model.element.ElementKind;
060: import javax.lang.model.element.TypeElement;
061: import javax.swing.DefaultListCellRenderer;
062: import javax.swing.DefaultListModel;
063: import javax.swing.JLabel;
064: import javax.swing.JList;
065: import javax.swing.KeyStroke;
066: import org.netbeans.api.editor.EditorRegistry;
067: import org.netbeans.api.java.source.JavaSource;
068: import org.netbeans.api.java.source.Task;
069: import org.netbeans.api.java.source.JavaSource.Phase;
070: import org.netbeans.api.java.source.TreeMaker;
071: import org.netbeans.api.java.source.TreeUtilities;
072: import org.netbeans.api.java.source.WorkingCopy;
073: import org.netbeans.api.java.source.ui.ElementIcons;
074: import org.netbeans.editor.Utilities;
075: import org.netbeans.modules.java.editor.overridden.PopupUtil;
076: import org.openide.ErrorManager;
077: import org.openide.util.NbBundle;
078:
079: /**
080: *
081: * @author Jan Lahoda
082: */
083: public class ImportClassPanel extends javax.swing.JPanel {
084:
085: private JavaSource javaSource;
086: private DefaultListModel model;
087: private final int position;
088:
089: /** Creates new form ImportClassPanel */
090: public ImportClassPanel(List<TypeElement> priviledged,
091: List<TypeElement> denied, Font font, JavaSource javaSource,
092: int position) {
093: // System.err.println("priviledged=" + priviledged);
094: // System.err.println("denied=" + denied);
095: this .javaSource = javaSource;
096: this .position = position;
097: createModel(priviledged, denied);
098: initComponents();
099: setBackground(jList1.getBackground());
100:
101: if (model.size() > 0) {
102: jList1.setModel(model);
103: setFocusable(false);
104: setNextFocusableComponent(jList1);
105: jScrollPane1.setBackground(jList1.getBackground());
106: setBackground(jList1.getBackground());
107: if (font != null) {
108: jList1.setFont(font);
109: }
110: int modelSize = jList1.getModel().getSize();
111: if (modelSize > 0) {
112: jList1.setSelectedIndex(0);
113: }
114: jList1.setVisibleRowCount(modelSize > 8 ? 8 : modelSize);
115: jList1.setCellRenderer(new Renderer(jList1));
116: jList1.grabFocus();
117: } else {
118: remove(jScrollPane1);
119: JLabel nothingFoundJL = new JLabel("<No Classes Found>");
120: if (font != null) {
121: nothingFoundJL.setFont(font);
122: }
123: nothingFoundJL.setBorder(javax.swing.BorderFactory
124: .createEmptyBorder(2, 4, 4, 4));
125: nothingFoundJL.setEnabled(false);
126: nothingFoundJL.setBackground(jList1.getBackground());
127: //nothingFoundJL.setOpaque(true);
128: add(nothingFoundJL);
129: }
130:
131: setA11Y();
132: }
133:
134: private void setA11Y() {
135: this .getAccessibleContext().setAccessibleName(
136: NbBundle.getMessage(ImportClassPanel.class,
137: "ImportClassPanel_ACN"));
138: this .getAccessibleContext().setAccessibleDescription(
139: NbBundle.getMessage(ImportClassPanel.class,
140: "ImportClassPanel_ACSD"));
141: jList1.getAccessibleContext().setAccessibleName(
142: NbBundle.getMessage(ImportClassPanel.class,
143: "ImportClassPanel_JList1_ACN"));
144: jList1.getAccessibleContext().setAccessibleDescription(
145: NbBundle.getMessage(ImportClassPanel.class,
146: "ImportClassPanel_JList1_ACSD"));
147: }
148:
149: /** This method is called from within the constructor to
150: * initialize the form.
151: * WARNING: Do NOT modify this code. The content of this method is
152: * always regenerated by the Form Editor.
153: */
154: // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
155: private void initComponents() {
156:
157: jScrollPane1 = new javax.swing.JScrollPane();
158: jList1 = new javax.swing.JList();
159: jLabel1 = new javax.swing.JLabel();
160: jPanel1 = new javax.swing.JPanel();
161: ctrlLabel = new javax.swing.JLabel();
162:
163: setBorder(javax.swing.BorderFactory
164: .createLineBorder(new java.awt.Color(64, 64, 64)));
165: setLayout(new java.awt.BorderLayout());
166:
167: jScrollPane1.setBorder(javax.swing.BorderFactory
168: .createEmptyBorder(2, 4, 4, 4));
169:
170: jList1.addKeyListener(new java.awt.event.KeyAdapter() {
171: public void keyReleased(java.awt.event.KeyEvent evt) {
172: listKeyReleased(evt);
173: }
174: });
175: jList1.addMouseListener(new java.awt.event.MouseAdapter() {
176: public void mouseReleased(java.awt.event.MouseEvent evt) {
177: listMouseReleased(evt);
178: }
179: });
180: jScrollPane1.setViewportView(jList1);
181:
182: add(jScrollPane1, java.awt.BorderLayout.CENTER);
183:
184: jLabel1.setLabelFor(jList1);
185: jLabel1.setText("Type to import:");
186: jLabel1.setBorder(javax.swing.BorderFactory.createEmptyBorder(
187: 4, 4, 4, 4));
188: jLabel1.setOpaque(true);
189: add(jLabel1, java.awt.BorderLayout.PAGE_START);
190:
191: jPanel1.setBorder(javax.swing.BorderFactory.createEmptyBorder(
192: 4, 4, 4, 4));
193: jPanel1.setLayout(new java.awt.BorderLayout());
194:
195: ctrlLabel.setText(org.openide.util.NbBundle.getMessage(
196: ImportClassPanel.class, "LBL_PackageImport")); // NOI18N
197: jPanel1.add(ctrlLabel, java.awt.BorderLayout.CENTER);
198:
199: add(jPanel1, java.awt.BorderLayout.PAGE_END);
200: }// </editor-fold>//GEN-END:initComponents
201:
202: private void listMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_listMouseReleased
203: importClass(getSelected(),
204: (evt.getModifiers() & InputEvent.ALT_MASK) > 0, (evt
205: .getModifiers() & InputEvent.SHIFT_MASK) > 0);
206: }//GEN-LAST:event_listMouseReleased
207:
208: private void listKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_listKeyReleased
209: KeyStroke ks = KeyStroke.getKeyStrokeForEvent(evt);
210: if (ks.getKeyCode() == KeyEvent.VK_ENTER
211: || ks.getKeyCode() == KeyEvent.VK_SPACE) {
212: importClass(getSelected(),
213: (evt.getModifiers() & InputEvent.ALT_MASK) > 0,
214: (evt.getModifiers() & InputEvent.SHIFT_MASK) > 0);
215: }
216: }//GEN-LAST:event_listKeyReleased
217:
218: // Variables declaration - do not modify//GEN-BEGIN:variables
219: public javax.swing.JLabel ctrlLabel;
220: public javax.swing.JLabel jLabel1;
221: public javax.swing.JList jList1;
222: public javax.swing.JPanel jPanel1;
223: public javax.swing.JScrollPane jScrollPane1;
224:
225: // End of variables declaration//GEN-END:variables
226:
227: public String getSelected() {
228: TypeDescription typeDescription = ((TypeDescription) jList1
229: .getSelectedValue());
230: return typeDescription == null ? null
231: : typeDescription.qualifiedName;
232: }
233:
234: private void createModel(List<TypeElement> priviledged,
235: List<TypeElement> denied) {
236:
237: List<TypeDescription> l = new ArrayList<TypeDescription>(
238: priviledged.size());
239: for (TypeElement typeElement : priviledged) {
240: l.add(new TypeDescription(typeElement, false));
241: }
242:
243: List<TypeDescription> ld = new ArrayList<TypeDescription>(
244: priviledged.size());
245: for (TypeElement typeElement : denied) {
246: l.add(new TypeDescription(typeElement, true));
247: }
248:
249: Collections.sort(l);
250:
251: model = new DefaultListModel();
252: for (TypeDescription td : l) {
253: model.addElement(td);
254: }
255:
256: }
257:
258: private void importClass(String name, final boolean packageImport,
259: final boolean useFqn) {
260: PopupUtil.hidePopup();
261:
262: if (packageImport && !useFqn) {
263: int index = name.lastIndexOf('.'); // NOI18N
264: if (index != -1) {
265: name = name.substring(0, index) + ".*"; // NOI18N
266: }
267: }
268:
269: final String fqn = name;
270:
271: if (fqn != null) {
272: Task<WorkingCopy> task = new Task<WorkingCopy>() {
273:
274: public void run(final WorkingCopy wc)
275: throws IOException {
276: wc.toPhase(Phase.RESOLVED);
277: TreeMaker make = wc.getTreeMaker();
278: CompilationUnitTree cut = wc.getCompilationUnit();
279: // make a copy of list
280: List<ImportTree> imports = new ArrayList<ImportTree>(
281: cut.getImports());
282:
283: if (useFqn && replaceSimpleName(fqn, wc)) {
284: return;
285: }
286:
287: // Test whether already imported
288: if (isImported(fqn, imports)) {
289: Utilities
290: .setStatusText(
291: EditorRegistry
292: .lastFocusedComponent(),
293: NbBundle
294: .getMessage(
295: ImportClassPanel.class,
296: packageImport ? "MSG_PackageAlreadyImported"
297: : "MSG_ClassAlreadyImported",
298: fqn));
299: return;
300: }
301:
302: // prepare the import tree to add
303: ImportTree njuImport = make.Import(make
304: .Identifier(fqn), false);
305: for (ListIterator<ImportTree> it = imports
306: .listIterator(); it.hasNext();) {
307: ImportTree item = it.next();
308: if (item.isStatic()
309: || item.getQualifiedIdentifier()
310: .toString().compareTo(fqn) > 0) {
311: it.set(njuImport);
312: it.add(item);
313: break;
314: }
315: }
316: CompilationUnitTree cutCopy;
317: // import was inserted somewhere to inside the list, prepare
318: // copy of compilation unit.
319: if (imports.contains(njuImport)) {
320: cutCopy = make.CompilationUnit(cut
321: .getPackageName(), imports, cut
322: .getTypeDecls(), cut.getSourceFile());
323: } else {
324: // import section was not modified by for loop,
325: // either it means the section is empty or
326: // the import has to be added to the end of the section.
327: // prepare copy of compilation unit tree.
328: cutCopy = make
329: .addCompUnitImport(cut, njuImport);
330: }
331: wc.rewrite(cut, cutCopy);
332: }
333:
334: private boolean replaceSimpleName(String fqn,
335: WorkingCopy wc) {
336:
337: TreeUtilities tu = wc.getTreeUtilities();
338: TreePath tp = tu.pathFor(position);
339: TreeMaker tm = wc.getTreeMaker();
340:
341: if (tp.getLeaf().getKind() == Tree.Kind.IDENTIFIER) {
342: wc.rewrite(tp.getLeaf(), tm.Identifier(fqn));
343: return true;
344: }
345: return false;
346: }
347:
348: private boolean isImported(String fqn,
349: List<ImportTree> imports) {
350: for (ImportTree i : imports) {
351: if (fqn.equals(i.getQualifiedIdentifier()
352: .toString())) {
353: return true;
354: }
355: }
356: return false;
357:
358: }
359:
360: };
361: try {
362: javaSource.runModificationTask(task).commit();
363: } catch (IOException ex) {
364: ErrorManager.getDefault().notify(ex);
365: }
366: }
367: }
368:
369: private static class Renderer extends DefaultListCellRenderer {
370:
371: private static int DARKER_COLOR_COMPONENT = 5;
372: private static int LIGHTER_COLOR_COMPONENT = DARKER_COLOR_COMPONENT;
373:
374: private Color denidedColor = new Color(0x80, 0x80, 0x80);
375: private Color fgColor;
376: private Color bgColor;
377: private Color bgColorDarker;
378: private Color bgSelectionColor;
379: private Color fgSelectionColor;
380:
381: public Renderer(JList list) {
382: setFont(list.getFont());
383: fgColor = list.getForeground();
384: bgColor = list.getBackground();
385: bgColorDarker = new Color(Math.abs(bgColor.getRed()
386: - DARKER_COLOR_COMPONENT), Math.abs(bgColor
387: .getGreen()
388: - DARKER_COLOR_COMPONENT), Math.abs(bgColor
389: .getBlue()
390: - DARKER_COLOR_COMPONENT));
391: bgSelectionColor = list.getSelectionBackground();
392: fgSelectionColor = list.getSelectionForeground();
393: }
394:
395: public Component getListCellRendererComponent(JList list,
396: Object value, int index, boolean isSelected,
397: boolean hasFocus) {
398:
399: if (isSelected) {
400: setForeground(fgSelectionColor);
401: setBackground(bgSelectionColor);
402: } else {
403: setForeground(fgColor);
404: setBackground(index % 2 == 0 ? bgColor : bgColorDarker);
405: }
406:
407: if (value instanceof TypeDescription) {
408: TypeDescription td = (TypeDescription) value;
409: // setIcon(td.getIcon());
410: setText(td.qualifiedName);
411: if (td.isDenied) {
412: setForeground(denidedColor);
413: }
414: setIcon(ElementIcons.getElementIcon(td.kind, null));
415: } else {
416: setText(value.toString());
417: }
418:
419: return this ;
420: }
421:
422: }
423:
424: private static class TypeDescription implements
425: Comparable<TypeDescription> {
426: private boolean isDenied;
427: private final ElementKind kind;
428: private final String qualifiedName;
429:
430: public TypeDescription(TypeElement typeElement, boolean isDenied) {
431: this .isDenied = isDenied;
432: this .kind = typeElement.getKind();
433: this .qualifiedName = typeElement.getQualifiedName()
434: .toString();
435: }
436:
437: public int compareTo(TypeDescription o) {
438:
439: if (isDenied && !o.isDenied) {
440: return 1;
441: } else if (!isDenied && o.isDenied) {
442: return -1;
443: } else {
444: return qualifiedName.compareTo(o.qualifiedName);
445: }
446: }
447:
448: }
449:
450: }
|