/** * Copyright 1999-2009 The Pegadi Team * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.pegadi.util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.*; import java.util.Arrays; import java.util.Comparator; import java.util.TreeSet; /** * This class is made for use with <code>pegadi.swing.AutoCompleteDocument</code>. * A list of strings will be read from a file, and a new entry may be saved to that file * * @author Ingar Saltvik */ public class AutoCompleteCatalog { private String[] catalogArray; private String filename; private Comparator comp; private final Logger log = LoggerFactory.getLogger(getClass()); /** * Default constructor. Created a new autocompletecatalog from the specified file * @param filename The file from which the catalog will be initialized. */ public AutoCompleteCatalog(String filename) { this.filename = filename; comp = new CompletionTextComparator(); TreeSet s = null; if (filename != null) s = loadCatalogFile(); prepare(s); } private void prepare(TreeSet catalog) { Object[] o = catalog.toArray(); catalogArray = new String[o.length]; for (int i = 0; i < o.length; i++) { catalogArray[i] = (String)o[i]; } } /** * Returns a possible completion to the specified string. A binarysearch will be used, * so the lookup will run in almost logarithmic time * @param str The string to find a completion for. * @return The completiontext */ public String getCompletionText(String str) { if (str.length() > 0) { int ct = Arrays.binarySearch(catalogArray, str, comp); if (ct >= 0) { String s = catalogArray[ct]; while (ct>0 && catalogArray[ct-1].startsWith(str)) { s = catalogArray[ct-1]; ct--; } return s.substring(str.length()-1); } } return ""; } private TreeSet loadCatalogFile() { TreeSet catalogTree = new TreeSet(); BufferedReader br; try { File f = new File(filename); if (!f.exists()) { log.debug("Cannot read file "+ filename +", because it doesn't exist"); return catalogTree; } br = new BufferedReader(new FileReader(f)); } catch (IOException e) { log.error("Cannot read file. Error initializing stream", e); return catalogTree; } String next = ""; while (next != null) { try { next = br.readLine(); } catch (IOException e) { log.error("Cannot read next line from file"); break; } if (next != null) catalogTree.add(next); } try { br.close(); } catch (IOException e) { log.error("Could not close inputstream", e); } return catalogTree; } /** * Saved a new entry to the file, if it does not already exist in the catalog. * @param newEntry The new text for future completions. */ public void save(String newEntry) { if (Arrays.binarySearch(catalogArray, newEntry) >= 0 || "".equals(newEntry)) return; PrintWriter pw; try { File f = new File(filename); if (!f.exists()) { f.createNewFile(); log.debug("Creating file with logged-in usernames, for later autocompletion"); } pw = new PrintWriter(new FileWriter(filename, true)); pw.println(newEntry); pw.flush(); pw.close(); } catch (IOException e) { log.error("Error writing to file", e); } } /** * When this is used for comparing two string, they are treated as equals if the second string * is a completion for the first one. */ private class CompletionTextComparator implements Comparator { public int compare(Object o1, Object o2) { if (o1 instanceof String && o2 instanceof String) return compare((String)o1, (String)o2); //this should never happen return o1.toString().compareTo(o2.toString()); } public boolean equals(Object o) { return o instanceof CompletionTextComparator; } public int compare(String s1, String s2) { if (s1.startsWith(s2)) return 0; return s1.compareTo(s2); } } }