001: /*
002: * Copyright (C) 2005 Gerd Wagner
003: *
004: * This program is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU General Public License
006: * as published by the Free Software Foundation; either version 2
007: * of the License, or any later version.
008: *
009: * This program is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU General Public License for more details.
013: *
014: * You should have received a copy of the GNU General Public License
015: * along with this program; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
017: */
018:
019: package net.sourceforge.squirrel_sql.plugins.codecompletion;
020:
021: import net.sourceforge.squirrel_sql.client.session.ISession;
022: import net.sourceforge.squirrel_sql.client.session.SQLTokenListener;
023: import net.sourceforge.squirrel_sql.client.session.parser.ParserEventsAdapter;
024: import net.sourceforge.squirrel_sql.client.session.parser.kernel.TableAliasInfo;
025: import net.sourceforge.squirrel_sql.fw.completion.CompletionCandidates;
026: import net.sourceforge.squirrel_sql.fw.completion.util.CompletionParser;
027: import net.sourceforge.squirrel_sql.fw.id.IIdentifier;
028: import net.sourceforge.squirrel_sql.fw.util.log.ILogger;
029: import net.sourceforge.squirrel_sql.fw.util.log.LoggerController;
030: import net.sourceforge.squirrel_sql.plugins.codecompletion.prefs.CodeCompletionPreferences;
031:
032: import java.sql.SQLException;
033: import java.util.ArrayList;
034: import java.util.Arrays;
035:
036: public class StandardCompletorModel {
037:
038: private ISession _session;
039: private ILogger _log = LoggerController
040: .createLogger(CodeCompletorModel.class);
041: private CodeCompletionInfoCollection _codeCompletionInfos;
042:
043: private ArrayList<String> _lastSelectedCompletionNames = new ArrayList<String>();
044: private CodeCompletionPlugin _plugin;
045:
046: StandardCompletorModel(ISession session,
047: CodeCompletionPlugin plugin,
048: CodeCompletionInfoCollection codeCompletionInfos,
049: IIdentifier sqlEntryPanelIdentifier) {
050: _plugin = plugin;
051: try {
052: _session = session;
053: _codeCompletionInfos = codeCompletionInfos;
054:
055: _session.getParserEventsProcessor(sqlEntryPanelIdentifier)
056: .addParserEventsListener(new ParserEventsAdapter() {
057: public void aliasesFound(
058: TableAliasInfo[] aliasInfos) {
059: onAliasesFound(aliasInfos);
060: }
061: });
062: } catch (Exception e) {
063: _log.error("Could not get DB-Meta data", e);
064: }
065: }
066:
067: private void onAliasesFound(TableAliasInfo[] aliasInfos) {
068: _codeCompletionInfos.replaceLastAliasInfos(aliasInfos);
069: }
070:
071: CompletionCandidates getCompletionCandidates(String textTillCarret) {
072: CompletionParser parser = new CompletionParser(textTillCarret);
073:
074: ArrayList<CodeCompletionInfo> ret = new ArrayList<CodeCompletionInfo>();
075:
076: if (false == parser.isQualified()) {
077:
078: ///////////////////////////////////////////////////////////////////////////////
079: // The colums of the last completed table/view that match the tableNamePat
080: // will be returned on top of the collection
081: ret.addAll(getColumnsFromLastSelectionStartingWith(parser
082: .getStringToParse()));
083: //
084: //////////////////////////////////////////////////////////////////////////////
085:
086: ret.addAll(Arrays.asList(_codeCompletionInfos
087: .getInfosStartingWith(null, null, parser
088: .getStringToParse())));
089: } else // 1 < buf.size()
090: {
091: String catalog = null;
092: int catAndSchemCount = 0;
093: if (_codeCompletionInfos.isCatalog(parser.getToken(0))) {
094: catalog = parser.getToken(0);
095: catAndSchemCount = 1;
096: }
097:
098: String schema = null;
099: if (_codeCompletionInfos.isSchema(parser.getToken(0))) {
100: schema = parser.getToken(0);
101: catAndSchemCount = 1;
102: } else if (_codeCompletionInfos
103: .isSchema(parser.getToken(1))) {
104: schema = parser.getToken(1);
105: catAndSchemCount = 2;
106: }
107:
108: // Might also be a catalog or a schema name
109: String tableNamePat1 = parser.getToken(parser.size() - 2);
110: String colNamePat1 = parser.getToken(parser.size() - 1);
111:
112: if (0 < catAndSchemCount) {
113: String tableNamePat2 = parser
114: .getToken(catAndSchemCount);
115:
116: if (parser.size() > catAndSchemCount + 1) {
117: String colNamePat2 = parser
118: .getToken(catAndSchemCount + 1);
119: ret.addAll(getColumnsForName(catalog, schema,
120: tableNamePat2, colNamePat2, parser
121: .getStringToParsePosition()));
122: } else {
123: ret.addAll(Arrays.asList(_codeCompletionInfos
124: .getInfosStartingWith(catalog, schema,
125: tableNamePat2)));
126: }
127:
128: } else {
129: ret
130: .addAll(getColumnsForName(null, null,
131: tableNamePat1, colNamePat1, parser
132: .getStringToParsePosition()));
133: }
134: }
135:
136: CodeCompletionInfo[] ccis = ret
137: .toArray(new CodeCompletionInfo[ret.size()]);
138:
139: return new CompletionCandidates(ccis, parser
140: .getReplacementStart(), parser.getStringToReplace());
141: }
142:
143: private ArrayList<CodeCompletionInfo> getColumnsForName(
144: String catalog, String schema, String name,
145: String colNamePat, int colPos) {
146: CodeCompletionInfo[] infos = _codeCompletionInfos
147: .getInfosStartingWith(catalog, schema, name);
148: String upperCaseTableNamePat = name.toUpperCase();
149: CodeCompletionInfo toReturn = null;
150: if (colPos != -1) {
151: // First check aliases
152: for (int j = 0; j < infos.length; j++) {
153: CodeCompletionInfo info = infos[j];
154: if (info instanceof CodeCompletionTableAliasInfo) {
155: if (info
156: .upperCaseCompletionStringEquals(upperCaseTableNamePat)) {
157: // See if this is the same statement
158: CodeCompletionTableAliasInfo a = (CodeCompletionTableAliasInfo) info;
159: if (colPos >= a.getStatBegin()) {
160: toReturn = a;
161: }
162: }
163: }
164: }
165: }
166: if (toReturn == null) {
167: for (int i = 0; i < infos.length; ++i) {
168: if (infos[i]
169: .upperCaseCompletionStringEquals(upperCaseTableNamePat)) {
170: toReturn = infos[i];
171: break;
172: }
173: }
174: }
175: if (toReturn != null) {
176: try {
177: return toReturn.getColumns(_session.getSchemaInfo(),
178: colNamePat);
179: } catch (SQLException e) {
180: _log.error("Error retrieving columns", e);
181: }
182: }
183: return new ArrayList<CodeCompletionInfo>();
184: }
185:
186: private ArrayList<CodeCompletionInfo> getColumnsFromLastSelectionStartingWith(
187: String colNamePat) {
188: ArrayList<CodeCompletionInfo> ret = new ArrayList<CodeCompletionInfo>();
189:
190: for (String lastSelectedCompletionName : _lastSelectedCompletionNames) {
191: ret.addAll(getColumnsForName(null, null,
192: lastSelectedCompletionName, colNamePat, -1));
193: }
194:
195: return ret;
196: }
197:
198: public SQLTokenListener getSQLTokenListener() {
199: return new SQLTokenListener() {
200: public void tableOrViewFound(String name) {
201: performTableOrViewFound(name);
202: }
203: };
204: }
205:
206: private void performTableOrViewFound(String name) {
207: // Makes sure that the last name is always in top of the list.
208: _lastSelectedCompletionNames.remove(name);
209:
210: _lastSelectedCompletionNames.add(0, name);
211:
212: CodeCompletionPreferences prefs = (CodeCompletionPreferences) _session
213: .getPluginObject(_plugin,
214: CodeCompletionPlugin.PLUGIN_OBJECT_PREFS_KEY);
215: int maxLastSelectedCompletionNames = prefs
216: .getMaxLastSelectedCompletionNames();
217:
218: if (maxLastSelectedCompletionNames < _lastSelectedCompletionNames
219: .size()) {
220: _lastSelectedCompletionNames
221: .remove(_lastSelectedCompletionNames.size() - 1);
222: }
223: }
224:
225: public CodeCompletionInfoCollection getCodeCompletionInfoCollection() {
226: return _codeCompletionInfos;
227: }
228: }
|