1 /* 2 * Copyright (c) 2019 Helmut Neemann. 3 * Use of this source code is governed by the GPL v3 license 4 * that can be found in the LICENSE file. 5 */ 6 package de.neemann.digital; 7 8 import de.neemann.digital.draw.library.ElementLibrary; 9 import de.neemann.digital.gui.FileHistory; 10 import de.neemann.digital.gui.Main; 11 import org.slf4j.Logger; 12 import org.slf4j.LoggerFactory; 13 14 import java.io.File; 15 16 /** 17 * Helper to find a file if only the filename is known. 18 */ 19 public class FileLocator { 20 private static final Logger LOGGER = LoggerFactory.getLogger(FileLocator.class); 21 private static final int MAX_FILE_COUNTER = 5000; 22 23 private final String filename; 24 private File file; 25 private FileHistory history; 26 private ElementLibrary library; 27 private File baseFile; 28 private int fileCounter; 29 30 31 /** 32 * Creates a new instance 33 * 34 * @param file the file to search for 35 */ FileLocator(File file)36 public FileLocator(File file) { 37 this(file == null ? null : file.getName()); 38 this.file = file; 39 } 40 41 /** 42 * Creates a new instance 43 * 44 * @param filename the file name 45 */ FileLocator(String filename)46 public FileLocator(String filename) { 47 this.filename = filename; 48 } 49 50 /** 51 * Sets the relevant file history 52 * 53 * @param history the file history 54 * @return this for chained calls 55 */ setHistory(FileHistory history)56 public FileLocator setHistory(FileHistory history) { 57 this.history = history; 58 return this; 59 } 60 61 /** 62 * Sets the used library. 63 * If called the library folder is scanned to locate the file. 64 * 65 * @param library the library 66 * @return this for chained calls 67 */ setLibrary(ElementLibrary library)68 public FileLocator setLibrary(ElementLibrary library) { 69 this.library = library; 70 return this; 71 } 72 73 /** 74 * The base file from which the specified file name originates. 75 * Often the base file is a file with a different extension, 76 * which is located in the same directory. 77 * 78 * @param baseFile the base file 79 * @return this for chained calls 80 */ setBaseFile(File baseFile)81 public FileLocator setBaseFile(File baseFile) { 82 this.baseFile = baseFile; 83 return this; 84 } 85 86 /** 87 * Configures the file locator with the given main 88 * 89 * @param main the main class 90 * @return this for chained calls 91 */ setupWithMain(Main main)92 public FileLocator setupWithMain(Main main) { 93 if (main != null) { 94 setBaseFile(main.getBaseFileName()); 95 setLibrary(main.getLibrary()); 96 } 97 return this; 98 } 99 100 /** 101 * Tries to locate the given file. 102 * 103 * @return the file or null if not found 104 */ locate()105 public File locate() { 106 if (file != null && file.exists()) 107 return file; 108 109 if (filename == null) 110 return null; 111 112 if (baseFile != null) { 113 File f = new File(baseFile.getParentFile(), filename); 114 if (f.isFile() && f.exists()) { 115 LOGGER.debug(filename + " found in base file folder"); 116 return f; 117 } 118 } 119 120 if (history != null) { 121 for (File h : history.getFiles()) { 122 if (h.getName().equals(filename) && h.exists()) { 123 LOGGER.debug(filename + " found in file history"); 124 return h; 125 } 126 } 127 } 128 129 if (library != null) { 130 final File rootFilePath = library.getRootFilePath(); 131 if (rootFilePath != null) { 132 LOGGER.debug(filename + ": start library folder lookup"); 133 fileCounter = 0; 134 File f = search(rootFilePath); 135 if (f != null) { 136 LOGGER.debug(filename + " found in library folder"); 137 return f; 138 } 139 } 140 } 141 142 LOGGER.debug(filename + " not found"); 143 return file; 144 } 145 search(File path)146 private File search(File path) { 147 if (fileCounter > MAX_FILE_COUNTER) 148 return null; 149 150 File[] list = path.listFiles(); 151 if (list != null) { 152 for (File f : list) { 153 if (f.isFile() && f.getName().equals(filename)) 154 return f; 155 fileCounter++; 156 } 157 for (File f : list) { 158 if (f.isDirectory() && !f.getName().startsWith(".")) { 159 File af = search(f); 160 if (af != null) 161 return af; 162 } 163 } 164 } 165 return null; 166 } 167 168 } 169