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