0001: package tide.editor.completions;
0002:
0003: import tide.sources.FileItem;
0004: import tide.project.JDocRes;
0005: import tide.project.JavaDocManager;
0006: import tide.editor.Accelerators;
0007: import tide.bytecode.DecompileManager;
0008: import snow.texteditor.SimpleDocument;
0009: import snow.texteditor.DocumentUtils;
0010: import snow.utils.StringUtils;
0011: import javax.swing.table.DefaultTableModel;
0012: import snow.html.HTMLUtils;
0013: import java.awt.EventQueue;
0014: import java.awt.Insets;
0015: import java.awt.FlowLayout;
0016: import java.awt.BorderLayout;
0017: import tide.editor.MainEditorFrame;
0018: import snow.sortabletable.*;
0019: import tide.utils.SyntaxUtils;
0020: import tide.classsyntax.*;
0021: import java.util.*;
0022: import java.awt.event.*;
0023: import javax.swing.*;
0024: import javax.swing.event.*;
0025: import javax.swing.text.*;
0026: import javax.swing.text.html.*;
0027: import java.io.*;
0028: import java.lang.reflect.*;
0029:
0030: /** Fields and methods of class (and constructors).
0031: * Also used to complete the packages as in "java.lang." .
0032: * MODAL DIALOG. must be set visible by the caller !
0033: */
0034: public class AttributeCompletionDialog extends JDialog implements
0035: CompletionDialog {
0036: // TODO: javadoc & method argument names (parse from source OR javadoc)
0037: // TODO: listen to doc keys and close the dialog when "(" pressed !
0038: // TODO: factory methods (complete return type...)
0039:
0040: final int fontSize = UIManager.getFont("Label.font").getSize();
0041: final private CompletionModel cm = new CompletionModel();
0042: private final SortableTableModel stm = new SortableTableModel(cm);
0043: final private AdvancedSearchPanel asp = new AdvancedSearchPanel("",
0044: null, stm, false);
0045: private final JTable table = new JTable(stm);
0046: private final JEditorPane javaDocPane = new JEditorPane();
0047: private final JCheckBox viewInherited = new JCheckBox(
0048: "View inherited", true);
0049: private final JCheckBox viewDeprecated = new JCheckBox(
0050: "View deprecated", true);
0051: private final JCheckBox viewOnlyPublic = new JCheckBox(
0052: "Only public", false); // TODO
0053: private final JCheckBox viewDoc = new JCheckBox("Doc", true);
0054: private final JTabbedPane explPane = new JTabbedPane();
0055:
0056: private final JEditorPane memberExplorerPane = new JEditorPane();
0057: private final JPanel tablePanel = new JPanel(new BorderLayout(0, 0));
0058:
0059: private boolean wasCancelled = true; // BAD NAME...
0060: private AttrCompletionItem showedItem = null;
0061:
0062: String specialCompletion = null;
0063: String specialCompletionPrepend = null; // before the text entered after "." ...
0064:
0065: public String getSpecialCompletionPrepend() {
0066: return specialCompletionPrepend;
0067: }
0068:
0069: private JButton createVar = null, iterateCompl = null;
0070: private JButton overCompl = null;
0071:
0072: private final JSplitPane sp;
0073: final SimpleDocument doc;
0074: final int docOffset;
0075:
0076: private File browserLastBase = null;
0077:
0078: public AttributeCompletionDialog(JFrame owner, int x, int y,
0079: final SimpleDocument doc, final int docOffset,
0080: String title, boolean _viewOnlyPublicItems) {
0081: super (owner, title, true);
0082: this .setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
0083: this .docOffset = docOffset;
0084: this .doc = doc;
0085: viewOnlyPublic.setSelected(_viewOnlyPublicItems);
0086:
0087: setLayout(new BorderLayout(0, 0));
0088:
0089: tablePanel.add(new JScrollPane(table), BorderLayout.CENTER);
0090:
0091: stm.setSortedColumnAndOrder(-1, true); // avoid sorting.
0092: stm.installGUI(table);
0093: table.getSelectionModel().setSelectionMode(
0094: ListSelectionModel.SINGLE_SELECTION);
0095: //table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
0096:
0097: UniversalTableCellRenderer ute = new UniversalTableCellRenderer(
0098: stm);
0099: table.setDefaultRenderer(Object.class, ute);
0100:
0101: tablePanel.add(asp, BorderLayout.NORTH);
0102:
0103: ActionListener updateAction = new ActionListener() {
0104: public void actionPerformed(ActionEvent ae) {
0105: cm.filter(viewInherited.isSelected(), viewDeprecated
0106: .isSelected(), viewOnlyPublic.isSelected());
0107: }
0108: };
0109:
0110: asp.add(viewInherited);
0111: viewInherited.addActionListener(updateAction);
0112:
0113: asp.add(viewDeprecated);
0114: viewDeprecated.addActionListener(updateAction);
0115:
0116: asp.add(viewOnlyPublic);
0117: viewOnlyPublic.addActionListener(updateAction);
0118:
0119: asp.add(viewDoc);
0120: viewDoc.addActionListener(new ActionListener() {
0121: public void actionPerformed(ActionEvent ae) {
0122:
0123: MainEditorFrame.instance.globalProperties
0124: .setBoolean("ViewJavaDocInCompletion", viewDoc
0125: .isSelected());
0126: explPane.setVisible(viewDoc.isSelected());
0127: if (explPane.isVisible()) {
0128: int pos = MainEditorFrame.instance.globalProperties
0129: .getInteger(
0130: "AttributeCompletionDialog_divloc",
0131: fontSize * 30);
0132: if (pos >= getHeight()) {
0133: pos = getHeight() * 8 / 10;
0134: }
0135: //System.out.println("posloc="+pos);
0136: sp.setDividerLocation(pos);
0137: }
0138: }
0139: });
0140: viewDoc.setSelected(MainEditorFrame.instance.globalProperties
0141: .getBoolean("ViewJavaDocInCompletion", true));
0142: explPane.setVisible(viewDoc.isSelected());
0143:
0144: explPane.addTab("JavaDoc", new JScrollPane(javaDocPane));
0145: explPane.addTab("Member explorer", new JScrollPane(
0146: memberExplorerPane));
0147: explPane.setSelectedIndex(0);
0148: sp = new JSplitPane(JSplitPane.VERTICAL_SPLIT, tablePanel,
0149: explPane);
0150:
0151: javaDocPane.setEditable(false);
0152: memberExplorerPane.setEditable(false);
0153:
0154: add(sp, BorderLayout.CENTER);
0155:
0156: MainEditorFrame.instance.globalProperties
0157: .setComponentSizeFromINIFile(this ,
0158: "AttributeCompletionDialog", fontSize * 50,
0159: fontSize * 45, x, y);
0160: this .setLocation(x, y);
0161: CompletionUtils.ensureDialogInScreen(this );
0162: sp.setDividerLocation(MainEditorFrame.instance.globalProperties
0163: .getInteger("AttributeCompletionDialog_divloc",
0164: fontSize * 30));
0165: sp.setOneTouchExpandable(true);
0166:
0167: CompletionUtils.controlTableWithFieldKeys(asp.getTextField(),
0168: table, this , " @*/+-;,)");
0169:
0170: table.addKeyListener(new KeyAdapter() {
0171: @Override
0172: public void keyTyped(KeyEvent ke) {
0173: char c = ke.getKeyChar();
0174: if (Character.isLetterOrDigit(c)) {
0175: asp.getTextField().setText(
0176: asp.getTextField().getText() + c);
0177: asp.doSearch();
0178: }
0179: }
0180: });
0181:
0182: ((JComponent) getContentPane()).registerKeyboardAction(
0183: new ActionListener() {
0184: public void actionPerformed(ActionEvent ae) {
0185: wasCancelled = true;
0186: setVisible(false);
0187: return;
0188: }
0189: }, "Escape", Accelerators.escape,
0190: JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
0191:
0192: ((JComponent) getContentPane()).registerKeyboardAction(
0193: new ActionListener() {
0194: public void actionPerformed(ActionEvent ae) {
0195: wasCancelled = false;
0196: setVisible(false);
0197: return;
0198: }
0199: }, "Enter", KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,
0200: 0, true), // false => not working, let the table "jump"
0201: JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
0202:
0203: javaDocPane.addHyperlinkListener(new HyperlinkListener() {
0204: public void hyperlinkUpdate(HyperlinkEvent e) {
0205: if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
0206: JEditorPane pane = (JEditorPane) e.getSource();
0207: if (e instanceof HTMLFrameHyperlinkEvent) {
0208: // never occurs ??
0209: HTMLFrameHyperlinkEvent evt = (HTMLFrameHyperlinkEvent) e;
0210: HTMLDocument doc = (HTMLDocument) pane
0211: .getDocument();
0212: doc.processHTMLFrameHyperlinkEvent(evt);
0213: } else {
0214: try { // oct2007
0215: if (e.getURL() != null) {
0216: pane.setPage(e.getURL());
0217: return;
0218: }
0219:
0220: String relink = e.getDescription();
0221: // ex: ../../Object.html#wait(long)
0222: // relink=../../index.html?java/lang/StringBuilder.html
0223:
0224: //System.out.println("relink="+relink);
0225: if (relink != null && showedItem != null) {
0226: if (showedItem.jdoc != null
0227: && showedItem.jdoc != JDocRes.notFound) {
0228: if (browserLastBase == null) {
0229: browserLastBase = showedItem.jdoc.f;
0230: }
0231:
0232: String tag = null;
0233: String query = null; // TODO: handle
0234: int pos = relink.indexOf('#');
0235: File nf = null;
0236: if (pos >= 0) {
0237: tag = relink.substring(pos + 1);
0238: relink = relink.substring(0,
0239: pos);
0240: }
0241:
0242: pos = relink.indexOf('?'); // maybe in the tag ??
0243: if (pos >= 0) {
0244: query = relink
0245: .substring(pos + 1);
0246: relink = relink.substring(0,
0247: pos);
0248: }
0249:
0250: if (relink.length() == 0) {
0251: nf = browserLastBase; // pure tag
0252: } else {
0253: nf = new File(browserLastBase
0254: .getParentFile(),
0255: relink);
0256: nf = nf.getCanonicalFile();
0257: }
0258:
0259: if (!nf.exists()) {
0260: // TODO: try from all known doc roots...
0261:
0262: pane.setText("<html>Not Found:"
0263: + "<br> relink="
0264: + relink + "<br> tag="
0265: + tag + "<br> file="
0266: + nf + "<br> base="
0267: + browserLastBase
0268: + "<br> first base="
0269: + showedItem.jdoc.f);
0270: return;
0271: }
0272:
0273: browserLastBase = nf;
0274:
0275: String cont = JavaDocParser
0276: .getHTMLContent(nf);
0277: if (cont != null) {
0278: cont = JavaDocParser
0279: .replaceImages(cont);
0280: if (tag != null) {
0281: pos = cont
0282: .indexOf("<A NAME=\""
0283: + tag
0284: + "\"");
0285: if (pos > 0) {
0286: cont = cont
0287: .substring(pos);
0288: }
0289: }
0290: pane.setText(cont);
0291: pane.setCaretPosition(0);
0292: }
0293: }
0294:
0295: }
0296:
0297: } catch (Throwable t) {
0298: t.printStackTrace();
0299: }
0300: }
0301: }
0302: }
0303: });
0304:
0305: table.getSelectionModel().addListSelectionListener(
0306: new ListSelectionListener() {
0307: public void valueChanged(ListSelectionEvent lse) {
0308:
0309: int ind = stm
0310: .getIndexInUnsortedFromTablePos(table
0311: .getSelectedRow());
0312: if (ind >= 0) {
0313: //String pn = cm.getPackageOrTypeAt(ind);
0314: AttrCompletionItem ai = cm
0315: .getCompletionItem(ind);
0316: updateMemberAndJavaDocView(ai);
0317: updateButtonBar(ai);
0318: }
0319: }
0320: });
0321:
0322: this .addWindowListener(new WindowAdapter() {
0323: public void windowClosed(WindowEvent e) {
0324: saveSettingsOnClose();
0325: }
0326:
0327: public void windowClosing(WindowEvent e) {
0328: saveSettingsOnClose();
0329: }
0330: });
0331:
0332: }
0333:
0334: public void updateButtonBar(final AttrCompletionItem showedItem) {
0335: if (createVar != null) {
0336: createVar.setEnabled(showedItem != null
0337: && showedItem.getReturnType() != null
0338: && showedItem.getReturnType().length() > 0);
0339: }
0340: if (iterateCompl != null) {
0341: iterateCompl.setEnabled(showedItem != null
0342: && showedItem.getReturnType() != null
0343: && showedItem.getReturnType().length() > 0);
0344: // too restrictiveendsWith("[]"));
0345: }
0346:
0347: if (overCompl != null) {
0348: overCompl.setEnabled(showedItem != null
0349: && showedItem.isInherited()
0350: && (showedItem.getMember() instanceof Method));
0351: }
0352: }
0353:
0354: /** Offers creating a named variable for the return type.
0355: * For example after "this."
0356: */
0357: public void addFactoryBarForPointCompletion() {
0358: // only if ElementKind.Class
0359: JPanel fb = new JPanel(new FlowLayout(FlowLayout.LEFT, 1, 1));
0360: tablePanel.add(fb, BorderLayout.SOUTH);
0361:
0362: createVar = new JButton("create variable");
0363: createVar
0364: .setToolTipText("Creates a named variable for the return type of the selected completion");
0365: createVar.setMargin(new Insets(0, 2, 0, 2));
0366: fb.add(createVar);
0367: createVar.addActionListener(new ActionListener() {
0368: public void actionPerformed(ActionEvent ae) {
0369: if (showedItem == null)
0370: return;
0371:
0372: if (showedItem.getReturnType() == null
0373: || showedItem.getReturnType().trim().length() == 0)
0374: return;
0375:
0376: StringBuilder ret = new StringBuilder("final ");
0377: String rn = SyntaxUtils
0378: .makeAllJavaNamesSimpleInText(showedItem
0379: .getReturnType()); // Ex: Class<?>
0380: ret.append(rn);
0381:
0382: // remove the type parameters as in List<Object> => List
0383: rn = SyntaxUtils.removeSingleTypeParameters(rn);
0384:
0385: String varname = SyntaxUtils
0386: .removeAllArrayPartsAtEnd(Character
0387: .toLowerCase(rn.charAt(0))
0388: + rn.substring(1)); // NO plural (english ?)
0389: if (varname.equals(rn))
0390: varname = "_" + varname;
0391: ret.append(" ");
0392: ret.append(varname);
0393: ret.append(" = ");
0394: specialCompletionPrepend = ret.toString();
0395:
0396: specialCompletion = showedItem.getCompletion() + ";"; // make sense to put this...
0397: // todo: if method, append the ")"
0398:
0399: //close
0400: setVisible(false);
0401: }
0402: });
0403:
0404: addIterateBt(fb);
0405: addOverrideBt(fb);
0406: }
0407:
0408: private void addIterateBt(JPanel fb) {
0409: //TODO: iterate over iterable(), enumeration, ...
0410: iterateCompl = new JButton("iterate");
0411: iterateCompl
0412: .setToolTipText("Iterates over the return value. (must be an array or an iterator)");
0413: iterateCompl.setMargin(new Insets(0, 2, 0, 2));
0414: fb.add(iterateCompl);
0415: iterateCompl.addActionListener(new ActionListener() {
0416: public void actionPerformed(ActionEvent ae) {
0417: if (showedItem == null)
0418: return;
0419:
0420: if (showedItem.getReturnType() == null)
0421: return;
0422:
0423: if (showedItem.getReturnType().endsWith("[]")) {
0424: // array
0425: StringBuilder ret = new StringBuilder();
0426: String rn = SyntaxUtils
0427: .makeSingleJavaNameSimple(showedItem
0428: .getReturnType());
0429: rn = StringUtils.removeCharsAtEnd(rn, 2);
0430: ret.append("for(final " + rn);
0431: String varname = "it";
0432: if (varname.equals(rn))
0433: varname = "_" + varname;
0434: ret.append(" " + varname + " : ");
0435: specialCompletionPrepend = ret.toString();
0436:
0437: String line = DocumentUtils
0438: .getTextOfLineAtPosition(doc, docOffset);
0439: String spaces = DocumentUtils
0440: .getSpacesAtBeginning(line);
0441:
0442: specialCompletion = showedItem.getCompletion()
0443: + ") {\n" + spaces + " \n" + spaces + "}";
0444:
0445: //close
0446: setVisible(false);
0447: } else {
0448: // look if this is an iterator
0449:
0450: System.out.println("iterate over "
0451: + showedItem.getReturnType());
0452: if (showedItem.getMember() != null) {
0453: if (showedItem.getMember() instanceof Field) {
0454: Field fi = (Field) showedItem.getMember();
0455: System.out.println("field type = "
0456: + fi.getGenericType());
0457: } else if (showedItem.getMember() instanceof Method) {
0458: Method me = (Method) showedItem.getMember();
0459: System.out.println("method type = "
0460: + me.getGenericReturnType());
0461: } else if (showedItem.getMember() instanceof Constructor) {
0462: // constructor ? this is valid: for(String s : new ArrayList<String>( othercollection )) {}
0463: // must be iterable
0464: Constructor co = (Constructor) showedItem
0465: .getMember();
0466: System.out.println("constructor interf = "
0467: + Arrays.toString(co
0468: .getDeclaringClass()
0469: .getInterfaces()));
0470: } else if (showedItem.getMember() instanceof Class) {
0471: // constructor ? this is valid: for(String s : new ArrayList<String>( othercollection )) {}
0472: // must be iterable
0473: Class cl = (Class) showedItem.getMember();
0474: System.out.println("class interf = "
0475: + Arrays.toString(cl
0476: .getInterfaces()));
0477: }
0478: }
0479:
0480: String rt = showedItem.getReturnType(); // List<String>
0481: if (rt.indexOf('<') >= 0) {
0482: rt = StringUtils
0483: .extractFromFirstToLast_Excluded(rt,
0484: "<", ">");
0485: } else {
0486: rt = "Object"; // no generics.
0487: }
0488:
0489: // stupid case: just write...
0490:
0491: StringBuilder ret = new StringBuilder();
0492: String rn = SyntaxUtils
0493: .makeSingleJavaNameSimple(rt); // TODO
0494: ret.append("for(final " + rn);
0495: String varname = "it";
0496: if (varname.equals(rn))
0497: varname = "_" + varname;
0498: ret.append(" " + varname + " : ");
0499: specialCompletionPrepend = ret.toString();
0500:
0501: String line = DocumentUtils
0502: .getTextOfLineAtPosition(doc, docOffset);
0503: String spaces = DocumentUtils
0504: .getSpacesAtBeginning(line);
0505:
0506: specialCompletion = showedItem.getCompletion()
0507: + ") {\n" + spaces + " \n" + spaces + "}";
0508:
0509: //close
0510: setVisible(false);
0511: }
0512: }
0513: });
0514:
0515: updateButtonBar(null);
0516: }
0517:
0518: /**
0519: */
0520: private void addOverrideBt(JPanel fb) {
0521: overCompl = new JButton("override");
0522: overCompl.setToolTipText("Overrides the herited method");
0523: overCompl.setMargin(new Insets(0, 2, 0, 2));
0524: fb.add(overCompl);
0525: overCompl.addActionListener(new ActionListener() {
0526: public void actionPerformed(ActionEvent ae) {
0527: if (showedItem == null)
0528: return;
0529:
0530: if (!showedItem.isInherited())
0531: return;
0532:
0533: if (!(showedItem.getMember() instanceof Method))
0534: return;
0535:
0536: Method m = (Method) showedItem.getMember();
0537:
0538: StringBuilder ret = new StringBuilder();
0539: ret.append("@Override public final ");
0540: String rt = showedItem.getReturnType();
0541: boolean voidType = rt.length() == 0;
0542: if (voidType)
0543: rt = "void";
0544: ret.append(rt);
0545: ret.append(" ");
0546: ret.append(showedItem.getNameAndParams());
0547: ret.append(" {\n ");
0548: if (voidType) {
0549: ret.append("return ");
0550: }
0551: ret.append(showedItem.getSuperCall());
0552: ret.append("\n }");
0553:
0554: specialCompletion = ret.toString();
0555:
0556: //close
0557: setVisible(false);
0558:
0559: }
0560: });
0561:
0562: updateButtonBar(null);
0563: }
0564:
0565: /** Local variables.
0566: * Adds the buttons to create "new named instance" very useful for long names...
0567: * press JInterna and CTRL+space and you'll get a nice piece of code.
0568: */
0569: public void addFactoryBarForCTRLSpaceCompletion() {
0570: // only if ElementKind.Class
0571: JPanel fb = new JPanel(new FlowLayout(FlowLayout.LEFT, 1, 1));
0572: tablePanel.add(fb, BorderLayout.SOUTH);
0573: JButton insClass = new JButton("new named instance");
0574: insClass.setMargin(new Insets(0, 2, 0, 2));
0575: fb.add(insClass);
0576: insClass.addActionListener(new ActionListener() {
0577: public void actionPerformed(ActionEvent ae) {
0578: if (showedItem == null)
0579: return;
0580:
0581: if (showedItem.getKind() == ElementKind.Class) {
0582:
0583: // todo: maybe look if variable name exist and increment some counter
0584: String classname = SyntaxUtils
0585: .makeAllJavaNamesSimpleInText(showedItem
0586: .getNameAndParams());
0587: String varName = SyntaxUtils
0588: .createVariableNameFromClassName(classname);
0589:
0590: specialCompletion = showedItem.getCompletion()
0591: + " " + varName + " = new " + classname
0592: + "();";
0593:
0594: //close
0595: setVisible(false);
0596: }
0597: }
0598: });
0599:
0600: addIterateBt(fb);
0601: addOverrideBt(fb);
0602: }
0603:
0604: private void updateMemberAndJavaDocView(
0605: final AttrCompletionItem item) {
0606: if (showedItem == item)
0607: return;
0608: showedItem = item;
0609:
0610: // member doc
0611:
0612: StringBuilder sb = new StringBuilder();
0613:
0614: if (item.getMember() != null) {
0615: String normalStr = "" + item.getMember();
0616: sb.append("<br><b><code>"
0617: + HTMLUtils.convertCharsToHTML(normalStr)
0618: + "</code></b>");
0619:
0620: // there is no direct general way to call toGenericString() for a member, so we must switch:
0621: String genericStr = "";
0622: Type[] exceptions = new Type[0];
0623: if (item.getMember() instanceof Method) {
0624: Method me = (Method) item.getMember();
0625: genericStr = me.toGenericString();
0626: exceptions = me.getGenericExceptionTypes();
0627: } else if (item.getMember() instanceof Field) {
0628: genericStr = ((Field) item.getMember())
0629: .toGenericString();
0630: } else if (item.getMember() instanceof Constructor) {
0631: Constructor co = (Constructor) item.getMember();
0632: genericStr = co.toGenericString();
0633: exceptions = co.getGenericExceptionTypes();
0634: } else if (item.getMember() instanceof Class) {
0635: Class c = (Class) item.getMember();
0636: appendTypeMembers(c, sb);
0637: } else if (item.getMember() instanceof FileItem) {
0638: FileItem fi = (FileItem) item.getMember();
0639: if (fi.isDirectory()) {
0640: try {
0641: Package pack = Package.getPackage(fi
0642: .getJavaName());
0643: if (pack != null) {
0644: sb.append("<p>" + pack);
0645: if (pack.getAnnotations().length > 0) {
0646: sb.append("<p>"
0647: + pack.getAnnotations().length
0648: + " annotations.");
0649: }
0650:
0651: }
0652:
0653: } catch (Error ignore) {
0654: } catch (Exception ignore) {
0655: }
0656: } else {
0657: SingleClassLoader scl = SingleClassLoader
0658: .createSingleClassLoader(false);
0659: try {
0660: Class cl = scl.findClass(fi.getJavaName());
0661: if (cl != null) {
0662: appendTypeMembers(cl, sb);
0663: }
0664: } catch (Error ignore) {
0665: } catch (Exception ignore) {
0666: }
0667: }
0668: } else {
0669: sb.append("<br>Member is of type: "
0670: + item.getMember().getClass());
0671: }
0672:
0673: if (genericStr.length() > 0
0674: && !genericStr.equals(normalStr)) {
0675: sb.append("<br><b><code>Gen: "
0676: + HTMLUtils.convertCharsToHTML(genericStr)
0677: + "</code></b>");
0678: }
0679:
0680: if (exceptions.length > 0) {
0681: sb.append("<br><b><code>Exceptions: "
0682: + Arrays.toString(exceptions) + "</code></b>");
0683: }
0684:
0685: if (item.getMember() instanceof Member) {
0686: if (((Member) item.getMember()).isSynthetic()) {
0687: sb
0688: .append("<br><b><code>This member is synthetic, it was introduced by the compiler.</code></b>");
0689: }
0690: }
0691:
0692: // Todo: show final static primitive values ?
0693:
0694: } else {
0695: sb.append("<br><b><code>"
0696: + HTMLUtils
0697: .convertCharsToHTML(item.getReturnType())
0698: + " "
0699: + HTMLUtils.convertCharsToHTML(item
0700: .getNameAndParams()) + "</code></b>");
0701: }
0702:
0703: if (item.declaringClass != null) {
0704: sb.append("<p>Declaring class = "
0705: + HTMLUtils.convertCharsToHTML(""
0706: + item.declaringClass));
0707: }
0708: memberExplorerPane.setContentType("text/html");
0709: memberExplorerPane.setText("<html><body>" + sb.toString()
0710: + "</body></html>");
0711: memberExplorerPane.setCaretPosition(0);
0712:
0713: setJavaDoc(item);
0714:
0715: }
0716:
0717: private void appendTypeMembers(Class type, StringBuilder sb) {
0718: // todo: add params
0719: sb.append("<br><code> "
0720: + HTMLUtils.convertCharsToHTML("" + type.toString())
0721: + "</code>");
0722:
0723: for (Method mi : type.getMethods()) {
0724: sb.append("<br><code> "
0725: + HTMLUtils
0726: .convertCharsToHTML(mi.toGenericString())
0727: + "</code>");
0728: }
0729:
0730: for (Field mi : type.getFields()) {
0731: sb.append("<br><code> "
0732: + HTMLUtils
0733: .convertCharsToHTML(mi.toGenericString())
0734: + "</code>");
0735: }
0736: }
0737:
0738: private void saveSettingsOnClose() {
0739: MainEditorFrame.instance.globalProperties
0740: .saveComponentSizeInINIFile(this ,
0741: "AttributeCompletionDialog");
0742: if (explPane.isVisible()) {
0743: MainEditorFrame.instance.globalProperties.setInteger(
0744: "AttributeCompletionDialog_divloc", sp
0745: .getDividerLocation());
0746: }
0747: showedItem = null;
0748: }
0749:
0750: /** Sets the javaDoc (delayed).
0751: */
0752: public void setJavaDoc(final AttrCompletionItem ai) {
0753: if (!viewDoc.isSelected())
0754: return;
0755: browserLastBase = null;
0756: if (ai == null)
0757: return;
0758:
0759: Thread t = new Thread() {
0760: public void run() {
0761: final String jd;
0762: if (ai.customJavaDoc != null) {
0763: jd = ai.customJavaDoc;
0764: } else {
0765: if (ai.jdoc == null) {
0766: ai.jdoc = MainEditorFrame.instance
0767: .getActualProject().getJavaDocManager()
0768: .getJavaDocFor(ai);
0769: }
0770:
0771: if (ai.jdoc != null) {
0772: jd = ai.jdoc.part;
0773: } else {
0774: jd = "<html>No javadoc found";
0775: }
0776: }
0777:
0778: EventQueue.invokeLater(new Runnable() {
0779: public void run() {
0780: javaDocPane.setContentType("text/html");
0781: javaDocPane.setText(jd);
0782: javaDocPane.setCaretPosition(0);
0783: }
0784: });
0785: }
0786: };
0787: t.setName("AttributesCompletion:doc");
0788: t.setPriority(Thread.NORM_PRIORITY - 1);
0789: t.start();
0790:
0791: }
0792:
0793: boolean wasClosed = false;
0794:
0795: public void selectAndQuit() {
0796: this .wasCancelled = false;
0797: wasClosed = true;
0798: setVisible(false);
0799: }
0800:
0801: public void cancelDialog() {
0802: this .wasCancelled = true;
0803: wasClosed = true;
0804: setVisible(false);
0805: }
0806:
0807: // TODO... also show
0808: public int caretRewind = 0;
0809: public boolean showArgDialog = false;
0810:
0811: /** Without "."
0812: */
0813: public String getSelectionAndClear() {
0814: if (specialCompletion != null) {
0815: clear();
0816: return specialCompletion;
0817: }
0818: if (table.getSelectedRow() == -1 || wasCancelled) {
0819: // no selection made, return the typed text
0820: clear();
0821: return asp.getTextField().getText();
0822: }
0823:
0824: // return the selected table element
0825: int pos = stm.getIndexInUnsortedFromTablePos(table
0826: .getSelectedRow());
0827:
0828: String comp = cm.getCompletion(pos);
0829: caretRewind = cm.getCaretRewind(pos);
0830: //AttrCompletionItem ati = cm.getCompletionItem(pos);
0831: // ati.getMember();
0832:
0833: clear();
0834:
0835: return comp;
0836: }
0837:
0838: /** Should always be called to clear mem at end.
0839: */
0840: public void clear() {
0841: stm.removeOldListeners();
0842: table.setModel(new DefaultTableModel());
0843: cm.clear();
0844: }
0845:
0846: /** Call this delayed after the dialog appears ! */
0847: public void setCompletionItems(List<AttrCompletionItem> av) {
0848: //System.out.println("setCompletionItems");
0849: cm.initialize(av, viewInherited.isSelected(), viewDeprecated
0850: .isSelected(), viewOnlyPublic.isSelected());
0851: Thread t = new Thread() {
0852: public void run() {
0853: addParameterNames();
0854: }
0855: };
0856: t.setPriority(Thread.MIN_PRIORITY);
0857: t.start();
0858: }
0859:
0860: /** Adds lazyly, after cm.initialize.
0861: */
0862: private void addParameterNames() {
0863: // important...
0864: DecompileManager.getInstance().removeDecompForSources();
0865:
0866: for (AttrCompletionItem aci : new ArrayList<AttrCompletionItem>(
0867: cm.allItems)) // DECOUPLE !
0868: {
0869: if (wasClosed) // wascancelled is NOT ok.
0870: {
0871: System.out.println("add params abort");
0872: return;
0873: }
0874:
0875: if (aci.getHasArgs() && aci.getMember() != null) {
0876: if (aci.getMember() instanceof Method
0877: || aci.getMember() instanceof Constructor) {
0878: List<String> pn = AttributesParamNamesManager
0879: .getInstance().getParameterNames(
0880: (Member) aci.getMember());
0881: if (pn == null) {
0882: if (aci.isPublic()) {
0883: // private methods may not be documented, nor have names in bytecode (rt.jar)
0884: System.out.println("No param names for "
0885: + aci.getMember());
0886: }
0887: // do nothing...
0888: } else {
0889: //System.out.println(""+aci.getMember()+": "+pn );
0890: StringBuilder sb = new StringBuilder();
0891: if (aci.getMember() instanceof Method) {
0892: Method me = (Method) aci.getMember();
0893: sb.append(me.getName());
0894: } else if (aci.getMember() instanceof Constructor) {
0895: Constructor co = (Constructor) aci
0896: .getMember();
0897: sb.append(co.getName());
0898: }
0899:
0900: if (aci.getMember() != null) {
0901: Member me = (Member) aci.getMember();
0902:
0903: String args = AttributesParamNamesManager
0904: .createArgumentListWithNames(me,
0905: pn, aci.mapper, false); // (args)
0906: sb.append(args);
0907: } else {
0908: sb.append("NULL MEMBER");
0909: }
0910:
0911: aci.setNameAndParams(sb.toString());
0912: }
0913:
0914: }
0915: }
0916:
0917: cm.refresh();
0918: }
0919: //keep sel?
0920: cm.refresh();
0921: }
0922:
0923: static class CompletionModel extends FineGrainTableModel {
0924: final public List<AttrCompletionItem> allItems = new ArrayList<AttrCompletionItem>();
0925: final private List<AttrCompletionItem> filteredItems = new ArrayList<AttrCompletionItem>();
0926:
0927: public void clear() {
0928: /* Collides with the names resolver
0929: for(AttrCompletionItem it : allItems)
0930: {
0931: it.freeMem();
0932: }*/
0933: allItems.clear();
0934: filteredItems.clear();
0935: }
0936:
0937: /** Called later
0938: */
0939: public void initialize(List<AttrCompletionItem> av,
0940: boolean includeInherited, boolean includeDeprecated,
0941: boolean onlyPublic) {
0942: allItems.addAll(av);
0943: filter(includeInherited, includeDeprecated, onlyPublic);
0944: }
0945:
0946: public void filter(boolean includeInherited,
0947: boolean includeDeprecated, boolean onlyPublic) {
0948: synchronized (filteredItems) {
0949: filteredItems.clear();
0950: filteredItems.addAll(allItems);
0951: if (!includeInherited || !includeDeprecated
0952: || onlyPublic) // only look in case of limitation
0953: {
0954: for (int i = filteredItems.size() - 1; i >= 0; i--) // reverse !!
0955: {
0956: AttrCompletionItem fi = filteredItems.get(i);
0957: if ((fi.isInherited() && !includeInherited)
0958: || (fi.deprecated && !includeDeprecated)
0959: || (!fi.isPublic() && onlyPublic)) {
0960: //System.out.println("remove "+fi);
0961: filteredItems.remove(i);
0962: }
0963: }
0964: }
0965: }
0966: refresh();
0967: }
0968:
0969: private void refresh() {
0970: EventQueue.invokeLater(new Runnable() {
0971: public void run() {
0972: fireTableModelWillChange();
0973: fireTableDataChanged();
0974: fireTableModelHasChanged();
0975: }
0976: });
0977:
0978: }
0979:
0980: public Object getValueAt(int row, int col) {
0981:
0982: synchronized (filteredItems) {
0983: if (row < 0 || row >= filteredItems.size())
0984: return ""; //return "bad row "+row;
0985: if (col == 0)
0986: return filteredItems.get(row).isInherited() ? "I"
0987: : "";
0988: if (col == 1)
0989: return filteredItems.get(row).kindAndModifiers;
0990: if (col == 2)
0991: return filteredItems.get(row).getReturnType();
0992: if (col == 3) {
0993: if (filteredItems.get(row).deprecated) {
0994: return "DEPRECATED: "
0995: + filteredItems.get(row)
0996: .getNameAndParams();
0997: }
0998: return filteredItems.get(row).getNameAndParams();
0999: }
1000: if (col == 4)
1001: return filteredItems.get(row).deprecated;
1002: }
1003: return "??";
1004: }
1005:
1006: public String getCompletion(int row) {
1007: synchronized (filteredItems) {
1008: if (row < 0 || row >= filteredItems.size())
1009: return "bad row " + row;
1010: return filteredItems.get(row).getCompletion();
1011: }
1012: }
1013:
1014: public int getCaretRewind(int row) {
1015: synchronized (filteredItems) {
1016: if (row < 0 || row >= filteredItems.size())
1017: return 0;
1018: return filteredItems.get(row).rewindCaret;
1019: }
1020: }
1021:
1022: public int getRowCount() {
1023: return filteredItems.size();
1024: }
1025:
1026: public int getColumnCount() {
1027: return 4;
1028: } // don't show deprecated
1029:
1030: @Override
1031: public int getPreferredColumnWidth(int column) {
1032: if (column == 0)
1033: return 1;
1034: if (column == 1)
1035: return 8;
1036: if (column == 2)
1037: return 9;
1038: if (column == 3)
1039: return 40;
1040: if (column == 4)
1041: return 3;
1042: return 30;
1043: }
1044:
1045: @Override
1046: public int getColumnAlignment(int column) {
1047: if (column == 2)
1048: return JLabel.RIGHT;
1049: return JLabel.LEFT;
1050: }
1051:
1052: @Override
1053: public String getColumnName(int c) {
1054: if (c == 0)
1055: return "Inherited";
1056: if (c == 1)
1057: return "Type";
1058: if (c == 2)
1059: return "Return";
1060: if (c == 3)
1061: return "Name and args";
1062: if (c == 4)
1063: return "Deprecated";
1064:
1065: return "??";
1066: }
1067:
1068: public AttrCompletionItem getCompletionItem(int row) {
1069: synchronized (filteredItems) {
1070: if (row < 0 || row >= filteredItems.size())
1071: return null;
1072: return filteredItems.get(row);
1073: }
1074: }
1075:
1076: // TODO: manage the selection better (only one allowed, always the first hit if not already existing...
1077:
1078: @Override
1079: public void setRowSelection(int row, boolean isSelected) {
1080: clearRowSelection();
1081: synchronized (filteredItems) {
1082: if (row < 0 || row >= filteredItems.size()) {
1083: // System.out.println("Bad row "+row);
1084: return;
1085: }
1086: filteredItems.get(row).selectedInView = isSelected;
1087: }
1088:
1089: }
1090:
1091: @Override
1092: public boolean isRowSelected(int row) {
1093: synchronized (filteredItems) {
1094: if (row < 0 || row >= filteredItems.size())
1095: return false;
1096: return filteredItems.get(row).selectedInView;
1097: }
1098:
1099: }
1100:
1101: @Override
1102: public void clearRowSelection() {
1103: for (AttrCompletionItem ai : allItems) {
1104: ai.selectedInView = false;
1105: }
1106: }
1107: }
1108:
1109: }
|