package tide.editor.completions;
import tide.editor.MainEditorFrame;
import snow.sortabletable.*;
import tide.utils.SyntaxUtils;
import java.util.*;
import java.awt.BorderLayout;
import java.awt.Insets;
import java.awt.EventQueue;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;
/** Javadoc or annotations, depending on context.
* BAD NAME, should not be Ampersand but "At"
* TODO: fetch available annotations (types).
*/
public class AmpersandCompletionDialog extends JDialog implements CompletionDialog
{
final private CompletionModel cm = new CompletionModel();
private final SortableTableModel stm = new SortableTableModel(cm);
final private AdvancedSearchPanel asp = new AdvancedSearchPanel("@ ", null, stm, false);
private final JTable table = new JTable(stm);
private final JPanel optsPanel = new JPanel();
private final String preceedingTokenOfInterrest;
private boolean wasCancelled = true;
public AmpersandCompletionDialog( final boolean inComment, JFrame owner, int x, int y,
final Document doc, final int docOffset, final String preceedingTokenOfInterrest )
{
super(owner, "Completion", true);
this.preceedingTokenOfInterrest = preceedingTokenOfInterrest;
setLayout(new BorderLayout(0,0));
add(new JScrollPane(table), BorderLayout.CENTER);
stm.installGUI(table);
stm.setSortedColumnAndOrder(-1,true); // avoid sorting.
table.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
add(optsPanel, BorderLayout.SOUTH);
optsPanel.setVisible(false);
add(asp, BorderLayout.NORTH);
final int fontSize = UIManager.getFont("Label.font").getSize();
// fixed, but fontsize relative size :
this.setSize( fontSize*45 ,fontSize*30 );
this.setLocation(x,y);
CompletionUtils.controlTableWithFieldKeys(asp.getTextField(), table, this, "");
table.addKeyListener(new KeyAdapter()
{
@Override public void keyTyped(KeyEvent ke)
{
char c = ke.getKeyChar();
if(Character.isLetterOrDigit(c))
{
asp.getTextField().setText( asp.getTextField().getText()+c );
asp.doSearch();
}
}
});
((JComponent) getContentPane()).registerKeyboardAction(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
wasCancelled = true;
setVisible(false);
return;
}
}, "Escape", KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, true), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
((JComponent) getContentPane()).registerKeyboardAction(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
wasCancelled = false;
setVisible(false);
return;
}
}, "Enter", KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, true), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
// immediately show the dialog, delay the construction of the model to later !!
// so the user have an immediate completion
Thread t = new Thread()
{
public void run()
{
List<String>[] args = null;
try
{
if(inComment)
{
String txtAfter= doc.getText(docOffset,doc.getLength()-docOffset); //offset,length
args = SyntaxUtils.parseSignatureAfterForJavaDoc(txtAfter, 0);
if(args!=null && args[1]!=null && args[1].size()>0)
{
offerAddingAll(args);
}
else
{
// System.out.println("NO arg compl");
}
}
}
catch(Exception e)
{
e.printStackTrace();
}
// Quick !
cm.initialize(inComment, args);
EventQueue.invokeLater(new Runnable() { public void run() {
setTitle( (inComment ? "Javadoc tag completion" :"Annotation completion") );
}});
}
};
t.setPriority(Thread.NORM_PRIORITY-1);
t.start();
this.setVisible(true);
} // initialize
String customReplace = null;
/** Generates the param tags for all entries...
*/
private void offerAddingAll(final List<String>[] params)
{
EventQueue.invokeLater(new Runnable() { public void run() {
//System.out.println("adding all params: "+Arrays.toString(params));
JButton addAll = new JButton("Add javadoc tags for all parameters");
addAll.setMargin(new Insets(0,1,0,1));
addAll.setFocusPainted(false);
optsPanel.add(addAll);
optsPanel.setPreferredSize(optsPanel.getPreferredSize());
optsPanel.setVisible(true);
// must restitue the focus !
asp.getTextField().requestFocus();
addAll.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae)
{
StringBuilder sb = new StringBuilder();
for( String pn: params[1] )
{
// TODO: look for the correct indent !
sb.append("\n * @param "+pn+" ");
}
customReplace = ""+sb;
selectAndQuit();
} });
}});
}
public void selectAndQuit()
{
this.wasCancelled = false;
setVisible(false);
}
public void cancelDialog()
{
this.wasCancelled = true;
setVisible(false);
}
public boolean getWasCancelled()
{
return wasCancelled;
}
public String getSelection()
{
if(customReplace!=null) return customReplace;
if(table.getSelectedRow()==-1)
{
// no selection, return the typed text, with @
return "@"+asp.getTextField().getText();
}
// return the selected table element followed by a space
int pos = stm.getIndexInUnsortedFromTablePos( table.getSelectedRow() );
String sel = ""+cm.getValueAt(pos,0)+" ";
if(sel.startsWith("{")) sel = sel.substring(1); // don't repeat several "{"
return sel;
}
static class CompletionModel extends FineGrainTableModel
{
List<Item> items = new ArrayList<Item>();
int columns = 2;
public void initialize(boolean isInComment, List<String>[] parsedMethodArgs)
{
if(isInComment)
{
columns=1;
items.add(new Item("@author", "", "1.0"));
items.add(new Item("@deprecated", "", "1.0"));
items.add(new Item("@exception", "", "1.0"));
items.add(new Item("@return", "", "1.0"));
items.add(new Item("@see", "syntax: @see fullClassName or #methodName", "1.0"));
items.add(new Item("@serial", "", "1,2"));
items.add(new Item("@serialData", "","1.2"));
items.add(new Item("@serialField", "","1.2"));
items.add(new Item("@since", "", "1.1"));
items.add(new Item("@throws", "", "1.2"));
items.add(new Item("@version", "", "1.0"));
//items.add(new Item("@beaninfo\n attribute: xxx\n description: yyy", "", "1.0"));
items.add(new Item("{@value }", "", "1.4"));
items.add(new Item("{@code }", "", "1.5"));
items.add(new Item("{@docRoot }", "", "1.3"));
items.add(new Item("{@inheritDoc }","","1.4"));
items.add(new Item("{@link }", "", "1.2"));
items.add(new Item("{@linkplain }","", "1.4"));
items.add(new Item("{@literal }", "", "1.5"));
if(parsedMethodArgs!=null)
{
@SuppressWarnings("unchecked")
List<String> ls = parsedMethodArgs[1];
for(String pn : ls)
{
items.add(new Item("@param "+pn, "parameter"));
}
if(ls.size()>0)
{
// offer adding all
}
}
else
{
items.add(new Item("@param", ""));
}
}
else
{
columns=2; // not ok, needs a structchanged... but also need to be improved... why not javadoc ?... TODO.
items.add(new Item("@SuppressWarnings(\"unchecked\")", "Suppress the compiler Xlint warnings for unchecked generic types."));
items.add(new Item("@Deprecated", "Annotate deprecated methods"));
items.add(new Item("@Override", "Annotate methods that override the parent method."));
items.add(new Item("@WebService", "defines a web service (compiler wil generate WSDL)."));
items.add(new Item("@SOAPBinding(style=SOAPBinding.Style.RPC)", "Specifies the communication type for a WebService."));
items.add(new Item("@WebOperation(exclude=true)", "Excludes the method from WebService."));
items.add(new Item("@org.junit.Test", "mark a method to test. (Requires JUnit)."));
if(MainEditorFrame.instance.sourcesTreePanel.getTreeModel().knownAnnotations.size()>0)
{
// TODO: lock ?
for(String s : MainEditorFrame.instance.sourcesTreePanel.getTreeModel().knownAnnotations)
{
items.add(new Item("@"+s, "(in project)"));
}
}
if(MainEditorFrame.instance.librariesPanel.getTreeModel().knownAnnotations.size()>0)
{
// TODO: lock ?
for(String s : MainEditorFrame.instance.librariesPanel.getTreeModel().knownAnnotations)
{
if(s.startsWith("java.lang."))
{
s = s.substring(10);
}
items.add(new Item("@"+s, "(found in classpath)"));
}
}
// TODO: add also the inner annotations... (not declared as toplevel, iff contained in super or this scope).
}
this.setRowSelection(0,true);
EventQueue.invokeLater(new Runnable() { public void run() {
fireTableDataChanged();
fireTableModelHasChanged();
}});
}
public Object getValueAt(int row, int col)
{
if(row<0 || row>=items.size()) return ""; //"bad row "+row;
if(col==0)
{
return items.get(row).value;
}
return items.get(row).descr;
}
public int getRowCount() { return items.size(); }
public int getColumnCount() { return columns; }
@Override
public String getColumnName(int c)
{
if(c==0) return "Item";
if(c==1) return "Descr";
return "??";
}
}
static class Item
{
final String value;
final String descr;
final String since;
public Item(String value, String descr)
{
this(value, descr, "1.0");
}
public Item(String value, String descr, String since)
{
this.value = value;
this.descr = descr;
this.since = since;
}
}
}
|