/** * Returns the sorted names of all available databases and, optionally, backups. Filters for * {@code name} if not {@code null} with glob support. * * @param db return databases? * @param backup return backups? * @param name name filter (may be {@code null}) * @return database and backups list */ private StringList list(final boolean db, final boolean backup, final String name) { final Pattern pt; if (name != null) { final String nm = REGEX.matcher(name).matches() ? IOFile.regex(name) : name.replaceAll("([" + REGEXCHARS + "])", "\\\\$1"); pt = Pattern.compile(nm, Prop.CASE ? 0 : Pattern.CASE_INSENSITIVE); } else { pt = null; } final IOFile[] children = soptions.dbpath().children(); final StringList list = new StringList(children.length); final HashSet<String> map = new HashSet<>(children.length); for (final IOFile f : children) { final String fn = f.name(); String add = null; if (backup && fn.endsWith(IO.ZIPSUFFIX)) { final String nn = ZIPPATTERN.split(fn)[0]; if (!nn.equals(fn)) add = nn; } else if (db && f.isDir() && fn.indexOf('.') == -1) { add = fn; } // add entry if it matches the pattern, and has not already been added if (add != null && (pt == null || pt.matcher(add).matches()) && map.add(add)) { list.add(add); } } return list.sort(false); }
/** * Returns the names of all backups. * * @return backups */ public StringList backups() { final StringList backups = new StringList(); for (final IOFile f : soptions.dbpath().children()) { final String n = f.name(); if (n.endsWith(IO.ZIPSUFFIX)) backups.add(n.substring(0, n.lastIndexOf('.'))); } return backups; }
/** * Returns the name of a specific backup, or all backups found for a specific database, in a * descending order. * * @param db database * @return names of specified backups */ public StringList backups(final String db) { final StringList backups = new StringList(); final IOFile file = soptions.dbpath(db + IO.ZIPSUFFIX); if (file.exists()) { backups.add(db); } else { final String regex = db.replaceAll("([" + REGEXCHARS + "])", "\\\\$1") + DateTime.PATTERN + IO.ZIPSUFFIX; for (final IOFile f : soptions.dbpath().children()) { final String n = f.name(); if (n.matches(regex)) backups.add(n.substring(0, n.lastIndexOf('.'))); } } return backups.sort(Prop.CASE, false); }
/** * Chooses files that match the specified pattern. * * @param file file filter * @param content content filter * @param root root directory * @return sorted file paths * @throws InterruptedException interruption */ String[] filter(final String file, final String content, final IOFile root) throws InterruptedException { final long id = ++filterId; final TreeSet<String> results = new TreeSet<>(); final int[] search = new TokenParser(Token.lc(Token.token(content))).toArray(); // glob pattern final ProjectCache pc = cache(root); if (file.contains("*") || file.contains("?")) { final Pattern pt = Pattern.compile(IOFile.regex(file)); for (final String path : pc) { final int offset = offset(path, true); if (pt.matcher(path.substring(offset)).matches() && filterContent(path, search)) { results.add(path); if (results.size() >= MAXHITS) break; } if (id != filterId) throw new InterruptedException(); } } else { // starts-with, contains, camel case final String pttrn = file.toLowerCase(Locale.ENGLISH).replace('\\', '/'); final HashSet<String> exclude = new HashSet<>(); final boolean pathSearch = pttrn.indexOf('/') != -1; for (int i = 0; i < (pathSearch ? 2 : 3); i++) { filter(pttrn, search, i, results, exclude, pathSearch, pc, id); } } return results.toArray(new String[results.size()]); }
/** * Refreshes the list of recent query files and updates the query path. * * @param file new file */ void refreshHistory(final IOFile file) { final StringList sl = new StringList(); String path = null; if (file != null) { path = file.path(); gui.gprop.set(GUIProp.WORKPATH, file.dirPath()); sl.add(path); tabs.setToolTipTextAt(tabs.getSelectedIndex(), path); } final String[] qu = gui.gprop.strings(GUIProp.EDITOR); for (int q = 0; q < qu.length && q < 19; q++) { final String f = qu[q]; if (!f.equalsIgnoreCase(path) && IO.get(f).exists()) sl.add(f); } // store sorted history gui.gprop.set(GUIProp.EDITOR, sl.toArray()); hist.setEnabled(!sl.isEmpty()); }
/** * Refreshes the view after a file has been saved. * * @param root root directory * @param ctx database context * @throws InterruptedException interruption */ void parse(final IOFile root, final Context ctx) throws InterruptedException { final long id = ++parseId; final HashSet<String> parsed = new HashSet<>(); final TreeMap<String, InputInfo> errs = new TreeMap<>(); // collect files to be parsed final ProjectCache pc = cache(root); final StringList mods = new StringList(), lmods = new StringList(); for (final String path : pc) { final IOFile file = new IOFile(path); if (file.hasSuffix(IO.XQSUFFIXES)) (file.hasSuffix(IO.XQMSUFFIX) ? lmods : mods).add(path); } mods.add(lmods); // parse modules for (final String path : mods) { if (id != parseId) throw new InterruptedException(); if (parsed.contains(path)) continue; final IOFile file = new IOFile(path); try (final TextInput ti = new TextInput(file)) { // parse query try (final QueryContext qc = new QueryContext(ctx)) { final String input = ti.cache().toString(); final boolean lib = QueryProcessor.isLibrary(input); qc.parse(input, lib, path, null); // parsing was successful: remember path parsed.add(path); for (final byte[] mod : qc.modParsed) parsed.add(Token.string(mod)); } catch (final QueryException ex) { // parsing failed: remember path final InputInfo ii = ex.info(); errs.put(path, ii); parsed.add(ii.path()); } } catch (final IOException ex) { // file may not be accessible Util.debug(ex); } } errors = errs; }
/** * Saves the specified editor contents. * * @param file file to write * @return {@code false} if confirmation was canceled */ private boolean save(final IOFile file) { try { final EditorArea edit = getEditor(); file.write(edit.getText()); edit.file(file); return true; } catch (final IOException ex) { BaseXDialog.error(gui, FILE_NOT_SAVED); return false; } }
/** * Recursively populates the cache. * * @param root root directory * @param pc file cache * @throws InterruptedException interruption */ void add(final IOFile root, final ProjectCache pc) throws InterruptedException { // check if file cache was replaced or invalidated if (pc != cache) throw new InterruptedException(); final IOFile[] files = root.children(); for (final IOFile file : files) { if (file.name().equals(IO.IGNORESUFFIX)) return; } for (final IOFile file : files) { if (file.isDir()) { add(file, pc); } else { pc.add(file.path()); } } }
/** * Opens the specified query file. * * @param file query file * @return opened editor */ public EditorArea open(final IOFile file) { if (!visible()) GUICommands.C_SHOWEDITOR.execute(gui); EditorArea edit = find(file, true); try { if (edit != null) { // display open file tabs.setSelectedComponent(edit); edit.reopen(true); } else { // get current editor edit = getEditor(); // create new tab if current text is stored on disk or has been modified if (edit.opened() || edit.modified) edit = addTab(); edit.initText(file.read()); edit.file(file); } } catch (final IOException ex) { BaseXDialog.error(gui, FILE_NOT_OPENED); } return edit; }