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