001: package tide.editor.completions;
002:
003: import tide.classsyntax.JavaDocParser;
004: import java.io.File;
005: import tide.project.JDocRes;
006: import snow.utils.gui.Icons;
007: import tide.utils.SyntaxUtils;
008: import java.awt.FlowLayout;
009: import javax.swing.table.DefaultTableModel;
010: import snow.sortabletable.*;
011: import tide.editor.*;
012: import tide.sources.*;
013: import java.util.*;
014: import java.awt.BorderLayout;
015: import java.awt.Insets;
016: import java.awt.EventQueue;
017: import java.awt.event.*;
018: import javax.swing.*;
019: import javax.swing.event.*;
020: import javax.swing.text.*;
021: import javax.swing.text.html.*;
022:
023: /** Displays all packages and all classes ! and the javadoc for the selected.
024: * TODO: add Package version description tab, ... or reflection info, if any, for classes.
025: */
026: public final class ImportCompletionDialog extends JDialog implements
027: CompletionDialog {
028: //TODO: deprecations analysis !!
029: //TODO: insertTypeMode : offer adding missing import.
030:
031: final private int fontSize = UIManager.getFont("Label.font")
032: .getSize();
033:
034: // if true, special mode for inserting a type (not the import dialog)
035: final boolean insertTypeMode;
036:
037: private boolean wasCancelled = true; //TODO: fix this !
038: final private CompletionModel cm = new CompletionModel();
039: private final SortableTableModel stm = new SortableTableModel(cm);
040: final private MultiSearchPanel asp2 = new MultiSearchPanel("",
041: null, stm);
042: private final JTable table = new JTable(stm);
043: private final JPanel tablePanel = new JPanel(new BorderLayout(0, 0));
044: private final JEditorPane javaDocPane = new JEditorPane();
045: final private JScrollPane jdocPane;
046: private final JCheckBox viewDoc = new JCheckBox("Doc", true);
047: private final JSplitPane docSplitPane;
048:
049: private final boolean createWildcardImports;
050: private final boolean projectOnly;
051:
052: //TODO, currently buggy
053: // private final JCheckBox showSingleClasses;
054: private File browserLastBase = null;
055:
056: /** @param createWildcardImports if false, only the types are presented.
057: */
058: public ImportCompletionDialog(boolean insertTypeMode, JFrame owner,
059: int x, int y, final Document doc, final int docOffset,
060: boolean projectOnly, final String initialTextForBrowseMode) {
061: super (owner, (!insertTypeMode ? "Import Completion"
062: : "Insert type completion")
063: + (projectOnly ? " (project only)" : ""), true);
064:
065: this .insertTypeMode = insertTypeMode;
066: this .createWildcardImports = !insertTypeMode;
067: this .projectOnly = projectOnly;
068: this .setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
069:
070: // this.showSingleClasses = new JCheckBox("Hide packages", !createWildcardImports);
071:
072: setLayout(new BorderLayout(0, 0));
073:
074: stm.setSortedColumnAndOrder(-1, true); // avoid sorting.
075: stm.installGUI(table);
076: table.getSelectionModel().setSelectionMode(
077: ListSelectionModel.SINGLE_SELECTION);
078:
079: UniversalTableCellRenderer ute = new UniversalTableCellRenderer(
080: stm);
081: table.setDefaultRenderer(Object.class, ute);
082: table.setDefaultRenderer(String.class, ute);
083: tablePanel.add(new JScrollPane(table), BorderLayout.CENTER);
084:
085: JPanel pan = new JPanel();
086: pan.setLayout(new BoxLayout(pan, BoxLayout.X_AXIS));
087: add(pan, BorderLayout.NORTH);
088: pan.add(asp2);
089: if (initialTextForBrowseMode != null) {
090: asp2.setQueries(Query
091: .simpleSearchQuery(initialTextForBrowseMode));
092: }
093: pan.add(Box.createHorizontalStrut(5));
094: pan.add(viewDoc);
095:
096: jdocPane = new JScrollPane(javaDocPane);
097:
098: viewDoc.addActionListener(new ActionListener() {
099: public void actionPerformed(ActionEvent ae) {
100: MainEditorFrame.instance.globalProperties
101: .setBoolean("ViewJavaDocInCompletion", viewDoc
102: .isSelected());
103: jdocPane.setVisible(viewDoc.isSelected());
104: if (viewDoc.isSelected()) {
105: docSplitPane
106: .setDividerLocation(MainEditorFrame.instance.globalProperties
107: .getInteger(
108: "ImportCompletionDialog_divloc",
109: fontSize * 30));
110: }
111: }
112: });
113: viewDoc.setSelected(MainEditorFrame.instance.globalProperties
114: .getBoolean("ViewJavaDocInCompletion", true));
115: jdocPane.setVisible(viewDoc.isSelected());
116:
117: docSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
118: tablePanel, jdocPane);
119: javaDocPane.setEditable(false);
120:
121: add(docSplitPane, BorderLayout.CENTER);
122:
123: MainEditorFrame.instance.globalProperties
124: .setComponentSizeFromINIFile(this ,
125: "ImportCompletionDialog", fontSize * 40,
126: fontSize * 40, x, y);
127: this .setLocation(x, y);
128: docSplitPane
129: .setDividerLocation(MainEditorFrame.instance.globalProperties
130: .getInteger("ImportCompletionDialog_divloc",
131: fontSize * 30));
132: docSplitPane.setOneTouchExpandable(true);
133: /*
134: if(createWildcardImports)
135: {
136: pan.add(showSingleClasses);
137:
138: showSingleClasses.setMargin(new Insets(0,2,0,2));
139: showSingleClasses.setFocusPainted(false);
140: showSingleClasses.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae)
141: {
142: updateToggle();
143: } });
144: // todo: remember
145: //showSingleClasses.setSelected(true); // don't selects!
146: }*/
147:
148: final JTextField tf = asp2.getFirstTextField();
149: EventQueue.invokeLater(new Runnable() {
150: public void run() {
151: tf.requestFocus();
152: }
153: });
154: CompletionUtils
155: .controlTableWithFieldKeys(tf, table, this , "; ");
156:
157: table.addKeyListener(new KeyAdapter() {
158: @Override
159: public void keyTyped(KeyEvent ke) {
160: if (ke.getKeyCode() == KeyEvent.VK_UP)
161: return;
162: if (ke.getKeyCode() == KeyEvent.VK_DOWN)
163: return;
164: if (ke.getKeyCode() == KeyEvent.VK_ENTER)
165: return;
166:
167: char c = ke.getKeyChar(); // (only makes sense in keyTyped)
168: if (c == '\n')
169: return; // important, do not trigger search
170:
171: if (tf.getText().length() == 0) {
172: if (ke.getKeyCode() == KeyEvent.VK_BACK_SPACE
173: || ke.getKeyCode() == KeyEvent.VK_DELETE
174: || ke.getKeyCode() == KeyEvent.VK_LEFT) {
175: wasCancelled = true;
176: setVisible(false);
177: return;
178: }
179: }
180:
181: //if(Character.isLetterOrDigit(c))
182: {
183: tf.setText(tf.getText() + c);
184: asp2.doSearch();
185: }
186: }
187: });
188:
189: ((JComponent) getContentPane()).registerKeyboardAction(
190: new ActionListener() {
191: public void actionPerformed(ActionEvent ae) {
192: wasCancelled = true;
193: setVisible(false);
194: return;
195: }
196: }, "Escape", Accelerators.escape,
197: JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
198:
199: ((JComponent) getContentPane()).registerKeyboardAction(
200: new ActionListener() {
201: public void actionPerformed(ActionEvent ae) {
202: wasCancelled = false;
203: setVisible(false);
204: return;
205: }
206: }, "Enter", KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,
207: 0, true),
208: JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
209:
210: // immediately show the dialog, delay the construction of the model to later !!
211: // so the user have an immediate completion
212: Thread t = new Thread() {
213: public void run() {
214: cm.initialize();
215: //updateToggle();
216: }
217: };
218: t.setName("ImportCompletionDialog:init");
219: t.setPriority(Thread.NORM_PRIORITY - 1);
220: t.start();
221:
222: table.getSelectionModel().addListSelectionListener(
223: new ListSelectionListener() {
224: public void valueChanged(ListSelectionEvent lse) {
225: if (!viewDoc.isSelected())
226: return;
227:
228: javaDocPane.setContentType("text/html");
229: javaDocPane
230: .setText("<html><body></body></html>");
231: browserLastBase = null;
232:
233: int ind = stm
234: .getIndexInUnsortedFromTablePos(table
235: .getSelectedRow());
236: if (ind >= 0) {
237: String pn = cm.getPackageOrTypeAt(ind);
238: if (pn.endsWith(".*")) {
239: // package
240: JDocRes ps = MainEditorFrame.instance
241: .getActualProject()
242: .getJavaDocManager()
243: .getPackageSummary(
244: pn.substring(0, pn
245: .length() - 2));
246: if (ps != null) {
247: javaDocPane
248: .setContentType("text/html");
249: javaDocPane.setText(ps.part);
250: //System.out.println("\n*************HTMLPackage="+ps);
251: javaDocPane.setCaretPosition(0);
252:
253: browserLastBase = ps.f != null ? ps.f
254: : null;
255: }
256: //new Throwable().printStackTrace();
257: } else {
258: JDocRes ps = MainEditorFrame.instance
259: .getActualProject()
260: .getJavaDocManager()
261: .getClassSummary(pn);
262: if (ps != null) {
263: javaDocPane
264: .setContentType("text/html");
265: javaDocPane.setText(ps.part);
266: //System.out.println("\n************ HTMLClass="+cont);
267: //no, the text appears at the end !
268: javaDocPane.setCaretPosition(0); // but yes, ...
269:
270: browserLastBase = ps.f;
271: }
272: }
273: }
274: }
275: });
276: /*OLD
277: javaDocPane.addHyperlinkListener(new HyperlinkListener()
278: {
279:
280: public void hyperlinkUpdate(HyperlinkEvent e)
281: {
282: System.out.println("HLE url= "+e.getURL());
283: if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED)
284: {
285: System.out.println("EVT "+e+" "+e.getURL());
286:
287: JEditorPane pane = (JEditorPane) e.getSource();
288: if (e instanceof HTMLFrameHyperlinkEvent) {
289: HTMLFrameHyperlinkEvent evt = (HTMLFrameHyperlinkEvent)e;
290: HTMLDocument doc = (HTMLDocument)pane.getDocument();
291:
292: doc.processHTMLFrameHyperlinkEvent(evt);
293: } else {
294: try {
295: //TODO: resolve relative names !
296: System.out.println("URL: "+e+", "+e.getURL());
297: pane.setPage(e.getURL());
298: } catch (Throwable t) {
299: t.printStackTrace();
300: }
301: }
302: }
303: }
304: });
305: */
306:
307: javaDocPane.addHyperlinkListener(new HyperlinkListener() {
308: public void hyperlinkUpdate(HyperlinkEvent e) {
309: if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
310: JEditorPane pane = (JEditorPane) e.getSource();
311: if (e instanceof HTMLFrameHyperlinkEvent) {
312: // never occurs ??
313: HTMLFrameHyperlinkEvent evt = (HTMLFrameHyperlinkEvent) e;
314: HTMLDocument doc = (HTMLDocument) pane
315: .getDocument();
316: doc.processHTMLFrameHyperlinkEvent(evt);
317: } else {
318: try {
319: if (e.getURL() != null) {
320: pane.setPage(e.getURL());
321: return;
322: }
323:
324: String relink = e.getDescription(); // ../../Object.html#wait(long)
325: if (relink != null
326: && browserLastBase != null) {
327:
328: String tag = null;
329: String query = null; // TODO: handle
330: int pos = relink.indexOf('#');
331: File nf = null;
332: if (pos >= 0) {
333: tag = relink.substring(pos + 1);
334: relink = relink.substring(0, pos);
335: }
336:
337: pos = relink.indexOf('?'); // maybe in the tag ??
338: if (pos >= 0) {
339: query = relink.substring(pos + 1);
340: relink = relink.substring(0, pos);
341: }
342:
343: if (relink.length() == 0) {
344: nf = browserLastBase; // pure tag
345: } else {
346: nf = new File(browserLastBase
347: .getParentFile(), relink);
348: nf = nf.getCanonicalFile();
349: }
350:
351: if (!nf.exists()) {
352: // TODO: try from all known doc roots...
353:
354: pane.setText("<html>Not Found:"
355: + "<br> relink=" + relink
356: + "<br> tag=" + tag
357: + "<br> file=" + nf
358: + "<br> base="
359: + browserLastBase);
360: // +"<br> first base="+showedItem.jdoc.f);
361: return;
362: }
363:
364: String cont = JavaDocParser
365: .getHTMLContent(nf);
366: if (cont != null) {
367: cont = JavaDocParser
368: .replaceImages(cont);
369: if (tag != null) {
370: pos = cont.indexOf("<A NAME=\""
371: + tag + "\"");
372: if (pos > 0) {
373: cont = cont.substring(pos);
374: }
375: }
376: pane.setText(cont);
377: pane.setCaretPosition(0);
378: }
379:
380: }
381:
382: } catch (Throwable t) {
383: t.printStackTrace();
384: }
385: }
386: }
387: }
388: });
389:
390: if (insertTypeMode) {
391: addFactoryBarForTypeInsert();
392: }
393:
394: insertSimpleTypeName = insertTypeMode;
395:
396: this .setVisible(true); // MODAL
397:
398: MainEditorFrame.instance.globalProperties
399: .saveComponentSizeInINIFile(this ,
400: "ImportCompletionDialog");
401: if (viewDoc.isSelected()) {
402: MainEditorFrame.instance.globalProperties.setInteger(
403: "ImportCompletionDialog_divloc", docSplitPane
404: .getDividerLocation());
405: }
406:
407: } // initialize
408:
409: boolean insertSimpleTypeName = false;
410: boolean insertInstance = false;
411:
412: /** Adds the buttons to create simple name insert.
413: */
414: private void addFactoryBarForTypeInsert() {
415: // only if ElementKind.Class
416: JPanel fb = new JPanel(new FlowLayout(FlowLayout.LEFT, 1, 1));
417: tablePanel.add(fb, BorderLayout.SOUTH);
418: JButton insS = new JButton("Insert full class name");
419: insS.setMargin(new Insets(0, 2, 0, 2));
420: fb.add(insS);
421: insS.addActionListener(new ActionListener() {
422: public void actionPerformed(ActionEvent ae) {
423: //Item showedItem = cm.getItem(0);
424: //if(showedItem==null) return;
425: if (table.getSelectedRowCount() == 0)
426: return;
427: insertSimpleTypeName = false;
428: selectAndQuit();
429:
430: }
431: });
432:
433: JButton insClass = new JButton("Create instance");
434: insClass.setMargin(new Insets(0, 2, 0, 2));
435: fb.add(insClass);
436: insClass.addActionListener(new ActionListener() {
437: public void actionPerformed(ActionEvent ae) {
438: //Item showedItem = cm.getItem(0);
439: //if(showedItem==null) return;
440: if (table.getSelectedRowCount() == 0)
441: return;
442: insertInstance = true;
443: insertSimpleTypeName = true;
444: selectAndQuit();
445: }
446: });
447:
448: JButton jmpClass = new JButton("Jump to...",
449: Icons.sharedRightArrow);
450: jmpClass.setMargin(new Insets(0, 2, 0, 2));
451: fb.add(jmpClass);
452: jmpClass.addActionListener(new ActionListener() {
453: public void actionPerformed(ActionEvent ae) {
454: //Item showedItem = cm.getItem(0);
455: //if(showedItem==null) return;
456: if (table.getSelectedRowCount() == 0)
457: return;
458: int pos = stm.getIndexInUnsortedFromTablePos(table
459: .getSelectedRow());
460: String sel = "" + cm.getValueAt(pos, 0);
461:
462: // OK, let also the $, it displays the decompiled file.
463: // the user may then select the parent file source (if existing) to see the source...
464: FileItem fi = MainEditorFrame.instance.getFileItem(sel,
465: null);
466:
467: if (fi != null) {
468: cancelDialog();
469: MainEditorFrame.instance
470: .setSourceOrItemToEditOrView(fi, true);
471: } else {
472: MainEditorFrame.debugOut("FileItem not found: "
473: + sel);
474: }
475: }
476: });
477: }
478:
479: /*
480: private void updateToggle()
481: {
482: showSingleClasses.setText( showSingleClasses.isSelected() ? "show packages" : "hide packages");
483: if(showSingleClasses.isSelected())
484: {
485: cm.addSingleTypes();
486: }
487: else
488: {
489: cm.removePackages();
490: }
491: }*/
492:
493: public void selectAndQuit() {
494: this .wasCancelled = false;
495: setVisible(false);
496: }
497:
498: public void cancelDialog() {
499: this .wasCancelled = true;
500: setVisible(false);
501: clear();
502: }
503:
504: public boolean getWasCancelled() {
505: return wasCancelled;
506: }
507:
508: public String getSelectionAndClear() {
509: if (table.getSelectedRow() == -1)
510: new Throwable().printStackTrace();
511:
512: if (table.getSelectedRow() == -1 || wasCancelled) {
513: clear();
514: // no selection, return the typed text.
515: return asp2.getFirstTextField().getText();
516: }
517:
518: // return the selected table element
519: int pos = stm.getIndexInUnsortedFromTablePos(table
520: .getSelectedRow());
521: String sel = "" + cm.getValueAt(pos, 0) + ";";
522:
523: clear();
524:
525: if (insertSimpleTypeName) {
526: int posPt = sel.lastIndexOf('.');
527: if (posPt > 0) {
528: sel = sel.substring(posPt + 1);
529: }
530: if (sel.endsWith(";")) {
531: sel = sel.substring(0, sel.length() - 1);
532: }
533: }
534:
535: sel = sel.replace('$', '.');
536:
537: if (insertInstance) {
538: sel = sel + " "
539: + SyntaxUtils.createVariableNameFromClassName(sel)
540: + " = new " + sel + "();";
541: }
542:
543: // internal classes are shown with $ (to know that they are internal, but the path is with points.)
544: return sel;
545: }
546:
547: public void clear() {
548: stm.removeOldListeners();
549: table.setModel(new DefaultTableModel());
550: cm.clearModel();
551:
552: }
553:
554: class CompletionModel extends FineGrainTableModel {
555: List<Item> items = new ArrayList<Item>();
556: boolean singleClassesAdded = false;
557:
558: public void clearModel() {
559: items.clear();
560: }
561:
562: /** Called in a separate thread TODO: kill if escaped...
563: */
564: public void initialize() {
565: List<SourceFile> dirs = new ArrayList<SourceFile>();
566: SourcesTreeModel sotm = MainEditorFrame.instance.sourcesTreePanel
567: .getTreeModel();
568: sotm.getAllDirectoriesRecurse_depthFirst(sotm
569: .getRootSource(), dirs);
570:
571: if (createWildcardImports) {
572: for (SourceFile sf : dirs) {
573: String jn = sf.getJavaName();
574: if (jn.length() > 0
575: && sf.hasPackageDirectJavaChilds()) // sometimes not compiling if importing empty dirs !
576: {
577: items.add(new Item(jn + ".*", "", "package")); // from="" for project sources, added in the view
578: }
579: }
580: }
581:
582: if (!projectOnly) {
583: List<LibFileItem> dirsl = new ArrayList<LibFileItem>();
584: LibrariesTreeModel ltm = MainEditorFrame.instance.librariesPanel
585: .getTreeModel();
586: ltm.getAllDirsRecurse(dirsl, ltm.root);
587:
588: if (createWildcardImports) {
589: for (LibFileItem lf : dirsl) {
590: String jn = lf.getJavaName();
591: if (jn.length() > 0
592: && lf.hasPackageDirectJavaChilds()) // sometimes not compiling if importing empty dirs !
593: {
594: items.add(new Item(jn + ".*", lf
595: .getRootArchiveName(), "package"));
596: }
597: }
598: }
599: }
600:
601: addSingleTypes();
602:
603: if (items.size() > 0) {
604: this .setRowSelection(0, true);
605: update();
606: }
607:
608: }
609:
610: /** Not only .* but each class also !
611: */
612: public void addSingleTypes() {
613: if (singleClassesAdded)
614: return; // add only once !
615:
616: SourcesTreeModel stm = MainEditorFrame.instance.sourcesTreePanel
617: .getTreeModel();
618: List<SourceFile> sfs = stm.getAllSourceFiles(false); // not the ignored ones
619:
620: for (SourceFile sf : sfs) {
621: if (sf.isJavaFile()) {
622: String jn = sf.getJavaName();
623: String kind = null;
624: if (sf.topKind == SourceFile.Kind.Interface) {
625: kind = "INT";
626: } else if (sf.topKind == SourceFile.Kind.Annotation) {
627: kind = "ANN";
628: }
629:
630: items.add(new Item(jn, "", kind));
631: }
632: }
633:
634: if (!projectOnly) {
635: Vector<LibFileItem> sfsl = new Vector<LibFileItem>();
636: LibrariesTreeModel ltm = MainEditorFrame.instance.librariesPanel
637: .getTreeModel();
638: ltm.getAllFilesRecurse(sfsl, ltm.root, true); // only java files (class and .java)
639:
640: for (LibFileItem lf : sfsl) {
641: if (lf.isJavaFile()) {
642: String jn = lf.getJavaName();
643: String kind = null;
644: if (MainEditorFrame.instance.librariesPanel
645: .getTreeModel().knownAnnotations
646: .contains(jn)) {
647: kind = "ANN";
648: } else if (MainEditorFrame.instance.librariesPanel
649: .getTreeModel().knownInterfaces
650: .contains(jn)) {
651: kind = "INT";
652: }
653:
654: items.add(new Item(jn, lf.getRootArchiveName(),
655: kind));
656: }
657: }
658: }
659: singleClassesAdded = true;
660:
661: if (items.size() > 0) {
662: this .setRowSelection(0, true);
663:
664: update();
665: }
666: }
667:
668: private void update() {
669: EventQueue.invokeLater(new Runnable() {
670: public void run() {
671: fireTableDataChanged();
672: fireTableModelHasChanged();
673: }
674: });
675: }
676:
677: public void removePackages() {
678: List<Item> rem = new ArrayList<Item>();
679: for (int i = items.size() - 1; i >= 0; i--) {
680: if (items.get(i).value.endsWith("*")) {
681: rem.add(items.get(i));
682: }
683: }
684: if (rem.size() > 0) {
685: items.removeAll(rem);
686: update();
687: }
688: }
689:
690: public Object getValueAt(int row, int col) {
691: if (row < 0 || row >= items.size())
692: return ""; //"bad row "+row;
693:
694: if (col == 0)
695: return items.get(row).value;
696: if (col == 1) {
697: if (items.get(row).descr.length() == 0)
698: return "project";
699: return items.get(row).descr;
700: }
701: if (col == 2) {
702: if (items.get(row).kind == null)
703: return "";
704: return items.get(row).kind;
705: }
706:
707: return "?";
708: }
709:
710: public Item getItemAt(int row) {
711: if (row < 0 || row >= items.size())
712: return null;
713: return items.get(row);
714: }
715:
716: public String getPackageOrTypeAt(int row) {
717: if (row < 0 || row >= items.size())
718: return "ERROR: bad row " + row;
719: return items.get(row).value;
720: }
721:
722: @Override
723: public String getColumnName(int col) {
724: if (col == 0)
725: return "package or type";
726: if (col == 1)
727: return "from";
728: if (col == 2)
729: return "kind"; // interface, class, annotation (INT, -, ANN)
730: return "?";
731: }
732:
733: int[] COLUMN_PREFERED_SIZES = new int[] { 30, 10, 2 };
734:
735: @Override
736: public int getPreferredColumnWidth(int column) {
737: if (column >= 0 && column < COLUMN_PREFERED_SIZES.length)
738: return COLUMN_PREFERED_SIZES[column];
739: return -1;
740: }
741:
742: @Override
743: public Class getColumnClass(int col) {
744: return String.class;
745: }
746:
747: public int getRowCount() {
748: return items.size();
749: }
750:
751: public int getColumnCount() {
752: return 3;
753: }
754: }
755:
756: /** class or package
757: */
758: static class Item {
759: String value;
760: String descr;
761: String kind;
762:
763: public Item(String value, String descr, String kind) {
764: this .value = value;
765: this .descr = descr;
766: this .kind = kind;
767: //if(deprecated) value+=" (Deprecated)"; // NOT yet... we don't know before reflecting...
768: }
769: }
770: }
|