/* * ----------------------------------------------------------------------- * File: $HeadURL: http://keith-laptop/svn/krs/LanguageTest/trunk/org.thanlwinsoft.languagetest/src/org/thanlwinsoft/languagetest/language/test/UserConfig.java $ * Revision $LastChangedRevision: 1388 $ * Last Modified: $LastChangedDate: 2009-01-31 19:32:00 +0700 (Sat, 31 Jan 2009) $ * Last Change by: $LastChangedBy: keith $ * ----------------------------------------------------------------------- * Copyright (C) 2003 Keith Stribley <devel@thanlwinsoft.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA * ----------------------------------------------------------------------- */ package org.thanlwinsoft.languagetest.language.test; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.util.Vector; import java.util.Iterator; import java.util.Set; import java.util.HashMap; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.ProjectScope; import org.osgi.service.prefs.BackingStoreException; import org.osgi.service.prefs.Preferences; import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.core.runtime.preferences.IScopeContext; import org.eclipse.swt.graphics.FontData; /** * * @author keith */ public class UserConfig { public final static String PREF_NODE = "org.thanlwinsoft.languagetest"; private final String BROWSE_MODULE_PREF = "BrowseModulePath"; public static final String PROFILES = "Profiles"; public static final String LAST_USED = "lastUsed"; private final static String DEFAULT_SOUND_FORMAT = "SoundExtension"; public static final String LANGUAGE_CONFIG_FILE = "LangConfig.xml"; public static final String LANG_CONFIG_ELEMENT = "LangConfig"; public static final String MAX_FLIP_REPEATS = "MaxFlipRepeats"; public static final String FLIP_PERIOD = "FlipPeriod"; public static final String LANG_LAST_USED_ATTRIB = "lastUsed"; public static final String LANG_XML_COMMENT = "Language Configuration for LanguageTest Program\nCreated on"; private static String DEFAULT_SOUND_EXT = ".wav"; private String userName = "Unknown"; private TestHistory testHistory = null; private final static long MS_IN_HOUR = 3600000; private final static long MS_IN_DAY = MS_IN_HOUR * 24; private File modulePath = null; private File configPath = null; private int[] learntPassCount = null; private long [] minRetestPeriod = null; private long [] initialRevisionPeriod = null; private long [] shortTermPeriod = null; private long [] shortTermRevisionPeriod = null; private long [] longTermPeriod = null; private long [] longTermRevisionPeriod = null; private int maxFlipRepeats = 10; private int flipPeriodSec = 5; private String defaultSoundExtension = DEFAULT_SOUND_EXT; private static Vector<UserConfigListener> listeners = null; private final static String LEARNT_PASS_COUNT = "learntPassCount"; private final static String MIN_RETEST_PERIOD = "minRetestPeriod"; private final static String INITIAL_REV_PERIOD = "initialRevPeriod"; private final static String SHORT_TERM_PERIOD = "shortTermPeriod"; private final static String SHORT_TERM_REV_PERIOD = "shortTermRevPeriod"; private final static String LONG_TERM_PERIOD = "longTermPeriod"; private final static String LONG_TERM_REV_PERIOD = "longTermRevPeriod"; private final static String PREF_DIRECTORY = "LanguageTest"; //private final static String CONFIG_PATH = "ConfigPath"; private final static String MAX_NUM_TEST_ITEMS = "maxNumTestItems"; private Preferences userNode = null; private HashMap<UniversalLanguage, FontData> [] languages = null; private HashMap<UniversalLanguage, FontData> nativeLanguages = null; private HashMap<UniversalLanguage, FontData> foreignLanguages = null; //private IProject userProject = null; // private RecentFilesList recentFilesList = null; private int maxNumTestItems = -1; /** Creates a new instance of UserConfig - this is only used to * get the package name internally */ public UserConfig(IProject userProject) throws IllegalArgumentException //, IOException, //TestHistoryStorageException { //this.userProject = userProject; this.userName = userProject.getName(); //this.recentFilesList = rfList; IScopeContext projectScope = new ProjectScope(userProject); IEclipsePreferences projectNode = projectScope.getNode(PREF_NODE); if (projectNode != null && projectNode instanceof Preferences) { userNode = (Preferences) projectNode; } else { throw new IllegalArgumentException("Failed to get projectNode"); } // write a key so that it will be detected by userExists long lastUsed = userNode.getLong(LAST_USED, new Date().getTime()); userNode.putLong(LAST_USED,lastUsed); // default test types learntPassCount = new int[TestType.NUM_TEST_TYPES]; minRetestPeriod = new long[TestType.NUM_TEST_TYPES]; initialRevisionPeriod = new long[TestType.NUM_TEST_TYPES]; shortTermPeriod = new long[TestType.NUM_TEST_TYPES]; shortTermRevisionPeriod = new long[TestType.NUM_TEST_TYPES]; longTermPeriod = new long[TestType.NUM_TEST_TYPES]; longTermRevisionPeriod = new long[TestType.NUM_TEST_TYPES]; readTestParameters(); // modulePath = new File(userNode.get(BROWSE_MODULE_PREF,"")); // defaultSoundExtension = // userNode.get(DEFAULT_SOUND_FORMAT,DEFAULT_SOUND_EXT); // if (!modulePath.exists()) modulePath = null; // try // { // if (userNode.nodeExists(CONFIG_PATH)) // { // configPath = new File(userNode.get(CONFIG_PATH, null)); // } // else // { // configPath = createConfigPath(userName); // } // } //catch (BackingStoreException e) //{ // throw new IOException("Error saving config date:\n" // + e.getMessage()); //} // create listeners object before creating test history if (listeners == null) { listeners = new Vector<UserConfigListener>(); } // if (testHistory.getModuleCount() == 0) // { // cloneHistory(); // } languages = new ArrayList<HashMap<UniversalLanguage, FontData>>(2).toArray(languages); nativeLanguages = new HashMap<UniversalLanguage, FontData>(); foreignLanguages = new HashMap<UniversalLanguage, FontData>(); languages[UniversalLanguage.NATIVE_LANG] = nativeLanguages; languages[UniversalLanguage.FOREIGN_LANG] = foreignLanguages; // parse site config first, then user config // any duplicates will be overwritten by the user config settings // URL siteConfig = this.getClass().getResource( // "/" + LANGUAGE_CONFIG_FILE); // if (siteConfig != null) // { // parseLanguageConfig(siteConfig.openStream()); // } // File userLangFile = new File(configPath, LANGUAGE_CONFIG_FILE); // if (userLangFile.exists() && userLangFile.canRead()) // { // InputStream uLIS = // new BufferedInputStream(new FileInputStream(userLangFile)); // parseLanguageConfig(uLIS); // uLIS.close(); // } flipPeriodSec = userNode.getInt(FLIP_PERIOD, 5); maxFlipRepeats = userNode.getInt(MAX_FLIP_REPEATS, 10); maxNumTestItems = userNode.getInt(MAX_NUM_TEST_ITEMS, -1); // lang config may now be known, so set history if possible //reloadTestHistory(); } public void reload() { } /* public RecentFilesList getRecentFilesList() { return recentFilesList; } */ // public void reloadTestHistory() throws TestHistoryStorageException // { // // if (LanguageConfig.getCurrent() != null) // { // if (testHistory != null) // { // testHistory.savePermanent(); // } // testHistory = new XmlTestHistory(this, LanguageConfig.getCurrent()); // } // } public Set<UniversalLanguage> getLanguages(int langType) { return languages[langType].keySet(); } public Set<UniversalLanguage> getNativeLanguages() { return nativeLanguages.keySet(); } public Set<UniversalLanguage> getForeignLanguages() { return foreignLanguages.keySet(); } public void removeNativeLanguage(UniversalLanguage ul) { if (nativeLanguages.containsKey(ul)) { nativeLanguages.remove(ul); } } public void removeForeignLanguage(UniversalLanguage ul) { if (foreignLanguages.containsKey(ul)) { foreignLanguages.remove(ul); } } public void addLanguage(UniversalLanguage ul, int langType, FontData font) { if (langType == UniversalLanguage.FOREIGN_LANG) { addForeignLanguage(ul, font); } else { addNativeLanguage(ul, font); } } public void addForeignLanguage(UniversalLanguage ul, FontData font) { foreignLanguages.put(ul,font); } public void addNativeLanguage(UniversalLanguage ul, FontData font) { nativeLanguages.put(ul,font); } public FontData getNativeDefaultFont(UniversalLanguage ul) { if (nativeLanguages.containsKey(ul)) { return nativeLanguages.get(ul); } return null; } public FontData getForeignDefaultFont(UniversalLanguage ul) { if (foreignLanguages.containsKey(ul)) { return foreignLanguages.get(ul); } return null; } public boolean containsNativeLanguage(UniversalLanguage ul) { return nativeLanguages.containsKey(ul); } public boolean containsForeignLanguage(UniversalLanguage ul) { return foreignLanguages.containsKey(ul); } public void setDefaultSoundExtension(String format) { defaultSoundExtension = format; } // public javax.sound.sampled.Mixer.Info getRecordingMixer(LineController lc) // { // return null; // } // // public javax.sound.sampled.Mixer.Info getPlayingMixer(LineController lc) // { // return null; // } // protected void parseLanguageConfig(InputStream xmlIs) // throws TestHistoryStorageException // { // if (xmlIs != null) // { // org.w3c.dom.Document doc = null; // try // { // DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance(); // DocumentBuilder docBuilder = dfactory.newDocumentBuilder(); // doc = docBuilder.parse(new InputSource(xmlIs)); // // } // catch (ParserConfigurationException pce) // { // System.out.println(pce.getMessage()); // } // catch (SAXException se) // { // System.out.println(se.getMessage()); // } // catch (IOException ioe) // { // System.out.println(ioe.getMessage()); // } // if (doc != null) // { // doc.normalize(); // join adjacent text nodes // NodeList top = doc.getElementsByTagName(LANG_CONFIG_ELEMENT); // // if (top.getLength()>0) // { // Element configElement = (Element)top.item(0); // NodeList langs = configElement.getChildNodes(); // UniversalLanguage nul = null; // UniversalLanguage ful = null; // for (int i = 0; i<langs.getLength(); i++) // { // if (langs.item(i).getNodeType() != Node.ELEMENT_NODE) // // { // continue; // } // if (langs.item(i).getNodeName() // .equals(TestModule.LANG_TAG)) // { // Element lang = (Element)langs.item(i); // UniversalLanguage ul = // new UniversalLanguage(lang.getAttribute // (TestModule.LANG_CODE_ATTRIB)); // if (lang.hasChildNodes() && // lang.getFirstChild().getNodeType() == Node.TEXT_NODE && // lang.getFirstChild().getNodeValue().length() > 0) // { // ul.setDescription(lang.getFirstChild().getNodeValue()); // } // Font defaultFont = TestModule.readFont(lang, // TestModule.FONT_NAME_ATTRIB, // TestModule.FONT_STYLE_ATTRIB, // TestModule.FONT_SIZE_ATTRIB, DEFAULT_FONT_SIZE); // String langType = // lang.getAttribute(TestModule.LANG_TYPE_ATTRIB); // if (langType.equals(TestModule.LANG_NATIVE)) // { // nativeLanguages.put(ul,defaultFont); // if (lang.hasAttribute(LANG_LAST_USED_ATTRIB)) // { // nul = ul; // } // } // else if (langType.equals(TestModule.LANG_FOREIGN)) // { // foreignLanguages.put(ul,defaultFont); // if (lang.hasAttribute(LANG_LAST_USED_ATTRIB)) // { // ful = ul; // } // } // }/* // else if (langs.item(i).getNodeName() // .equals(RecentFilesList.RECENT_FILES) && // recentFilesList != null) // { // recentFilesList.parseXml((Element)langs.item(i)); // } // */ // } // if (ful != null && nul != null) // { // // replace language config // new LanguageConfig(nul,ful).load(); // // } // } // } // } // } // // protected boolean saveLanguageConfig(File file) // { // org.w3c.dom.Document doc = null; // try // { // // reuse factory objects between module instances // DocumentBuilderFactory dfactory = // DocumentBuilderFactory.newInstance(); // DocumentBuilder docBuilder = dfactory.newDocumentBuilder(); // // doc = docBuilder.newDocument(); // // add a comment to explain file // org.w3c.dom.Comment comment = // doc.createComment(LANG_XML_COMMENT + new Date().toString()); // doc.insertBefore(comment,null); // // add a style sheet link so can be viewed in web browser // //org.w3c.dom.ProcessingInstruction style = // // doc.createProcessingInstruction(STYLE_SHEET, XSL_LINK); // //doc.insertBefore(style,null); // // create top level element // org.w3c.dom.Element top = doc.createElement(LANG_CONFIG_ELEMENT); // createLangTags(doc, top, nativeLanguages, TestModule.LANG_NATIVE); // createLangTags(doc, top, foreignLanguages, TestModule.LANG_FOREIGN); // // //if (recentFilesList != null) // //{ // // top.insertBefore(recentFilesList.saveToXml(doc), null); // //} // doc.insertBefore(top, null); // // } // catch (ParserConfigurationException e) // { // System.out.println(e.getMessage()); // // from copy of xsl file so not worth giving false for this // return false; // } // try // { // TransformerFactory tfactory = TransformerFactory.newInstance(); // // // This creates a transformer that does a simple identity transform, // // and thus can be used for all intents and purposes as a serializer. // Transformer serializer = tfactory.newTransformer(); // // Properties oprops = new Properties(); // oprops.put(OutputKeys.METHOD, "xml"); // oprops.put(OutputKeys.INDENT, "yes"); // serializer.setOutputProperties(oprops); // // DOMSource domSource = new DOMSource(doc); // // now output the result // serializer.transform(domSource, // new StreamResult(file)); // } // catch (IllegalArgumentException iae) // { // System.out.println(iae.toString()); // return false; // } // catch (TransformerConfigurationException tce) // { // System.out.println(tce.toString()); // return false; // } // catch (TransformerException te) // { // System.out.println(te.toString()); // return false; // } // return true; // } // // protected void createLangTags(org.w3c.dom.Document doc, // org.w3c.dom.Element top, // HashMap fonts, // String langType) // { // // iterate over languages // Iterator f = fonts.keySet().iterator(); // while (f.hasNext()) // { // UniversalLanguage ul = (UniversalLanguage)f.next(); // org.w3c.dom.Element lang = doc.createElement(TestModule.LANG_TAG); // lang.setAttribute(TestModule.LANG_TYPE_ATTRIB, langType); // lang.setAttribute(TestModule.LANG_CODE_ATTRIB, ul.getCode()); // Font font = (Font)fonts.get(ul); // if (font != null) // { // lang.setAttribute(TestModule.FONT_NAME_ATTRIB, font.getName()); // lang.setAttribute(TestModule.FONT_STYLE_ATTRIB, // Integer.toString(font.getStyle())); // lang.setAttribute(TestModule.FONT_SIZE_ATTRIB, // Integer.toString(font.getSize())); // } // if (langType.equals(TestModule.LANG_NATIVE) && // ul.equals(LanguageConfig.getCurrent().getNativeLanguage())) // { // lang.setAttribute(LANG_LAST_USED_ATTRIB, "true"); // } // else if (langType.equals(TestModule.LANG_FOREIGN) && // ul.equals(LanguageConfig.getCurrent().getForeignLanguage())) // { // lang.setAttribute(LANG_LAST_USED_ATTRIB, "true"); // } // if (ul.getDescription() != null && ul.getDescription().length()>0) // { // lang.insertBefore(doc.createTextNode(ul.getDescription()),null); // } // top.insertBefore(lang, null); // } // } public static String generateConfigPath(String newUserName) { File userDir = new File(System.getProperty("user.home")); // if Application Data directory exists (as it does in XP) then use // that directory. Otherwise default to main directory File settingsDir = new File(userDir,"Application Data"); if (!settingsDir.exists()) settingsDir = userDir; String path = settingsDir.getAbsolutePath() + File.separator + PREF_DIRECTORY + File.separator + newUserName; return path; } protected File createConfigPath(String newUserName) throws IOException { File newConfigPath = new File(generateConfigPath(newUserName)); if (!newConfigPath.exists()) { if (!newConfigPath.mkdirs()) { throw new IOException("Cannot create " + newConfigPath.getAbsolutePath()); } } // check that the path is writable - otherwise its fairly useless if (!newConfigPath.canWrite()) { throw new IOException("Cannot write to " + newConfigPath.getAbsolutePath()); } return newConfigPath; } /* protected void cloneHistory() throws IOException { // perhaps an old history exists in Prefs format TestHistory oldHistory = new PrefsTestHistory(userName); this.load(); // currentConfig needs to be set before loading modules if (oldHistory.getModuleCount() > 0) { TestType type = null; try { for (int tt = 0; tt<TestType.NUM_TEST_TYPES; tt++) { TestModule module = null; type = TestType.getById(tt); Iterator i = oldHistory.iterator(type); while (i.hasNext()) { try { ItemHistory ih = (ItemHistory)i.next(); if (module == null || !module.getFile().equals(ih.getModuleFile())) { module = new TestModule(ih.getModuleFile()); } TestItem testItem = module.getItemByCreationTime(ih.getCreationTime(), ih.getCreator()); if (testItem != null) { for (int t = 0; t<ih.getTestCount(); t++) { testHistory.saveResult(testItem, type, ((Date)(ih.getResultTable()[t][0])) .getTime(), ((Boolean)(ih.getResultTable()[t][1])) .booleanValue()); } } } catch (FileNotFoundException fnfe) { System.out.println(fnfe); } catch (TestModule.ParseException pe) { System.out.println(pe); } } } testHistory.savePermanent(); } catch (TestHistoryStorageException thse) { throw new IOException(thse.getMessage()); } } } */ // public boolean rename(String newName) // { // String oldName = userName; // try // { // // check whether new name already exists // if (userExists(newName)) return false; // File newPath = createConfigPath(newName); // // before we do anything make sure test history is saved // testHistory.savePermanent(); // // try to copy files // File [] files = configPath.listFiles(); // boolean renameOk = true; // for (int f = 0; f < files.length; f++) // { // renameOk = files[f].renameTo(new File(newPath, // files[f].getName())); // if (renameOk == false) // { // System.out.println("Rename failed " + // files[f].getAbsolutePath() + "\n" + // newPath.getAbsolutePath()); // break; // } // } // // set new config path if copy successful // if (renameOk) // { // // there is a small chance of losing date here if an error // // occurred half way through the copy // // // delete old path // configPath.delete(); // configPath = newPath; // } // // set new userNode // Preferences oldUserNode = userNode; // userNode = Preferences.userNodeForPackage(this.getClass()) // .node(PROFILES + "/" + newName); // // write a key so that it will be detected by userExists // userNode.putLong(LAST_USED, new Date().getTime()); // // save parameters // // try // { // save(); // } // catch (TestHistoryStorageException e) // { // // at this stage ignore TestHistoryStorageException // // since we have gone too far to backtrack // } // userName = newName; // // update history path in TestHistory // // finally remove the node // oldUserNode.removeNode(); // // notify listeners // notifyConfigListeners(); // } // catch (IOException e) // { // userName = oldName; // System.out.println(e); // return false; // } // catch (BackingStoreException e) // { // userName = oldName; // System.out.println(e); // return false; // } // catch (TestHistoryStorageException e) // { // userName = oldName; // System.out.println(e); // return false; // } // return true; // } public String getDefaultSoundExtension() { return defaultSoundExtension; } public File getModulePath() { return modulePath; } public void setModulePath(File newPath) { modulePath = newPath; } public File getConfigPath() { return configPath; } public boolean setConfigPath(File newPath) throws IOException { // test new path if (!newPath.exists()) { if (!newPath.mkdirs()) return false; } if (!newPath.isDirectory()) return false; if (!newPath.canWrite()) return false; // try to copy old files to new path if (configPath.exists()) { String copyErrors = ""; File [] fileList = configPath.listFiles(); for (int i = 0; i<fileList.length; i++) { if (!fileList[i].renameTo(new File(newPath, fileList[i].getName()))) { copyErrors += "Failed to copy " + fileList[i].getAbsolutePath() + "\n"; } } if (copyErrors.length() > 0) { throw new IOException(copyErrors); } } configPath = newPath; return true; } public String getUserName() { return userName; } public void load() { notifyConfigListeners(); } public TestHistory getTestHistory() { return testHistory; } public int getLearntPassCount(TestType tt) { return learntPassCount[tt.getId()]; } public long getInitialRevisionPeriod(TestType tt) { return initialRevisionPeriod[tt.getId()]; } public long getShortTermPeriod(TestType tt) { return shortTermPeriod[tt.getId()]; } public long getShortTermRevisionPeriod(TestType tt) { return shortTermRevisionPeriod[tt.getId()]; } public long getLongTermPeriod(TestType tt) { return longTermPeriod[tt.getId()]; } public long getLongTermRevisionPeriod(TestType tt) { return longTermRevisionPeriod[tt.getId()]; } public long getMinRetestPeriod(TestType tt) { return minRetestPeriod[tt.getId()]; } public void setLearntPassCount(TestType tt, int value) { learntPassCount[tt.getId()] = value; } public void setInitialRevisionPeriod(TestType tt, long value) { initialRevisionPeriod[tt.getId()] = value; } public void setShortTermPeriod(TestType tt, long value) { shortTermPeriod[tt.getId()] = value; } public void setShortTermRevisionPeriod(TestType tt, long value) { shortTermRevisionPeriod[tt.getId()] = value; } public void setLongTermPeriod(TestType tt, long value) { longTermPeriod[tt.getId()] = value; } public void setLongTermRevisionPeriod(TestType tt, long value) { longTermRevisionPeriod[tt.getId()] = value; } public void setMinRetestPeriod(TestType tt, long value) { minRetestPeriod[tt.getId()] = value; } public void setMaxFlipRepeats(int max) { maxFlipRepeats = max; } public int getMaxFlipRepeats() { return maxFlipRepeats; } public void setFlipPeriod(int period) { flipPeriodSec = period; } public int getFlipPeriod() { return flipPeriodSec; } public int getMaxNumTestItems() { return maxNumTestItems; } public void setMaxNumTestItems(int num) { maxNumTestItems = num; } protected void readTestParameters() { for (int tt = 0; tt < TestType.NUM_TEST_TYPES; tt++) { Preferences ttNode = userNode.node(TestType.getById(tt).getCode()); learntPassCount[tt] = ttNode.getInt(LEARNT_PASS_COUNT, 2); minRetestPeriod[tt] = ttNode.getLong(MIN_RETEST_PERIOD, MS_IN_HOUR * 12); initialRevisionPeriod[tt] = ttNode.getLong(INITIAL_REV_PERIOD, MS_IN_DAY *7); shortTermPeriod[tt] = ttNode.getLong(SHORT_TERM_PERIOD, MS_IN_DAY * 30); shortTermRevisionPeriod[tt] = ttNode.getLong(SHORT_TERM_REV_PERIOD, MS_IN_DAY * 30); longTermPeriod[tt] = ttNode.getLong(LONG_TERM_PERIOD, MS_IN_DAY * 90); longTermRevisionPeriod[tt] = ttNode.getLong(LONG_TERM_REV_PERIOD, MS_IN_DAY * 180); } } public void save() throws TestHistoryStorageException { if (modulePath != null) { userNode.put(BROWSE_MODULE_PREF, modulePath.getAbsolutePath()); } userNode.put(DEFAULT_SOUND_FORMAT, defaultSoundExtension); userNode.putInt(FLIP_PERIOD, flipPeriodSec); userNode.putInt(MAX_FLIP_REPEATS, maxFlipRepeats); userNode.putInt(MAX_NUM_TEST_ITEMS, maxNumTestItems); saveTestParameters(); try { userNode.flush(); } catch (BackingStoreException e) { throw new TestHistoryStorageException(e); } //saveLanguageConfig(new File(configPath, LANGUAGE_CONFIG_FILE)); if (testHistory != null) testHistory.savePermanent(); } protected void saveTestParameters() { for (int tt = 0; tt < TestType.NUM_TEST_TYPES; tt++) { Preferences ttNode = userNode.node(TestType.getById(tt).getCode()); ttNode.putInt(LEARNT_PASS_COUNT, learntPassCount[tt]); ttNode.putLong(MIN_RETEST_PERIOD, minRetestPeriod[tt]); ttNode.putLong(INITIAL_REV_PERIOD, initialRevisionPeriod[tt]); ttNode.putLong(SHORT_TERM_PERIOD,shortTermPeriod[tt]); ttNode.putLong(SHORT_TERM_REV_PERIOD,shortTermRevisionPeriod[tt]); ttNode.putLong(LONG_TERM_PERIOD,longTermPeriod[tt]); ttNode.putLong(LONG_TERM_REV_PERIOD, longTermRevisionPeriod[tt]); } } protected void notifyConfigListeners() { Iterator<UserConfigListener> l = listeners.iterator(); while (l.hasNext()) { l.next() .userConfigChanged(this); } } public static void addListener(UserConfigListener ucl) { if (listeners == null) listeners = new Vector<UserConfigListener>(); listeners.add(ucl); } public static void removeListener(UserConfigListener ucl) { if (listeners != null) listeners.remove(ucl); } }