001 /*
002 * The contents of this file are subject to the Mozilla Public
003 * License Version 1.1 (the "License"); you may not use this file
004 * except in compliance with the License. You may obtain a copy of
005 * the License at http://www.mozilla.org/MPL/
006 *
007 * Software distributed under the License is distributed on an "AS
008 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
009 * implied. See the License for the specific language governing
010 * rights and limitations under the License.
011 *
012 * The Original Code is Knowtator.
013 *
014 * The Initial Developer of the Original Code is University of Colorado.
015 * Copyright (C) 2005 - 2008. All Rights Reserved.
016 *
017 * Knowtator was developed by the Center for Computational Pharmacology
018 * (http://compbio.uchcs.edu) at the University of Colorado Health
019 * Sciences Center School of Medicine with support from the National
020 * Library of Medicine.
021 *
022 * Current information about Knowtator can be obtained at
023 * http://knowtator.sourceforge.net/
024 *
025 * Contributor(s):
026 * Philip V. Ogren <philip@ogren.info> (Original Author) - pvo
027 * Angus Roberts - ar
028 */
029
030 /**
031 * Changes
032 * 2/8/2007 ar updated getRecentDirectory see note at method
033 * 2/8/2007 ar updated save() see note at method
034 *
035 */
036 package edu.uchsc.ccp.knowtator.textsource.files;
037
038 import java.awt.Component;
039 import java.io.File;
040 import java.io.IOException;
041 import java.nio.charset.Charset;
042 import java.nio.charset.IllegalCharsetNameException;
043 import java.util.ArrayList;
044 import java.util.Collections;
045 import java.util.Comparator;
046 import java.util.HashMap;
047 import java.util.List;
048 import java.util.Map;
049 import java.util.regex.Matcher;
050 import java.util.regex.Pattern;
051
052 import javax.swing.JFileChooser;
053 import javax.swing.JOptionPane;
054
055 import edu.stanford.smi.protege.model.Cls;
056 import edu.stanford.smi.protege.model.KnowledgeBase;
057 import edu.stanford.smi.protege.model.Project;
058 import edu.uchsc.ccp.knowtator.KnowtatorProjectUtil;
059 import edu.uchsc.ccp.knowtator.textsource.TextSource;
060 import edu.uchsc.ccp.knowtator.textsource.TextSourceAccessException;
061 import edu.uchsc.ccp.knowtator.textsource.TextSourceCollection;
062 import edu.uchsc.ccp.knowtator.textsource.TextSourceIterator;
063
064 public class FileTextSourceCollection extends TextSourceCollection {
065 public static final String DISPLAY_NAME = "Local Files";
066
067 public static String CLS_NAME = "file text source";
068
069 public static final String PROJECT_SETTING_RECENT_DIRECTORY = new String(
070 "FileTextSourceCollection_RECENT_DIRECTORY");
071
072 public static final String PROJECT_SETTING_RECENT_CHARSET = new String("FileTextSourceCollection_RECENT_CHARSET");
073
074 File directory;
075
076 Charset charset;
077
078 String rootPath;
079
080 String name;
081
082 Map<String, TextSource> namesToTextSource;
083
084 Map<TextSource, Integer> textSourceToIndex;
085
086 List<TextSource> textSources;
087
088 List<String> textSourceNames;
089
090 public FileTextSourceCollection(String directoryName, Charset charset) throws IOException {
091 this(new File(directoryName), charset);
092 }
093
094 public FileTextSourceCollection(File directory, Charset charset) throws IOException {
095 this.directory = directory;
096 this.charset = charset;
097 name = directory.getName();
098 rootPath = directory.getPath();
099
100 List<File> files = new ArrayList<File>();
101 collectFiles(directory, files);
102
103 Collections.sort(files, new Comparator<File>() {
104 public int compare(File file1, File file2) {
105 return String.CASE_INSENSITIVE_ORDER.compare(file1.getName(), file2.getName());
106 }
107 });
108
109 namesToTextSource = new HashMap<String, TextSource>();
110 textSourceToIndex = new HashMap<TextSource, Integer>();
111 textSources = new ArrayList<TextSource>(files.size());
112 textSourceNames = new ArrayList<String>(files.size());
113
114 for (File file : files) {
115 TextSource textSource = new FileTextSource(file, rootPath, charset);
116 String textSourceName = textSource.getName();
117 namesToTextSource.put(textSourceName, textSource);
118 textSources.add(textSource);
119 textSourceNames.add(textSourceName);
120 textSourceToIndex.put(textSource, textSources.size() - 1);
121 }
122 Collections.sort(textSourceNames);
123 }
124
125 /**
126 * This method allows a text source to be added to this TextSourceCollection
127 * on the fly.
128 *
129 * @param fileToAdd
130 * the file to add to this FileTextSourceCollection
131 */
132 public void addTextSourceToCollection(File fileToAdd) {
133 TextSource textSource = new FileTextSource(fileToAdd, rootPath, charset);
134 String textSourceName = textSource.getName();
135 namesToTextSource.put(textSourceName, textSource);
136 textSources.add(textSource);
137 textSourceNames.add(textSourceName);
138 textSourceToIndex.put(textSource, textSources.size() - 1);
139 Collections.sort(textSourceNames);
140 }
141
142 public File getDirectory() {
143 return directory;
144 }
145
146 private void collectFiles(File file, List<File> files) throws IOException {
147 if (file.isDirectory()) {
148 if (!file.getName().equals(".svn") && !file.getName().equals("CVS")) {
149 File[] dirFiles = file.listFiles();
150 for (int i = 0; i < dirFiles.length; i++) {
151 collectFiles(dirFiles[i], files);
152 }
153 }
154 } else {
155 files.add(file);
156 }
157 }
158
159 public int size() {
160 return textSources.size();
161 }
162
163 public TextSource get(int index) throws TextSourceAccessException {
164 TextSource textSource = textSources.get(index);
165 if (textSource != null)
166 return textSource;
167 throw new TextSourceAccessException("There is no text source at index=" + index
168 + " for text source collection = " + getName());
169 }
170
171 public TextSource get(String textSourceName) throws TextSourceAccessException {
172 TextSource textSource = namesToTextSource.get(textSourceName);
173 if (textSource != null)
174 return textSource;
175 throw new TextSourceAccessException("There is no text source for name='" + textSourceName
176 + "' for text source collection = " + getName());
177 }
178
179 public int getIndex(TextSource textSource) {
180 Integer index = textSourceToIndex.get(textSource);
181 if (index != null) {
182 return index.intValue();
183 }
184 return -1;
185 }
186
187 public String getName() {
188 return name;
189 }
190
191 public TextSource select(Component parent) {
192 Object selection = JOptionPane.showInputDialog(parent, "Select text source", "Select text source",
193 JOptionPane.INFORMATION_MESSAGE, null, textSourceNames.toArray(), textSourceNames.toArray()[0]);
194 try {
195 if (selection != null)
196 return get((String) selection);
197 } catch (TextSourceAccessException tsae) {
198 return null;
199 }
200 return null;
201 }
202
203 public TextSource find(Component parent) {
204 String searchString = JOptionPane.showInputDialog(parent, "Enter a regular expression for the name of a text source", "Find a text source",
205 JOptionPane.PLAIN_MESSAGE);
206 Pattern pattern = Pattern.compile(searchString);
207 Matcher matcher;
208 try {
209
210 for (String textSourceName : textSourceNames) {
211 matcher = pattern.matcher(textSourceName);
212 if (matcher.find())
213 return get(textSourceName);
214
215 }
216 } catch (TextSourceAccessException tsae) {
217 tsae.printStackTrace();
218 }
219
220 JOptionPane.showMessageDialog(parent, "No text source found with a name matching the search string you provided.");
221 return null;
222 }
223
224 /**
225 * contribution from Angus Roberts saves a relative path if the directory is
226 * under the protege project directory
227 */
228 public void save(Project project) {
229 // If the directory is contained in the project, save relative to the
230 // project.
231 // Otherwise, save the directory as given
232 String directoryPath = directory.getAbsolutePath();
233 String annotationProjectPath = new File(project.getProjectDirectoryURI().getPath()).getPath();
234
235 if (directoryPath.startsWith(annotationProjectPath)) {
236 directoryPath = directoryPath.substring(annotationProjectPath.length() + 1);
237 project.setClientInformation(PROJECT_SETTING_RECENT_DIRECTORY, directoryPath);
238 } else {
239 project.setClientInformation(PROJECT_SETTING_RECENT_DIRECTORY, directory.getPath());
240 }
241 project.setClientInformation(PROJECT_SETTING_RECENT_CHARSET, charset.name());
242 }
243
244 public static TextSourceCollection open(Project project) {
245 File recentDirectory = getRecentDirectory(project);
246 Charset charset = getRecentCharset(project);
247 if (recentDirectory != null && charset != null) {
248 try {
249 TextSourceCollection tsc = new FileTextSourceCollection(recentDirectory, charset);
250 return tsc;
251 } catch (IOException ioe) {
252 ioe.printStackTrace();
253 }
254 }
255 return null;
256 }
257
258 /**
259 * updated by Angus Roberts to look for the directory relative to the
260 * protege project directory
261 *
262 * @param project
263 * @return
264 */
265 private static File getRecentDirectory(Project project) {
266 String recentPath = (String) project.getClientInformation(PROJECT_SETTING_RECENT_DIRECTORY);
267
268 if (recentPath == null)
269 return null;
270
271 File recentDirectory = new File(recentPath);
272 // if the path is not absolute, and If the directory can be found
273 // below the protege project, restore from here.
274 if (!recentDirectory.isAbsolute()) {
275 String annotationProjectPath = new File(project.getProjectDirectoryURI()).getPath();
276 String absoluteRecentPath = annotationProjectPath + File.separator + recentPath;
277 recentDirectory = new File(absoluteRecentPath);
278 if (recentDirectory.exists() && recentDirectory.isDirectory()) {
279 return recentDirectory;
280 } else {
281 recentDirectory = new File(recentPath);
282 }
283 }
284
285 if (recentDirectory.exists() && recentDirectory.isDirectory()) {
286 return recentDirectory;
287 }
288 return null;
289 }
290
291 private static Charset getRecentCharset(Project project) {
292 String charsetName = (String) project.getClientInformation(PROJECT_SETTING_RECENT_CHARSET);
293 if (charsetName == null)
294 return null;
295 try {
296 Charset charset = Charset.forName(charsetName);
297 return charset;
298 } catch (IllegalCharsetNameException icne) {
299 return null;
300 }
301 }
302
303 public static TextSourceCollection open(Project project, Component parent) {
304 JFileChooser chooser = new JFileChooser();
305 File homeDirectory = chooser.getCurrentDirectory();
306 File recentDirectory = getRecentDirectory(project);
307 if (recentDirectory != null) {
308 chooser.setCurrentDirectory(recentDirectory);
309 }
310 chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
311 int returnVal = chooser.showOpenDialog(parent);
312 if (returnVal == JFileChooser.APPROVE_OPTION) {
313 File file = chooser.getSelectedFile();
314 if (file.equals(homeDirectory)) {
315 JOptionPane
316 .showMessageDialog(
317 parent,
318 "Choosing your home directory is not allowed. Please select a directory that contains only text files that you want to annotate.",
319 "", JOptionPane.ERROR_MESSAGE);
320 return null;
321 }
322 try {
323 FileTextSourceCollection tsc = new FileTextSourceCollection(file, Charset.forName("UTF-8"));
324 return tsc;
325 } catch (IOException ioe) {
326 ioe.printStackTrace();
327 JOptionPane.showMessageDialog(parent, "Unable to open directory as a text source collection", "",
328 JOptionPane.ERROR_MESSAGE);
329 }
330 }
331 return null;
332 }
333
334 public static void createCls(KnowledgeBase kb) {
335 if (kb.getCls(CLS_NAME) == null) {
336 Cls textSourceParent = kb.getCls(KnowtatorProjectUtil.TEXT_SOURCE_CLS_NAME);
337 List<Cls> parents = new ArrayList<Cls>();
338 parents.add(textSourceParent);
339 kb.createCls(CLS_NAME, parents);
340 }
341 return;
342 }
343
344 public TextSourceIterator iterator() {
345 return new FileTextSourceIterator();
346 }
347
348 class FileTextSourceIterator implements TextSourceIterator {
349 int tsIndex = -1;
350
351 public TextSource next() throws TextSourceAccessException {
352 try {
353 return textSources.get(++tsIndex);
354 } catch (IndexOutOfBoundsException ioobe) {
355 throw new TextSourceAccessException(ioobe);
356 }
357 }
358
359 public boolean hasNext() {
360 return (tsIndex + 1) < textSources.size();
361 }
362 }
363 }
364
365 // String[] selectionValues = new String[] {"US-ASCII",
366 // "ISO-8859-1",
367 // "UTF-8",
368 // "UTF-16BE",
369 // "UTF-16LE",
370 // "UTF-16"};
371 //
372 // String selectionValue = (String) JOptionPane.showInputDialog(parent,"Select
373 // file encoding","File encoding selection",JOptionPane.PLAIN_MESSAGE, null,
374 // selectionValues, selectionValues[0]);
375 // if(selectionValue == null) return null;
376 // Charset charset = null;
377 // try
378 // {
379 // charset = Charset.forName(selectionValue);
380 // }
381 // catch(IllegalCharsetNameException icne)
382 // {
383 // JOptionPane.showMessageDialog(parent,"Invalid charset.", "Invalid charset
384 // error",JOptionPane.ERROR_MESSAGE);
385 // return null;
386 // }
387