001: package tide.editor.completions;
002:
003: import tide.editor.MainEditorFrame;
004: import snow.sortabletable.*;
005: import tide.utils.SyntaxUtils;
006: import java.util.*;
007: import java.awt.BorderLayout;
008: import java.awt.Insets;
009: import java.awt.EventQueue;
010: import java.awt.event.*;
011: import javax.swing.*;
012: import javax.swing.text.*;
013:
014: /** Javadoc or annotations, depending on context.
015: * BAD NAME, should not be Ampersand but "At"
016: * TODO: fetch available annotations (types).
017: */
018: public class AmpersandCompletionDialog extends JDialog implements
019: CompletionDialog {
020: final private CompletionModel cm = new CompletionModel();
021: private final SortableTableModel stm = new SortableTableModel(cm);
022: final private AdvancedSearchPanel asp = new AdvancedSearchPanel(
023: "@ ", null, stm, false);
024: private final JTable table = new JTable(stm);
025: private final JPanel optsPanel = new JPanel();
026: private final String preceedingTokenOfInterrest;
027:
028: private boolean wasCancelled = true;
029:
030: public AmpersandCompletionDialog(final boolean inComment,
031: JFrame owner, int x, int y, final Document doc,
032: final int docOffset, final String preceedingTokenOfInterrest) {
033: super (owner, "Completion", true);
034:
035: this .preceedingTokenOfInterrest = preceedingTokenOfInterrest;
036: setLayout(new BorderLayout(0, 0));
037:
038: add(new JScrollPane(table), BorderLayout.CENTER);
039: stm.installGUI(table);
040: stm.setSortedColumnAndOrder(-1, true); // avoid sorting.
041: table.getSelectionModel().setSelectionMode(
042: ListSelectionModel.SINGLE_SELECTION);
043:
044: add(optsPanel, BorderLayout.SOUTH);
045: optsPanel.setVisible(false);
046:
047: add(asp, BorderLayout.NORTH);
048:
049: final int fontSize = UIManager.getFont("Label.font").getSize();
050:
051: // fixed, but fontsize relative size :
052: this .setSize(fontSize * 45, fontSize * 30);
053: this .setLocation(x, y);
054:
055: CompletionUtils.controlTableWithFieldKeys(asp.getTextField(),
056: table, this , "");
057:
058: table.addKeyListener(new KeyAdapter() {
059: @Override
060: public void keyTyped(KeyEvent ke) {
061: char c = ke.getKeyChar();
062: if (Character.isLetterOrDigit(c)) {
063: asp.getTextField().setText(
064: asp.getTextField().getText() + c);
065: asp.doSearch();
066: }
067: }
068: });
069:
070: ((JComponent) getContentPane()).registerKeyboardAction(
071: new ActionListener() {
072: public void actionPerformed(ActionEvent ae) {
073: wasCancelled = true;
074: setVisible(false);
075: return;
076: }
077: }, "Escape", KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE,
078: 0, true),
079: JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
080:
081: ((JComponent) getContentPane()).registerKeyboardAction(
082: new ActionListener() {
083: public void actionPerformed(ActionEvent ae) {
084: wasCancelled = false;
085: setVisible(false);
086: return;
087: }
088: }, "Enter", KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,
089: 0, true),
090: JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
091:
092: // immediately show the dialog, delay the construction of the model to later !!
093: // so the user have an immediate completion
094: Thread t = new Thread() {
095: public void run() {
096: List<String>[] args = null;
097:
098: try {
099:
100: if (inComment) {
101: String txtAfter = doc.getText(docOffset, doc
102: .getLength()
103: - docOffset); //offset,length
104: args = SyntaxUtils
105: .parseSignatureAfterForJavaDoc(
106: txtAfter, 0);
107: if (args != null && args[1] != null
108: && args[1].size() > 0) {
109: offerAddingAll(args);
110: } else {
111: // System.out.println("NO arg compl");
112: }
113:
114: }
115: } catch (Exception e) {
116: e.printStackTrace();
117: }
118: // Quick !
119: cm.initialize(inComment, args);
120:
121: EventQueue.invokeLater(new Runnable() {
122: public void run() {
123: setTitle((inComment ? "Javadoc tag completion"
124: : "Annotation completion"));
125: }
126: });
127: }
128: };
129: t.setPriority(Thread.NORM_PRIORITY - 1);
130: t.start();
131:
132: this .setVisible(true);
133: } // initialize
134:
135: String customReplace = null;
136:
137: /** Generates the param tags for all entries...
138: */
139: private void offerAddingAll(final List<String>[] params) {
140:
141: EventQueue.invokeLater(new Runnable() {
142: public void run() {
143:
144: //System.out.println("adding all params: "+Arrays.toString(params));
145:
146: JButton addAll = new JButton(
147: "Add javadoc tags for all parameters");
148: addAll.setMargin(new Insets(0, 1, 0, 1));
149: addAll.setFocusPainted(false);
150: optsPanel.add(addAll);
151: optsPanel
152: .setPreferredSize(optsPanel.getPreferredSize());
153: optsPanel.setVisible(true);
154:
155: // must restitue the focus !
156: asp.getTextField().requestFocus();
157:
158: addAll.addActionListener(new ActionListener() {
159: public void actionPerformed(ActionEvent ae) {
160: StringBuilder sb = new StringBuilder();
161: for (String pn : params[1]) {
162: // TODO: look for the correct indent !
163: sb.append("\n * @param " + pn + " ");
164: }
165: customReplace = "" + sb;
166: selectAndQuit();
167: }
168: });
169:
170: }
171: });
172:
173: }
174:
175: public void selectAndQuit() {
176: this .wasCancelled = false;
177: setVisible(false);
178: }
179:
180: public void cancelDialog() {
181: this .wasCancelled = true;
182: setVisible(false);
183: }
184:
185: public boolean getWasCancelled() {
186: return wasCancelled;
187: }
188:
189: public String getSelection() {
190: if (customReplace != null)
191: return customReplace;
192:
193: if (table.getSelectedRow() == -1) {
194: // no selection, return the typed text, with @
195: return "@" + asp.getTextField().getText();
196: }
197: // return the selected table element followed by a space
198: int pos = stm.getIndexInUnsortedFromTablePos(table
199: .getSelectedRow());
200: String sel = "" + cm.getValueAt(pos, 0) + " ";
201: if (sel.startsWith("{"))
202: sel = sel.substring(1); // don't repeat several "{"
203: return sel;
204: }
205:
206: static class CompletionModel extends FineGrainTableModel {
207: List<Item> items = new ArrayList<Item>();
208: int columns = 2;
209:
210: public void initialize(boolean isInComment,
211: List<String>[] parsedMethodArgs) {
212: if (isInComment) {
213: columns = 1;
214:
215: items.add(new Item("@author", "", "1.0"));
216: items.add(new Item("@deprecated", "", "1.0"));
217: items.add(new Item("@exception", "", "1.0"));
218: items.add(new Item("@return", "", "1.0"));
219: items.add(new Item("@see",
220: "syntax: @see fullClassName or #methodName",
221: "1.0"));
222: items.add(new Item("@serial", "", "1,2"));
223: items.add(new Item("@serialData", "", "1.2"));
224: items.add(new Item("@serialField", "", "1.2"));
225: items.add(new Item("@since", "", "1.1"));
226: items.add(new Item("@throws", "", "1.2"));
227: items.add(new Item("@version", "", "1.0"));
228: //items.add(new Item("@beaninfo\n attribute: xxx\n description: yyy", "", "1.0"));
229:
230: items.add(new Item("{@value }", "", "1.4"));
231: items.add(new Item("{@code }", "", "1.5"));
232: items.add(new Item("{@docRoot }", "", "1.3"));
233: items.add(new Item("{@inheritDoc }", "", "1.4"));
234: items.add(new Item("{@link }", "", "1.2"));
235: items.add(new Item("{@linkplain }", "", "1.4"));
236: items.add(new Item("{@literal }", "", "1.5"));
237:
238: if (parsedMethodArgs != null) {
239: @SuppressWarnings("unchecked")
240: List<String> ls = parsedMethodArgs[1];
241: for (String pn : ls) {
242: items
243: .add(new Item("@param " + pn,
244: "parameter"));
245: }
246:
247: if (ls.size() > 0) {
248: // offer adding all
249: }
250: } else {
251: items.add(new Item("@param", ""));
252: }
253: } else {
254: columns = 2; // not ok, needs a structchanged... but also need to be improved... why not javadoc ?... TODO.
255: items
256: .add(new Item(
257: "@SuppressWarnings(\"unchecked\")",
258: "Suppress the compiler Xlint warnings for unchecked generic types."));
259: items.add(new Item("@Deprecated",
260: "Annotate deprecated methods"));
261: items
262: .add(new Item("@Override",
263: "Annotate methods that override the parent method."));
264: items
265: .add(new Item("@WebService",
266: "defines a web service (compiler wil generate WSDL)."));
267: items
268: .add(new Item(
269: "@SOAPBinding(style=SOAPBinding.Style.RPC)",
270: "Specifies the communication type for a WebService."));
271: items.add(new Item("@WebOperation(exclude=true)",
272: "Excludes the method from WebService."));
273: items.add(new Item("@org.junit.Test",
274: "mark a method to test. (Requires JUnit)."));
275:
276: if (MainEditorFrame.instance.sourcesTreePanel
277: .getTreeModel().knownAnnotations.size() > 0) {
278: // TODO: lock ?
279: for (String s : MainEditorFrame.instance.sourcesTreePanel
280: .getTreeModel().knownAnnotations) {
281: items.add(new Item("@" + s, "(in project)"));
282: }
283: }
284:
285: if (MainEditorFrame.instance.librariesPanel
286: .getTreeModel().knownAnnotations.size() > 0) {
287: // TODO: lock ?
288: for (String s : MainEditorFrame.instance.librariesPanel
289: .getTreeModel().knownAnnotations) {
290: if (s.startsWith("java.lang.")) {
291: s = s.substring(10);
292: }
293: items.add(new Item("@" + s,
294: "(found in classpath)"));
295: }
296: }
297:
298: // TODO: add also the inner annotations... (not declared as toplevel, iff contained in super or this scope).
299: }
300: this .setRowSelection(0, true);
301:
302: EventQueue.invokeLater(new Runnable() {
303: public void run() {
304: fireTableDataChanged();
305: fireTableModelHasChanged();
306: }
307: });
308:
309: }
310:
311: public Object getValueAt(int row, int col) {
312: if (row < 0 || row >= items.size())
313: return ""; //"bad row "+row;
314:
315: if (col == 0) {
316: return items.get(row).value;
317: }
318: return items.get(row).descr;
319: }
320:
321: public int getRowCount() {
322: return items.size();
323: }
324:
325: public int getColumnCount() {
326: return columns;
327: }
328:
329: @Override
330: public String getColumnName(int c) {
331: if (c == 0)
332: return "Item";
333: if (c == 1)
334: return "Descr";
335: return "??";
336: }
337: }
338:
339: static class Item {
340: final String value;
341: final String descr;
342: final String since;
343:
344: public Item(String value, String descr) {
345: this (value, descr, "1.0");
346: }
347:
348: public Item(String value, String descr, String since) {
349: this.value = value;
350: this.descr = descr;
351: this.since = since;
352: }
353: }
354:
355: }
|