001: /*
002: * Copyright (C) 2003 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: package net.sourceforge.squirrel_sql.plugins.codecompletion;
019:
020: import net.sourceforge.squirrel_sql.client.session.ISession;
021: import net.sourceforge.squirrel_sql.client.session.schemainfo.SchemaInfoUpdateListener;
022: import net.sourceforge.squirrel_sql.client.session.parser.kernel.TableAliasInfo;
023: import net.sourceforge.squirrel_sql.fw.sql.IProcedureInfo;
024: import net.sourceforge.squirrel_sql.fw.sql.ITableInfo;
025: import net.sourceforge.squirrel_sql.fw.util.StringManager;
026: import net.sourceforge.squirrel_sql.fw.util.StringManagerFactory;
027:
028: import javax.swing.*;
029: import java.util.*;
030:
031: public class CodeCompletionInfoCollection {
032: private static final StringManager s_stringMgr = StringManagerFactory
033: .getStringManager(CodeCompletionInfoCollection.class);
034:
035: private Hashtable<String, Vector<CodeCompletionInfo>> _completionInfosByCataLogAndSchema = new Hashtable<String, Vector<CodeCompletionInfo>>();
036: private Vector<CodeCompletionInfo> _aliasCompletionInfos = new Vector<CodeCompletionInfo>();
037:
038: private Vector<CodeCompletionSchemaInfo> _schemas = new Vector<CodeCompletionSchemaInfo>();
039: private Vector<CodeCompletionCatalogInfo> _catalogs = new Vector<CodeCompletionCatalogInfo>();
040:
041: private ISession _session;
042: private CodeCompletionPlugin _plugin;
043:
044: private static final int MAX_COMPLETION_INFOS = 300;
045:
046: // i18n[codecompletion.listTruncated=Completion list truncated. Narrow by typing to get missing entries.]
047: private static final String TOO_MANY_COMPLETION_INFOS = s_stringMgr
048: .getString("codecompletion.listTruncated");
049:
050: public CodeCompletionInfoCollection(ISession session,
051: CodeCompletionPlugin plugin) {
052: _session = session;
053: _plugin = plugin;
054:
055: _session.getSchemaInfo().addSchemaInfoUpdateListener(
056: new SchemaInfoUpdateListener() {
057: public void schemaInfoUpdated() {
058: _completionInfosByCataLogAndSchema = new Hashtable<String, Vector<CodeCompletionInfo>>();
059: }
060: });
061: }
062:
063: private void load(String catalog, String schema,
064: boolean showLoadingMessage) {
065: String key = (catalog + "," + schema).toUpperCase();
066:
067: if (null == _completionInfosByCataLogAndSchema.get(key)) {
068: if (!_session.getSchemaInfo().isLoaded()) {
069: if (showLoadingMessage) {
070: // i18n[codecompletion.beingLoaded=Code competion infomation is still being loaded.\nTry again later.]
071: String msg = s_stringMgr
072: .getString("codecompletion.beingLoaded");
073: JOptionPane.showMessageDialog(_session
074: .getApplication().getMainFrame(), msg);
075: }
076: return;
077: }
078:
079: Vector<CodeCompletionInfo> completionInfos = new Vector<CodeCompletionInfo>();
080:
081: ITableInfo[] tables = _session.getSchemaInfo()
082: .getITableInfos(catalog, schema);
083:
084: Hashtable<String, CodeCompletionInfo> completionInfoByUcTableName = new Hashtable<String, CodeCompletionInfo>();
085: for (int i = 0; i < tables.length; i++) {
086: String ucTableName = tables[i].getSimpleName()
087: .toUpperCase();
088:
089: CodeCompletionTableInfo dupl = (CodeCompletionTableInfo) completionInfoByUcTableName
090: .get(ucTableName);
091:
092: CodeCompletionTableInfo tableInfo = new CodeCompletionTableInfo(
093: tables[i].getSimpleName(), tables[i].getType(),
094: tables[i].getCatalogName(), tables[i]
095: .getSchemaName());
096:
097: if (null != dupl) {
098: tableInfo.setHasDuplicateNameInDfifferentSchemas();
099: dupl.setHasDuplicateNameInDfifferentSchemas();
100: }
101:
102: completionInfos.add(tableInfo);
103: completionInfoByUcTableName.put(ucTableName, tableInfo);
104: }
105:
106: IProcedureInfo[] storedProceduresInfos = _session
107: .getSchemaInfo().getStoredProceduresInfos(catalog,
108: schema);
109: for (int i = 0; i < storedProceduresInfos.length; i++) {
110: CodeCompletionStoredProcedureInfo buf = new CodeCompletionStoredProcedureInfo(
111: storedProceduresInfos[i].getSimpleName(),
112: storedProceduresInfos[i].getProcedureType(),
113: _session, _plugin, catalog, schema);
114: completionInfos.add(buf);
115: }
116:
117: if (null == catalog && null == schema) {
118: // These objects do not depend on catalogs or schemas.
119: // It is enough if we load them once.
120:
121: String[] keywords = _session.getSchemaInfo()
122: .getKeywords();
123: for (int i = 0; i < keywords.length; i++) {
124: completionInfos.add(new CodeCompletionKeywordInfo(
125: keywords[i]));
126: }
127:
128: String[] dataTypes = _session.getSchemaInfo()
129: .getDataTypes();
130: for (int i = 0; i < dataTypes.length; i++) {
131:
132: if (false == _session.getSchemaInfo().isTable(
133: dataTypes[i])) {
134: // For example Postgres returns table names as datatypes.
135: // In those cases this prevents to have the table names twice.
136: completionInfos.add(new CodeCompletionTypeInfo(
137: dataTypes[i]));
138: }
139: }
140:
141: String[] functions = _session.getSchemaInfo()
142: .getFunctions();
143: for (int i = 0; i < functions.length; i++) {
144: completionInfos.add(new CodeCompletionFunctionInfo(
145: functions[i]));
146: }
147:
148: String[] catalogs = _session.getSchemaInfo()
149: .getCatalogs();
150: for (int i = 0; i < catalogs.length; i++) {
151: completionInfos.add(new CodeCompletionCatalogInfo(
152: catalogs[i]));
153: _catalogs.add(new CodeCompletionCatalogInfo(
154: catalogs[i]));
155: }
156:
157: String[] schemas = _session.getSchemaInfo()
158: .getSchemas();
159: for (int i = 0; i < schemas.length; i++) {
160: completionInfos.add(new CodeCompletionSchemaInfo(
161: schemas[i]));
162: _schemas.add(new CodeCompletionSchemaInfo(
163: schemas[i]));
164: }
165:
166: AutoCorrectProvider autoCorrectProvider = (AutoCorrectProvider) _session
167: .getApplication().getPluginManager()
168: .bindExternalPluginService("syntax",
169: AutoCorrectProvider.class);
170:
171: if (null == autoCorrectProvider) {
172: // i18n[codecompletion.useSyntaxPlugin=Code completion will work better if you use the Syntax plugin. Get it from squirrelsql.org, it's free!]
173: _session
174: .showMessage(s_stringMgr
175: .getString("codecompletion.useSyntaxPlugin"));
176: } else {
177: Hashtable<String, String> autoCorrections = autoCorrectProvider
178: .getAutoCorrects();
179:
180: for (Enumeration<String> e = autoCorrections.keys(); e
181: .hasMoreElements();) {
182: String toCorrect = e.nextElement();
183: String correction = autoCorrections
184: .get(toCorrect);
185:
186: completionInfos
187: .add(new CodeCompletionAutoCorrectInfo(
188: toCorrect, correction));
189: }
190: }
191:
192: }
193:
194: Collections.sort(completionInfos);
195:
196: _completionInfosByCataLogAndSchema
197: .put(key, completionInfos);
198: }
199: }
200:
201: public CodeCompletionInfo[] getInfosStartingWith(String catalog,
202: String schema, String prefix) {
203: load(catalog, schema, true);
204:
205: Vector<CodeCompletionInfo> completionInfos = getCompletionInfos(
206: catalog, schema);
207:
208: if (null == completionInfos) {
209: // CompletionInfos are still loading
210: return new CodeCompletionInfo[0];
211: }
212:
213: String upperCasePrefix = prefix.trim().toUpperCase();
214:
215: if ("".equals(upperCasePrefix)) {
216: Vector<CodeCompletionInfo> buf = new Vector<CodeCompletionInfo>();
217: buf.addAll(_aliasCompletionInfos);
218:
219: if (MAX_COMPLETION_INFOS < completionInfos.size()) {
220: buf.addAll(completionInfos.subList(0,
221: MAX_COMPLETION_INFOS));
222: _session.showMessage(TOO_MANY_COMPLETION_INFOS);
223: } else {
224: buf.addAll(completionInfos);
225: }
226:
227: return buf.toArray(new CodeCompletionInfo[0]);
228: }
229:
230: Vector<CodeCompletionInfo> ret = new Vector<CodeCompletionInfo>();
231:
232: for (int i = 0; i < _aliasCompletionInfos.size(); ++i) {
233: CodeCompletionInfo buf = _aliasCompletionInfos.get(i);
234: if (buf
235: .upperCaseCompletionStringStartsWith(upperCasePrefix)) {
236: ret.add(buf);
237: }
238: }
239:
240: for (int i = 0; i < completionInfos.size(); ++i) {
241: CodeCompletionInfo buf = completionInfos.get(i);
242: if (buf
243: .upperCaseCompletionStringStartsWith(upperCasePrefix)) {
244: ret.add(buf);
245:
246: if (MAX_COMPLETION_INFOS < ret.size()) {
247: _session.showMessage(TOO_MANY_COMPLETION_INFOS);
248: break;
249: }
250: }
251: }
252:
253: return ret.toArray(new CodeCompletionInfo[0]);
254: }
255:
256: private Vector<CodeCompletionInfo> getCompletionInfos(
257: String catalog, String schema) {
258: String key = (catalog + "," + schema).toUpperCase();
259: Vector<CodeCompletionInfo> ret = _completionInfosByCataLogAndSchema
260: .get(key);
261:
262: if (null == ret) {
263: load(catalog, schema, false);
264: }
265: ret = _completionInfosByCataLogAndSchema.get(key);
266:
267: return ret;
268: }
269:
270: public void replaceLastAliasInfos(TableAliasInfo[] aliasInfos) {
271: _aliasCompletionInfos = new Vector<CodeCompletionInfo>(
272: aliasInfos.length);
273:
274: for (int i = 0; i < aliasInfos.length; i++) {
275: if (false == aliasInfos[i].aliasName.startsWith("#")) {
276: _aliasCompletionInfos
277: .add(new CodeCompletionTableAliasInfo(
278: aliasInfos[i]));
279: }
280: }
281: }
282:
283: public boolean isCatalog(String name) {
284: for (int i = 0; i < _catalogs.size(); i++) {
285: CodeCompletionCatalogInfo info = _catalogs.get(i);
286: if (info.getCompareString().equalsIgnoreCase(name)) {
287: return true;
288: }
289: }
290: return false;
291: }
292:
293: public boolean isSchema(String name) {
294: for (int i = 0; i < _schemas.size(); i++) {
295: CodeCompletionSchemaInfo info = _schemas.get(i);
296: if (info.getCompareString().equalsIgnoreCase(name)) {
297: return true;
298: }
299: }
300: return false;
301: }
302:
303: public boolean addCompletionsAtListBegin(String catalog,
304: String schema, CodeCompletionInfo[] completions) {
305: Vector<CodeCompletionInfo> completionInfos = getCompletionInfos(
306: catalog, schema);
307:
308: if (null == completionInfos) {
309: // CompletionInfos are still loading
310: return false;
311: } else {
312: Arrays.sort(completions);
313: completionInfos.addAll(0, Arrays.asList(completions));
314: return true;
315: }
316: }
317: }
|