improved templates
[phpeclipse.git] / archive / net.sourceforge.phpeclipse.wiki / src / net / sourceforge / phpeclipse / wiki / editor / WikiCompletionProcessor.java
1 /***********************************************************************************************************************************
2  * Copyright (c) 2000, 2004 IBM Corporation and others. All rights reserved. This program and the accompanying materials are made
3  * available under the terms of the Common Public License v1.0 which accompanies this distribution, and is available at
4  * http://www.eclipse.org/legal/cpl-v10.html
5  * 
6  * Contributors: IBM Corporation - initial API and implementation
7  **********************************************************************************************************************************/
8 package net.sourceforge.phpeclipse.wiki.editor;
9
10 import java.util.ArrayList;
11 import java.util.Arrays;
12 import java.util.Collections;
13 import java.util.Comparator;
14 import java.util.List;
15
16 import net.sourceforge.phpeclipse.wiki.editor.model.WikipediaSection;
17 import net.sourceforge.phpeclipse.wiki.editor.model.WikipediaText;
18 import net.sourceforge.phpeclipse.wiki.sql.WikipediaDB;
19
20 import org.eclipse.jface.resource.ImageDescriptor;
21 import org.eclipse.jface.resource.ImageRegistry;
22 import org.eclipse.jface.text.BadLocationException;
23 import org.eclipse.jface.text.IDocument;
24 import org.eclipse.jface.text.IRegion;
25 import org.eclipse.jface.text.ITextSelection;
26 import org.eclipse.jface.text.ITextViewer;
27 import org.eclipse.jface.text.Region;
28 import org.eclipse.jface.text.TextUtilities;
29 import org.eclipse.jface.text.contentassist.CompletionProposal;
30 import org.eclipse.jface.text.contentassist.ICompletionProposal;
31 import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
32 import org.eclipse.jface.text.contentassist.IContextInformation;
33 import org.eclipse.jface.text.contentassist.IContextInformationValidator;
34 import org.eclipse.jface.text.templates.DocumentTemplateContext;
35 import org.eclipse.jface.text.templates.Template;
36 import org.eclipse.jface.text.templates.TemplateContext;
37 import org.eclipse.jface.text.templates.TemplateContextType;
38 import org.eclipse.jface.text.templates.TemplateException;
39 import org.eclipse.jface.text.templates.TemplateProposal;
40 import org.eclipse.swt.graphics.Image;
41
42 public class WikiCompletionProcessor implements IContentAssistProcessor {
43
44   static class StringComparator implements Comparator {
45     public int compare(Object o1, Object o2) {
46       String s1 = (String) o1;
47       String s2 = (String) o2;
48       return s1.compareTo(s2);
49       //        return s1.toUpperCase().compareTo(s2.toUpperCase());
50     }
51
52     public boolean equals(Object o) {
53       //      String s = (String) o;
54       return compare(this, o) == 0;
55     }
56   }
57
58   private static final String TEMPLATE_ICON = "icons/template.gif";
59
60   //  private static TreeSet TITLES_SET = null;
61   private static final String WIKIPEDIA_TEMPLATE_CTX = "net.sourceforge.phpeclipse.wiki.editor.templates";
62
63   private static final class ProposalComparator implements Comparator {
64     public int compare(Object o1, Object o2) {
65       return ((TemplateProposal) o2).getRelevance() - ((TemplateProposal) o1).getRelevance();
66     }
67   }
68
69   private static final Comparator fgProposalComparator = new ProposalComparator();
70
71   private final WikiEditor fEditor;
72
73   public WikiCompletionProcessor(WikiEditor editor) {
74     fEditor = editor;
75   }
76
77   //  private static void readFile(String filename) {
78   //    TITLES_SET = new TreeSet(new StringComparator());
79   //    FileReader fileReader;
80   //    try {
81   //      fileReader = new FileReader(filename);
82   //      BufferedReader bufferedReader = new BufferedReader(fileReader);
83   //      LineTokenizer lineTokenizer = new LineTokenizer();
84   //      StringBuffer line = new StringBuffer(1024);
85   //      while (lineTokenizer.getToken(line, bufferedReader)) {
86   //        if (line.length() == 0) {
87   //          // this should not happen
88   //        } else {
89   //          TITLES_SET.add(line.toString());
90   //          line.delete(0, line.length());
91   //        }
92   //      }
93   //      bufferedReader.close();
94   //    } catch (FileNotFoundException e) {
95   //      // ignore this
96   //      // TODO DialogBox which asks the user if she/he likes to build new index?
97   //    } catch (IOException e) {
98   //      // TODO Auto-generated catch block
99   //      e.printStackTrace();
100   //    }
101   //  }
102
103   public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) {
104     WikipediaSection section = fEditor.getSection();
105     if (section == null)
106       return null;
107
108     ITextSelection selection = (ITextSelection) viewer.getSelectionProvider().getSelection();
109     // adjust offset to start of normalized selection:
110     if (selection.getOffset() != offset)
111       offset = selection.getOffset();
112
113     String prefix = getPrefix(viewer, offset);
114     Region region = new Region(offset - prefix.length(), prefix.length() + selection.getLength());
115     List result = new ArrayList();
116
117     if (prefix.length() > 2) {
118       if (WikiEditorPlugin.fWikiDB == null) {
119         try {
120           WikiEditorPlugin.fWikiDB = new WikipediaDB();
121         } catch (Exception ex1) {
122           //        ex1.printStackTrace(); // could not start db
123           WikiEditorPlugin.fWikiDB = null;
124         }
125       }
126       if (WikiEditorPlugin.fWikiDB != null) {
127         try {
128           ArrayList list = WikiEditorPlugin.fWikiDB.queryPrefixTitle(prefix);
129           ICompletionProposal[] titleProposals = computeTitleProposals(list, region, viewer);
130           result.addAll(Arrays.asList(titleProposals));
131         } catch (Exception ex1) {
132           //    ex1.printStackTrace(); // could not start db
133           WikiEditorPlugin.fWikiDB = null;
134         }
135       }
136     }
137     //    if (TITLES_SET==null) {
138     // TODO make this a preference
139     //      readFile("c:\\temp\\titles.txt");
140     //    }
141     //    if (TITLES_SET.size()>0 && prefix.length()>3) {
142     //      SortedSet subSet = TITLES_SET.subSet(prefix, prefix + '\255');
143     //      Iterator iter = subSet.iterator();
144     //      ArrayList list;
145     //      String title;
146     //      int maxProposals = 200;
147     //      while (iter.hasNext()) {
148     //        title = (String) iter.next();
149     //        if (title.toLowerCase().startsWith(prefix.toLowerCase())) {
150     //          result.add(title);
151     //        }
152     //        if (maxProposals-- < 0) {
153     //          break;
154     //        }
155     //      }
156     //    }
157
158     ICompletionProposal[] templateProposals = computeTemplateProposals(viewer, region, section, prefix);
159     //    ICompletionProposal[] ingredientProposals = computeIngredientsProposals(viewer, region, recipe, prefix);
160     //    ICompletionProposal[] titleProposals = computeTitleProposals(viewer, region, recipe, prefix);
161
162     //    result.addAll(Arrays.asList(ingredientProposals));
163     result.addAll(Arrays.asList(templateProposals));
164     //    result.addAll(Arrays.asList(titleProposals));
165
166     return (ICompletionProposal[]) result.toArray(new ICompletionProposal[result.size()]);
167   }
168
169   private ICompletionProposal[] computeTitleProposals(ArrayList list, IRegion region, ITextViewer viewer) {
170     ICompletionProposal[] arr = new ICompletionProposal[list.size()];
171     //    String lineDelimiter = TextUtilities.getDefaultLineDelimiter(viewer.getDocument());
172     String temp;
173     for (int i = 0; i < arr.length; i++) {
174       temp = (String) list.get(i);
175       arr[i] = new CompletionProposal(temp, region.getOffset(), region.getLength(), temp.length(), null, temp,
176           null, null);
177     }
178     return arr;
179   }
180
181   private TemplateContextType getContextType(WikipediaSection section, int offset) {
182     return WikiEditorPlugin.getDefault().getContextTypeRegistry().getContextType(WIKIPEDIA_TEMPLATE_CTX);
183   }
184
185   /**
186    * Creates a concrete template context for the given region in the document. This involves finding out which context fType is
187    * valid at the given location, and then creating a context of this fType. The default implementation returns a
188    * <code>DocumentTemplateContext</code> for the context fType at the given location.
189    * 
190    * @param viewer
191    *          the viewer for which the context is created
192    * @param region
193    *          the region into <code>document</code> for which the context is created
194    * @return a template context that can handle template insertion at the given location, or <code>null</code>
195    */
196   private TemplateContext createContext(ITextViewer viewer, IRegion region, WikipediaSection recipe) {
197     TemplateContextType contextType = getContextType(recipe, region.getOffset());
198     if (contextType != null) {
199       IDocument document = viewer.getDocument();
200       return new DocumentTemplateContext(contextType, document, region.getOffset(), region.getLength());
201     }
202     return null;
203   }
204
205   private ICompletionProposal[] computeTemplateProposals(ITextViewer viewer, IRegion region, WikipediaSection recipe, String prefix) {
206     TemplateContext context = createContext(viewer, region, recipe);
207     if (context == null)
208       return new ICompletionProposal[0];
209
210     ITextSelection selection = (ITextSelection) viewer.getSelectionProvider().getSelection();
211     context.setVariable("selection", selection.getText()); // name of the selection variables {line, word}_selection
212
213     String id = context.getContextType().getId();
214     Template[] templates = WikiEditorPlugin.getDefault().getTemplateStore().getTemplates(id);
215
216     List matches = new ArrayList();
217     for (int i = 0; i < templates.length; i++) {
218       Template template = templates[i];
219       try {
220         context.getContextType().validate(template.getPattern());
221       } catch (TemplateException e) {
222         continue;
223       }
224       //      int relevance = getRelevance(template, prefix);
225       //      if (relevance > 0) {
226       matches.add(new TemplateProposal(template, context, region, getImage(template), 1));
227       //      }
228     }
229
230     Collections.sort(matches, fgProposalComparator);
231
232     return (ICompletionProposal[]) matches.toArray(new ICompletionProposal[matches.size()]);
233   }
234
235   /**
236    * Returns the relevance of a template given a prefix. The default implementation returns a number greater than zero if the
237    * template name starts with the prefix, and zero otherwise.
238    * 
239    * @param template
240    *          the template to compute the relevance for
241    * @param prefix
242    *          the prefix after which content assist was requested
243    * @return the relevance of <code>template</code>
244    * @see #getPrefix(ITextViewer, int)
245    */
246   private int getRelevance(Template template, String prefix) {
247     if (template.getName().startsWith(prefix))
248       return 90;
249     return 0;
250   }
251
252   private String getPrefix(ITextViewer viewer, int offset) {
253     int i = offset;
254     IDocument document = viewer.getDocument();
255     if (i > document.getLength())
256       return "";
257
258     try {
259       while (i > 0) {
260         char ch = document.getChar(i - 1);
261         if (!Character.isLetterOrDigit(ch) && (ch != ':') && (ch != '_'))
262           break;
263         i--;
264       }
265
266       return document.get(i, offset - i);
267     } catch (BadLocationException e) {
268       return "";
269     }
270   }
271
272   /**
273    * Always return the default image.
274    */
275   private Image getImage(Template template) {
276     ImageRegistry registry = WikiEditorPlugin.getDefault().getImageRegistry();
277     Image image = registry.get(TEMPLATE_ICON);
278     if (image == null) {
279       ImageDescriptor desc = WikiEditorPlugin.imageDescriptorFromPlugin("net.sourceforge.phpeclipse.wiki.editor", TEMPLATE_ICON);
280       registry.put(TEMPLATE_ICON, desc);
281       image = registry.get(TEMPLATE_ICON);
282     }
283     return image;
284   }
285
286   public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) {
287     return null;
288   }
289
290   public char[] getCompletionProposalAutoActivationCharacters() {
291     return null;
292   }
293
294   public char[] getContextInformationAutoActivationCharacters() {
295     return null;
296   }
297
298   public String getErrorMessage() {
299     return null;
300   }
301
302   public IContextInformationValidator getContextInformationValidator() {
303     return null;
304   }
305 }