/* All programs in this directory and subdirectories are published under the GNU General Public License as described below. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Further information about the GNU GPL is available at: http://www.gnu.org/copyleft/gpl.ja.html */ package net.sf.jabref.groups; import java.util.Vector; import net.sf.jabref.BibtexDatabase; import net.sf.jabref.Globals; import net.sf.jabref.Util; /** * Handles versioning of groups, e.g. automatic conversion from previous to * current versions, or import of flat groups (JabRef <= 1.6) to tree. * * @author jzieren (10.04.2005) */ public class VersionHandling { public static final int CURRENT_VERSION = 3; /** * Imports old (flat) groups data and converts it to a 2-level tree with an * AllEntriesGroup at the root. * * @return the root of the generated tree. */ public static GroupTreeNode importFlatGroups(Vector<String> groups) throws IllegalArgumentException { GroupTreeNode root = new GroupTreeNode(new AllEntriesGroup()); final int number = groups.size() / 3; String name, field, regexp; for (int i = 0; i < number; ++i) { field = groups.get(3 * i + 0); name = groups.get(3 * i + 1); regexp = groups.get(3 * i + 2); root.add(new GroupTreeNode(new KeywordGroup(name, field, regexp, false, true, AbstractGroup.INDEPENDENT))); } return root; } public static GroupTreeNode importGroups(Vector<String> orderedData, BibtexDatabase db, int version) throws Exception { switch (version) { case 0: case 1: return Version0_1.fromString(orderedData.firstElement(), db, version); case 2: case 3: return Version2_3.fromString(orderedData, db, version); default: throw new IllegalArgumentException(Globals.lang( "Failed to read groups data (unsupported version: %0)", "" + version)); } } /** Imports groups version 0 and 1. */ private static class Version0_1 { /** * Parses the textual representation obtained from * GroupTreeNode.toString() and recreates that node and all of its * children from it. * * @throws Exception * When a group could not be recreated */ private static GroupTreeNode fromString(String s, BibtexDatabase db, int version) throws Exception { GroupTreeNode root = null; GroupTreeNode newNode; int i; String g; while (s.length() > 0) { if (s.startsWith("(")) { String subtree = getSubtree(s); newNode = fromString(subtree, db, version); // continue after this subtree by removing it // and the leading/trailing braces, and // the comma (that makes 3) that always trails it // unless it's at the end of s anyway. i = 3 + subtree.length(); s = i >= s.length() ? "" : s.substring(i); } else { i = indexOfUnquoted(s, ','); g = i < 0 ? s : s.substring(0, i); if (i >= 0) s = s.substring(i + 1); else s = ""; newNode = new GroupTreeNode(AbstractGroup.fromString(Util .unquote(g, '\\'), db, version)); } if (root == null) // first node will be root root = newNode; else root.add(newNode); } return root; } /** * Returns the substring delimited by a pair of matching braces, with * the first brace at index 0. Quoted characters are skipped. * * @return the matching substring, or "" if not found. */ private static String getSubtree(String s) { int i = 1; int level = 1; while (i < s.length()) { switch (s.charAt(i)) { case '\\': ++i; break; case '(': ++level; break; case ')': --level; if (level == 0) return s.substring(1, i); break; } ++i; } return ""; } /** * Returns the index of the first occurence of c, skipping quoted * special characters (escape character: '\\'). * * @param s * The String to search in. * @param c * The character to search * @return The index of the first unescaped occurence of c in s, or -1 * if not found. */ private static int indexOfUnquoted(String s, char c) { int i = 0; while (i < s.length()) { if (s.charAt(i) == '\\') { ++i; // skip quoted special } else { if (s.charAt(i) == c) return i; } ++i; } return -1; } } private static class Version2_3 { private static GroupTreeNode fromString(Vector<String> data, BibtexDatabase db, int version) throws Exception { GroupTreeNode cursor = null; GroupTreeNode root = null; GroupTreeNode newNode; AbstractGroup group; int spaceIndex; int level; String s; for (int i = 0; i < data.size(); ++i) { s = data.elementAt(i).toString(); spaceIndex = s.indexOf(' '); if (spaceIndex <= 0) throw new Exception("bad format"); // JZTODO lyrics level = Integer.parseInt(s.substring(0, spaceIndex)); group = AbstractGroup.fromString(s.substring(spaceIndex + 1), db, version); newNode = new GroupTreeNode(group); if (cursor == null) { // create new root cursor = newNode; root = cursor; } else { // insert at desired location while (level <= cursor.getLevel()) cursor = (GroupTreeNode) cursor.getParent(); cursor.add(newNode); cursor = newNode; } } return root; } } }