8ea69f776b240e4c99063756e8543195abe0f743
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpeclipse / phpeditor / php / PHPCompletionProcessor.java
1 /**********************************************************************
2  Copyright (c) 2000, 2002 IBM Corp. and others.
3  All rights reserved. This program and the accompanying materials
4  are made available under the terms of the Common Public License v1.0
5  which accompanies this distribution, and is available at
6  http://www.eclipse.org/legal/cpl-v10.html
7
8  Contributors:
9  IBM Corporation - Initial implementation
10  Klaus Hartlage - www.eclipseproject.de
11  **********************************************************************/
12 package net.sourceforge.phpeclipse.phpeditor.php;
13
14 import java.sql.Connection;
15 import java.sql.DatabaseMetaData;
16 import java.sql.ResultSet;
17 import java.sql.SQLException;
18 import java.util.ArrayList;
19 import java.util.Arrays;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.SortedMap;
23
24 import net.sourceforge.phpdt.core.IBuffer;
25 import net.sourceforge.phpdt.core.ICompilationUnit;
26 import net.sourceforge.phpdt.core.IJavaProject;
27 import net.sourceforge.phpdt.core.JavaModelException;
28 import net.sourceforge.phpdt.core.ToolFactory;
29 import net.sourceforge.phpdt.core.compiler.ITerminalSymbols;
30 import net.sourceforge.phpdt.core.compiler.InvalidInputException;
31 import net.sourceforge.phpdt.internal.compiler.IProblemFactory;
32 import net.sourceforge.phpdt.internal.compiler.SourceElementParser;
33 import net.sourceforge.phpdt.internal.compiler.impl.CompilerOptions;
34 import net.sourceforge.phpdt.internal.compiler.parser.Scanner;
35 import net.sourceforge.phpdt.internal.compiler.problem.DefaultProblemFactory;
36 import net.sourceforge.phpdt.internal.core.CompilationUnit;
37 import net.sourceforge.phpdt.internal.core.CompilationUnitStructureRequestor;
38 import net.sourceforge.phpdt.internal.core.JavaModelManager;
39 import net.sourceforge.phpdt.internal.core.JavaProject;
40 import net.sourceforge.phpdt.internal.corext.template.ContextType;
41 import net.sourceforge.phpdt.internal.corext.template.ContextTypeRegistry;
42 import net.sourceforge.phpdt.internal.corext.template.php.CompilationUnitContextType;
43 import net.sourceforge.phpdt.internal.corext.template.php.PHPUnitContext;
44 import net.sourceforge.phpdt.internal.ui.PHPUiImages;
45 import net.sourceforge.phpdt.internal.ui.text.java.IPHPCompletionProposal;
46 import net.sourceforge.phpdt.internal.ui.text.java.PHPCompletionProposalComparator;
47 import net.sourceforge.phpdt.internal.ui.text.template.BuiltInEngine;
48 import net.sourceforge.phpdt.internal.ui.text.template.DeclarationEngine;
49 import net.sourceforge.phpdt.internal.ui.text.template.IdentifierEngine;
50 import net.sourceforge.phpdt.internal.ui.text.template.SQLProposal;
51 import net.sourceforge.phpdt.internal.ui.text.template.TemplateEngine;
52 import net.sourceforge.phpdt.ui.IWorkingCopyManager;
53 import net.sourceforge.phpeclipse.IPreferenceConstants;
54 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
55 import net.sourceforge.phpeclipse.builder.IdentifierIndexManager;
56 import net.sourceforge.phpeclipse.internal.compiler.ast.CompilationUnitDeclaration;
57 import net.sourceforge.phpeclipse.overlaypages.Util;
58 import net.sourceforge.phpeclipse.phpeditor.PHPEditor;
59 import net.sourceforge.phpeclipse.phpeditor.PHPSyntaxRdr;
60
61 import org.eclipse.core.resources.IFile;
62 import org.eclipse.core.resources.IProject;
63 import org.eclipse.jface.text.BadLocationException;
64 import org.eclipse.jface.text.IDocument;
65 import org.eclipse.jface.text.IRegion;
66 import org.eclipse.jface.text.ITextViewer;
67 import org.eclipse.jface.text.Region;
68 import org.eclipse.jface.text.TextPresentation;
69 import org.eclipse.jface.text.contentassist.ICompletionProposal;
70 import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
71 import org.eclipse.jface.text.contentassist.IContextInformation;
72 import org.eclipse.jface.text.contentassist.IContextInformationExtension;
73 import org.eclipse.jface.text.contentassist.IContextInformationPresenter;
74 import org.eclipse.jface.text.contentassist.IContextInformationValidator;
75 import org.eclipse.swt.graphics.Image;
76 import org.eclipse.ui.IEditorPart;
77 import org.eclipse.ui.IFileEditorInput;
78
79 import com.quantum.model.Bookmark;
80 import com.quantum.model.BookmarkCollection;
81 import com.quantum.model.NotConnectedException;
82 import com.quantum.util.connection.ConnectionUtil;
83
84 /**
85  * Example PHP completion processor.
86  */
87 public class PHPCompletionProcessor implements IContentAssistProcessor {
88   /**
89    * Simple content assist tip closer. The tip is valid in a range of 5
90    * characters around its popup location.
91    */
92   protected static class Validator implements IContextInformationValidator,
93       IContextInformationPresenter {
94     protected int fInstallOffset;
95
96     /*
97      * @see IContextInformationValidator#isContextInformationValid(int)
98      */
99     public boolean isContextInformationValid(int offset) {
100       return Math.abs(fInstallOffset - offset) < 5;
101     }
102
103     /*
104      * @see IContextInformationValidator#install(IContextInformation,
105      *      ITextViewer, int)
106      */
107     public void install(IContextInformation info, ITextViewer viewer, int offset) {
108       fInstallOffset = offset;
109     }
110
111     /*
112      * @see org.eclipse.jface.text.contentassist.IContextInformationPresenter#updatePresentation(int,
113      *      TextPresentation)
114      */
115     public boolean updatePresentation(int documentPosition,
116         TextPresentation presentation) {
117       return false;
118     }
119   };
120
121   private static class ContextInformationWrapper implements
122       IContextInformation, IContextInformationExtension {
123     private final IContextInformation fContextInformation;
124
125     private int fPosition;
126
127     public ContextInformationWrapper(IContextInformation contextInformation) {
128       fContextInformation = contextInformation;
129     }
130
131     /*
132      * @see IContextInformation#getContextDisplayString()
133      */
134     public String getContextDisplayString() {
135       return fContextInformation.getContextDisplayString();
136     }
137
138     /*
139      * @see IContextInformation#getImage()
140      */
141     public Image getImage() {
142       return fContextInformation.getImage();
143     }
144
145     /*
146      * @see IContextInformation#getInformationDisplayString()
147      */
148     public String getInformationDisplayString() {
149       return fContextInformation.getInformationDisplayString();
150     }
151
152     /*
153      * @see IContextInformationExtension#getContextInformationPosition()
154      */
155     public int getContextInformationPosition() {
156       return fPosition;
157     }
158
159     public void setContextInformationPosition(int position) {
160       fPosition = position;
161     }
162   };
163
164   private class TableName {
165     String fTableName;
166
167     TableName() {
168       fTableName = null;
169     }
170
171     /**
172      * @return Returns the tableName.
173      */
174     public String getTableName() {
175       if (fTableName == null) {
176         return "<!--no-table-->";
177       }
178       return fTableName;
179     }
180
181     /**
182      * @param tableName
183      *          The tableName to set.
184      */
185     public void setTableName(String tableName) {
186       fTableName = tableName;
187     }
188   }
189
190   private char[] fProposalAutoActivationSet;
191
192   protected IContextInformationValidator fValidator = new Validator();
193
194   private TemplateEngine fTemplateEngine;
195
196   private PHPCompletionProposalComparator fComparator;
197
198   private int fNumberOfComputedResults = 0;
199
200   private IEditorPart fEditor;
201
202   protected IWorkingCopyManager fManager;
203
204   public PHPCompletionProcessor(IEditorPart editor) {
205     fEditor = editor;
206     fManager = PHPeclipsePlugin.getDefault().getWorkingCopyManager();
207     ContextType contextType = ContextTypeRegistry.getInstance().getContextType(
208         "php"); //$NON-NLS-1$
209     if (contextType != null)
210       fTemplateEngine = new TemplateEngine(contextType);
211     fComparator = new PHPCompletionProposalComparator();
212   }
213
214   /**
215    * Tells this processor to order the proposals alphabetically.
216    * 
217    * @param order
218    *          <code>true</code> if proposals should be ordered.
219    */
220   public void orderProposalsAlphabetically(boolean order) {
221     fComparator.setOrderAlphabetically(order);
222   }
223
224   /**
225    * Sets this processor's set of characters triggering the activation of the
226    * completion proposal computation.
227    * 
228    * @param activationSet
229    *          the activation set
230    */
231   public void setCompletionProposalAutoActivationCharacters(char[] activationSet) {
232     fProposalAutoActivationSet = activationSet;
233   }
234
235   /*
236    * (non-Javadoc) Method declared on IContentAssistProcessor
237    */
238   public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer,
239       int documentOffset) {
240     int contextInformationPosition = guessContextInformationPosition(viewer,
241         documentOffset);
242     return internalComputeCompletionProposals(viewer, documentOffset,
243         contextInformationPosition);
244   }
245
246   private int getLastToken(ITextViewer viewer, int completionPosition,
247       PHPUnitContext context, TableName tableName) {
248     IDocument document = viewer.getDocument();
249     int start = context.getStart();
250     int end = context.getEnd();
251     String startText;
252     int lastSignificantToken = ITerminalSymbols.TokenNameEOF;
253     try {
254       // begin search 2 lines behind of this
255       int j = start;
256       if (j != 0) {
257         char ch;
258         while (j-- > 0) {
259           ch = document.getChar(j);
260           if (ch == '\n') {
261             break;
262           }
263         }
264         while (j-- > 0) {
265           ch = document.getChar(j);
266           if (ch == '\n') {
267             break;
268           }
269         }
270       }
271       if (j != start) {
272         // scan the line for the dereferencing operator '->'
273         startText = document.get(j, start - j);
274         if (Scanner.DEBUG) {
275           System.out.println(startText);
276         }
277         int token = ITerminalSymbols.TokenNameEOF;
278         //        token = getLastSQLToken(startText);
279         tableName.setTableName(getLastSQLTableName(startText));
280         Scanner scanner = ToolFactory.createScanner(false, false, false);
281         scanner.setSource(startText.toCharArray());
282         scanner.setPHPMode(true);
283         int beforeLastToken = ITerminalSymbols.TokenNameEOF;
284         int lastToken = ITerminalSymbols.TokenNameEOF;
285         char[] ident;
286         try {
287           token = scanner.getNextToken();
288           lastToken = token;
289           while (token != ITerminalSymbols.TokenNameERROR
290               && token != ITerminalSymbols.TokenNameEOF) {
291             beforeLastToken = lastToken;
292             if (lastToken==ITerminalSymbols.TokenNameVariable) {
293               ident = scanner.getCurrentTokenSource();
294               if (ident.length==5 &&
295                   ident[0]=='$' &&
296                   ident[1]=='t' &&
297                   ident[2]=='h' &&
298                   ident[3]=='i' &&
299                   ident[4]=='s') {
300                 beforeLastToken = ITerminalSymbols.TokenNamethis_PHP_COMPLETION;
301               }
302             }
303             lastToken = token;
304             //                                                          System.out.println(scanner.toStringAction(lastToken));
305             token = scanner.getNextToken();
306           }
307         } catch (InvalidInputException e1) {
308         }
309         switch (lastToken) {
310         case ITerminalSymbols.TokenNameMINUS_GREATER:
311           // dereferencing operator '->' found
312           lastSignificantToken = ITerminalSymbols.TokenNameMINUS_GREATER;
313           if (beforeLastToken == ITerminalSymbols.TokenNameVariable) {
314             lastSignificantToken = ITerminalSymbols.TokenNameVariable;
315           }
316           break;
317         case ITerminalSymbols.TokenNamenew:
318           lastSignificantToken = ITerminalSymbols.TokenNamenew;
319           break;
320         }
321       }
322     } catch (BadLocationException e) {
323     }
324     return lastSignificantToken;
325   }
326
327   String getSQLTableName(String sqlText, int start) {
328     int tableNameStart = -1;
329     int currentCharacterPosition = start + 1;
330     char ch;
331     try {
332       while (true) {
333         ch = sqlText.charAt(currentCharacterPosition++);
334         if (tableNameStart == -1 && Character.isJavaIdentifierStart(ch)) {
335           tableNameStart = currentCharacterPosition - 1;
336         } else {
337           if (!Character.isJavaIdentifierPart(ch)) {
338             return sqlText.substring(tableNameStart,
339                 currentCharacterPosition - 1);
340           }
341         }
342       }
343     } catch (IndexOutOfBoundsException e) {
344       if (tableNameStart >= 0) {
345         return sqlText.substring(tableNameStart, currentCharacterPosition - 1);
346       }
347     }
348     return "";
349   }
350
351   private String getLastSQLTableName(String startText) {
352     int token;
353     // scan for sql identifiers
354     char ch = ' ';
355     int currentSQLPosition = startText.length();
356     int identEnd = -1;
357     String ident = null;
358     boolean whiteSpace = true;
359     try {
360       while (true) {
361         ch = startText.charAt(--currentSQLPosition);
362         if (ch >= 'A' && ch <= 'Z') {
363           if (identEnd < 0) {
364             identEnd = currentSQLPosition + 1;
365           }
366         } else if (ch >= 'a' && ch <= 'z') {
367           if (identEnd < 0) {
368             identEnd = currentSQLPosition + 1;
369           }
370         } else if (identEnd >= 0) {
371           ident = startText.substring(currentSQLPosition + 1, identEnd);
372           // select -- from -- where --
373           // update -- set -- where --
374           // insert into -- ( -- ) values ( -- )
375           if (ident.length() >= 4 && ident.length() <= 6) {
376             ident = ident.toLowerCase();
377             switch (ident.length()) {
378             //              case 3 :
379             //                if (ident.equals("set")) {
380             //                  // System.out.println("set");
381             //                  token = ITerminalSymbols.TokenNameSQLset;
382             //                  return token;
383             //                }
384             //                break;
385             case 4:
386               if (ident.equals("from")) {
387                 //                  System.out.println("from");
388                 token = ITerminalSymbols.TokenNameSQLfrom;
389                 return getSQLTableName(startText, identEnd);
390               } else if (ident.equals("into")) {
391                 //                System.out.println("into");
392                 token = ITerminalSymbols.TokenNameSQLinto;
393                 return getSQLTableName(startText, identEnd);
394               }
395               break;
396             //              case 5 :
397             //                if (ident.equals("where")) {
398             //                  // System.out.println("where");
399             //                  token = ITerminalSymbols.TokenNameSQLwhere;
400             //                  return token;
401             //                }
402             //                break;
403             case 6:
404               //                if (ident.equals("select")) {
405               //                  // System.out.println("select");
406               //                  token = ITerminalSymbols.TokenNameSQLselect;
407               //                  return token;
408               //                } else if (ident.equals("insert")) {
409               //                  // System.out.println("insert");
410               //                  token = ITerminalSymbols.TokenNameSQLinsert;
411               //                  return token;
412               //                } else
413               if (ident.equals("update")) {
414                 //                  System.out.println("update");
415                 token = ITerminalSymbols.TokenNameSQLupdate;
416                 return getSQLTableName(startText, identEnd);
417               }
418               //                else if (ident.equals("values")) {
419               //                  // System.out.println("values");
420               //                  token = ITerminalSymbols.TokenNameSQLvalues;
421               //                  return token;
422               //                }
423               break;
424             }
425           }
426           whiteSpace = false;
427           identEnd = -1;
428         } else if (Character.isWhitespace(ch)) {
429         } else {
430           whiteSpace = false;
431         }
432       }
433     } catch (IndexOutOfBoundsException e) {
434     }
435     return "<!--no-table-->";
436   }
437
438   /**
439    * Detect the last significant SQL token in the text before the completion
440    * 
441    * @param startText
442    */
443   private int getLastSQLToken(String startText) {
444     int token;
445     // scan for sql identifiers
446     char ch = ' ';
447     int currentSQLPosition = startText.length();
448     int identEnd = -1;
449     String ident = null;
450     boolean whiteSpace = true;
451     try {
452       while (true) {
453         ch = startText.charAt(--currentSQLPosition);
454         if (ch >= 'A' && ch <= 'Z') {
455           if (identEnd < 0) {
456             identEnd = currentSQLPosition + 1;
457           }
458         } else if (ch >= 'a' && ch <= 'z') {
459           if (identEnd < 0) {
460             identEnd = currentSQLPosition + 1;
461           }
462         } else if (identEnd >= 0) {
463           ident = startText.substring(currentSQLPosition + 1, identEnd);
464           // select -- from -- where --
465           // update -- set -- where --
466           // insert into -- ( -- ) values ( -- )
467           if (ident.length() >= 3 && ident.length() <= 6) {
468             ident = ident.toLowerCase();
469             switch (ident.length()) {
470             case 3:
471               if (ident.equals("set")) {
472                 //                  System.out.println("set");
473                 token = ITerminalSymbols.TokenNameSQLset;
474                 return token;
475               }
476               break;
477             case 4:
478               if (ident.equals("from")) {
479                 //                  System.out.println("from");
480                 token = ITerminalSymbols.TokenNameSQLfrom;
481                 //getSQLTableName();
482                 return token;
483               } else if (ident.equals("into")) {
484                 //                System.out.println("into");
485                 token = ITerminalSymbols.TokenNameSQLinto;
486                 return token;
487               }
488               break;
489             case 5:
490               if (ident.equals("where")) {
491                 //                  System.out.println("where");
492                 token = ITerminalSymbols.TokenNameSQLwhere;
493                 return token;
494               }
495               break;
496             case 6:
497               if (ident.equals("select")) {
498                 //                  System.out.println("select");
499                 token = ITerminalSymbols.TokenNameSQLselect;
500                 return token;
501               } else if (ident.equals("insert")) {
502                 //                  System.out.println("insert");
503                 token = ITerminalSymbols.TokenNameSQLinsert;
504                 return token;
505               } else if (ident.equals("update")) {
506                 //                  System.out.println("update");
507                 token = ITerminalSymbols.TokenNameSQLupdate;
508                 return token;
509               } else if (ident.equals("values")) {
510                 //                System.out.println("values");
511                 token = ITerminalSymbols.TokenNameSQLvalues;
512                 return token;
513               }
514               break;
515             }
516           }
517           whiteSpace = false;
518           identEnd = -1;
519         } else if (Character.isWhitespace(ch)) {
520         } else {
521           whiteSpace = false;
522         }
523       }
524     } catch (IndexOutOfBoundsException e) {
525     }
526     return ITerminalSymbols.TokenNameEOF;
527   }
528
529   private ICompletionProposal[] internalComputeCompletionProposals(
530       ITextViewer viewer, int offset, int contextOffset) {
531
532     IDocument document = viewer.getDocument();
533     Object[] identifiers = null;
534     IFile file = null;
535     IProject project = null;
536     if (offset > 0) {
537       PHPEditor editor = null;
538       if (fEditor != null && (fEditor instanceof PHPEditor)) {
539         editor = (PHPEditor) fEditor;
540         file = ((IFileEditorInput) editor.getEditorInput()).getFile();
541         project = file.getProject();
542         //        outlinePage = editor.getfOutlinePage();
543         // TODO: get the identifiers from the new model
544         //        if (outlinePage instanceof PHPContentOutlinePage) {
545         //          identifiers = ((PHPContentOutlinePage) outlinePage).getVariables();
546         //        }
547       }
548     }
549     
550     ContextType phpContextType = ContextTypeRegistry.getInstance()
551         .getContextType("php"); //$NON-NLS-1$
552     ((CompilationUnitContextType) phpContextType).setContextParameters(
553         document, offset, 0);
554     PHPUnitContext context = (PHPUnitContext) phpContextType.createContext();
555     String prefix = context.getKey();
556     TableName sqlTable = new TableName();
557     int lastSignificantToken = getLastToken(viewer, offset, context, sqlTable);
558     boolean useClassMembers = (lastSignificantToken == ITerminalSymbols.TokenNameMINUS_GREATER)
559         || (lastSignificantToken == ITerminalSymbols.TokenNameVariable)
560         || (lastSignificantToken == ITerminalSymbols.TokenNamenew)
561         || (lastSignificantToken == ITerminalSymbols.TokenNamethis_PHP_COMPLETION);
562     boolean emptyPrefix = prefix == null || prefix.equals("");
563     if (fTemplateEngine != null) {
564       IPHPCompletionProposal[] templateResults = new IPHPCompletionProposal[0];
565       ICompletionProposal[] results;
566       if (!emptyPrefix) {
567         fTemplateEngine.reset();
568         fTemplateEngine.complete(viewer, offset); //, unit);
569         templateResults = fTemplateEngine.getResults();
570       }
571       IPHPCompletionProposal[] identifierResults = new IPHPCompletionProposal[0];
572       if ((!useClassMembers) && identifiers != null) {
573         IdentifierEngine identifierEngine;
574         ContextType contextType = ContextTypeRegistry.getInstance()
575             .getContextType("php"); //$NON-NLS-1$
576         if (contextType != null) {
577           identifierEngine = new IdentifierEngine(contextType);
578           identifierEngine.complete(viewer, offset, identifiers);
579           identifierResults = identifierEngine.getResults();
580         }
581       }
582       // declarations stored in file project.index on project level
583       IPHPCompletionProposal[] declarationResults = new IPHPCompletionProposal[0];
584       if (project != null) {
585         DeclarationEngine declarationEngine;
586         ContextType contextType = ContextTypeRegistry.getInstance()
587             .getContextType("php"); //$NON-NLS-1$
588         if (contextType != null) {
589           IdentifierIndexManager indexManager = PHPeclipsePlugin.getDefault()
590               .getIndexManager(project);
591           SortedMap sortedMap = indexManager.getIdentifierMap();
592           declarationEngine = new DeclarationEngine(project, contextType,
593               lastSignificantToken, file);
594           declarationEngine.complete(viewer, offset, sortedMap);
595           declarationResults = declarationEngine.getResults();
596         }
597       }
598       // built in function names from phpsyntax.xml
599       ArrayList syntaxbuffer = PHPSyntaxRdr.getSyntaxData();
600       IPHPCompletionProposal[] builtinResults = new IPHPCompletionProposal[0];
601       if ((!useClassMembers) && syntaxbuffer != null) {
602         BuiltInEngine builtinEngine;
603         String proposal;
604         ContextType contextType = ContextTypeRegistry.getInstance()
605             .getContextType("php"); //$NON-NLS-1$
606         if (contextType != null) {
607           builtinEngine = new BuiltInEngine(contextType);
608           builtinEngine.complete(viewer, offset, syntaxbuffer);
609           builtinResults = builtinEngine.getResults();
610         }
611       }
612       IPHPCompletionProposal[] sqlResults = new IPHPCompletionProposal[0];
613       if (project != null) {
614         // Get The Database bookmark from the Quantum SQL plugin:
615         BookmarkCollection sqlBookMarks = BookmarkCollection.getInstance();
616         if (sqlBookMarks != null) {
617           String bookmarkString = Util.getMiscProjectsPreferenceValue(project,
618               IPreferenceConstants.PHP_BOOKMARK_DEFAULT);
619           if (bookmarkString != null && !bookmarkString.equals("")) {
620             Bookmark bookmark = sqlBookMarks.find(bookmarkString);
621             ArrayList sqlList = new ArrayList();
622             if (bookmark != null && !bookmark.isConnected()) {
623               new ConnectionUtil().connect(bookmark, null);
624             }
625             if (bookmark != null && bookmark.isConnected()) {
626               try {
627                 Connection connection = bookmark.getConnection();
628                 DatabaseMetaData metaData = connection.getMetaData();
629
630                 if (metaData != null) {
631                   int start = context.getStart();
632                   int end = context.getEnd();
633                   String foundSQLTableName = sqlTable.getTableName();
634                   String tableName;
635                   String columnName;
636                   String prefixWithoutDollar = prefix;
637                   boolean isDollarPrefix = false;
638                   if (prefix.length() > 0 && prefix.charAt(0) == '$') {
639                     prefixWithoutDollar = prefix.substring(1);
640                     isDollarPrefix = true;
641                   }
642                   IRegion region = new Region(start, end - start);
643                   ResultSet set;
644                   if (!isDollarPrefix) {
645                     set = metaData.getTables(null, null, prefixWithoutDollar
646                         + "%", null);
647                     while (set.next()) {
648                       //                  String tempSchema = set.getString("TABLE_SCHEM");
649                       //                  tempSchema = (tempSchema == null) ? "" :
650                       // tempSchema.trim();
651                       tableName = set.getString("TABLE_NAME");
652                       tableName = (tableName == null) ? "" : tableName.trim();
653                       if (tableName != null && tableName.length() > 0) {
654                         sqlList.add(new SQLProposal(tableName, context, region,
655                             viewer, PHPUiImages.get(PHPUiImages.IMG_TABLE)));
656                       }
657                     }
658                     set.close();
659                   }
660                   set = metaData.getColumns(null, null, "%",
661                       prefixWithoutDollar + "%");
662                   SQLProposal sqlProposal;
663                   while (set.next()) {
664                     columnName = set.getString("COLUMN_NAME");
665                     columnName = (columnName == null) ? "" : columnName.trim();
666                     tableName = set.getString("TABLE_NAME");
667                     tableName = (tableName == null) ? "" : tableName.trim();
668                     if (tableName != null && tableName.length() > 0
669                         && columnName != null && columnName.length() > 0) {
670                       if (isDollarPrefix) {
671                         sqlProposal = new SQLProposal(tableName, "$"
672                             + columnName, context, region, viewer, PHPUiImages
673                             .get(PHPUiImages.IMG_COLUMN));
674                       } else {
675                         sqlProposal = new SQLProposal(tableName, columnName,
676                             context, region, viewer, PHPUiImages
677                                 .get(PHPUiImages.IMG_COLUMN));
678                       }
679                       if (tableName.equals(foundSQLTableName)) {
680                         sqlProposal.setRelevance(90);
681                       } else if (tableName.indexOf(foundSQLTableName) >= 0) {
682                         sqlProposal.setRelevance(75);
683                       }
684                       sqlList.add(sqlProposal);
685                     }
686                   }
687                   set.close();
688                   sqlResults = new IPHPCompletionProposal[sqlList.size()];
689                   for (int i = 0; i < sqlList.size(); i++) {
690                     sqlResults[i] = (SQLProposal) sqlList.get(i);
691                   }
692                 }
693               } catch (NotConnectedException e) {
694                 // ignore this - not mission critical
695               } catch (SQLException e) {
696                 e.printStackTrace();
697               }
698             }
699           }
700         }
701       }
702       // concatenate the result arrays
703       IPHPCompletionProposal[] total;
704       total = new IPHPCompletionProposal[templateResults.length
705           + identifierResults.length + builtinResults.length
706           + declarationResults.length + sqlResults.length];
707       System.arraycopy(templateResults, 0, total, 0, templateResults.length);
708       System.arraycopy(identifierResults, 0, total, templateResults.length,
709           identifierResults.length);
710       System.arraycopy(builtinResults, 0, total, templateResults.length
711           + identifierResults.length, builtinResults.length);
712       System.arraycopy(declarationResults, 0, total, templateResults.length
713           + identifierResults.length + builtinResults.length,
714           declarationResults.length);
715       System.arraycopy(sqlResults, 0, total, templateResults.length
716           + identifierResults.length + builtinResults.length
717           + declarationResults.length, sqlResults.length);
718       results = total;
719       fNumberOfComputedResults = (results == null ? 0 : results.length);
720       /*
721        * Order here and not in result collector to make sure that the order
722        * applies to all proposals and not just those of the compilation unit.
723        */
724       return order(results);
725     }
726     return new IPHPCompletionProposal[0];
727   }
728
729   private int guessContextInformationPosition(ITextViewer viewer, int offset) {
730     int contextPosition = offset;
731     IDocument document = viewer.getDocument();
732     //    try {
733     //
734     //      PHPCodeReader reader= new PHPCodeReader();
735     //      reader.configureBackwardReader(document, offset, true, true);
736     //  
737     //      int nestingLevel= 0;
738     //
739     //      int curr= reader.read();
740     //      while (curr != PHPCodeReader.EOF) {
741     //
742     //        if (')' == (char) curr)
743     //          ++ nestingLevel;
744     //
745     //        else if ('(' == (char) curr) {
746     //          -- nestingLevel;
747     //        
748     //          if (nestingLevel < 0) {
749     //            int start= reader.getOffset();
750     //            if (looksLikeMethod(reader))
751     //              return start + 1;
752     //          }
753     //        }
754     //
755     //        curr= reader.read();
756     //      }
757     //    } catch (IOException e) {
758     //    }
759     return contextPosition;
760   }
761
762   /*
763    * (non-Javadoc) Method declared on IContentAssistProcessor
764    */
765   //  public IContextInformation[] computeContextInformation(ITextViewer viewer,
766   // int documentOffset) {
767   //    IContextInformation[] result = new IContextInformation[5];
768   //    for (int i = 0; i < result.length; i++)
769   //      result[i] = new
770   // ContextInformation(MessageFormat.format(PHPEditorMessages.getString("CompletionProcessor.ContextInfo.display.pattern"),
771   // new Object[] { new Integer(i), new Integer(documentOffset)}),
772   // //$NON-NLS-1$
773   //      MessageFormat.format(PHPEditorMessages.getString("CompletionProcessor.ContextInfo.value.pattern"),
774   // new Object[] { new Integer(i), new Integer(documentOffset - 5), new
775   // Integer(documentOffset + 5)})); //$NON-NLS-1$
776   //    return result;
777   //  }
778   /**
779    * @see IContentAssistProcessor#computeContextInformation(ITextViewer, int)
780    */
781   public IContextInformation[] computeContextInformation(ITextViewer viewer,
782       int offset) {
783     int contextInformationPosition = guessContextInformationPosition(viewer,
784         offset);
785     List result = addContextInformations(viewer, contextInformationPosition);
786     return (IContextInformation[]) result
787         .toArray(new IContextInformation[result.size()]);
788   }
789
790   private List addContextInformations(ITextViewer viewer, int offset) {
791     ICompletionProposal[] proposals = internalComputeCompletionProposals(
792         viewer, offset, -1);
793     List result = new ArrayList();
794     for (int i = 0; i < proposals.length; i++) {
795       IContextInformation contextInformation = proposals[i]
796           .getContextInformation();
797       if (contextInformation != null) {
798         ContextInformationWrapper wrapper = new ContextInformationWrapper(
799             contextInformation);
800         wrapper.setContextInformationPosition(offset);
801         result.add(wrapper);
802       }
803     }
804     return result;
805   }
806
807   /**
808    * Order the given proposals.
809    */
810   private ICompletionProposal[] order(ICompletionProposal[] proposals) {
811     Arrays.sort(proposals, fComparator);
812     return proposals;
813   }
814
815   /*
816    * (non-Javadoc) Method declared on IContentAssistProcessor
817    */
818   public char[] getCompletionProposalAutoActivationCharacters() {
819     return fProposalAutoActivationSet;
820     //    return null; // new char[] { '$' };
821   }
822
823   /*
824    * (non-Javadoc) Method declared on IContentAssistProcessor
825    */
826   public char[] getContextInformationAutoActivationCharacters() {
827     return new char[] {};
828   }
829
830   /*
831    * (non-Javadoc) Method declared on IContentAssistProcessor
832    */
833   public IContextInformationValidator getContextInformationValidator() {
834     return fValidator;
835   }
836
837   /*
838    * (non-Javadoc) Method declared on IContentAssistProcessor
839    */
840   public String getErrorMessage() {
841     return null;
842   }
843 }