/**
* 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);
}
}
}