/* PrefListModel.java * Eisenkraut * * Copyright (c) 2004-2016 Hanns Holger Rutz. All rights reserved. * * This software is published under the GNU General Public License v3+ * * * For further information, please contact Hanns Holger Rutz at * contact@sciss.de */ package de.sciss.eisenkraut.gui; import java.util.ArrayList; import java.util.Arrays; //import java.util.Iterator; import java.util.List; import java.util.prefs.BackingStoreException; //import java.util.prefs.NodeChangeEvent; //import java.util.prefs.NodeChangeListener; import java.util.prefs.Preferences; import javax.swing.AbstractListModel; //import javax.swing.ListModel; //import javax.swing.event.ListDataEvent; import javax.swing.event.ListDataListener; import de.sciss.app.PreferenceNodeSync; import de.sciss.util.Disposable; /** * Warning: Because java.util.Preferences is broken (childAdded never called) * it is forbidden to change the preferences concurrently, since it's * not monitored. Only commit changes by calling any of the method * of the list model */ public abstract class PrefListModel extends AbstractListModel implements PreferenceNodeSync, Disposable { private Preferences prefs; private final List<Object> collData = new ArrayList<Object>(); public PrefListModel() { /* empty */ } public void dispose() { if (prefs != null) { prefs = null; } collData.clear(); final ListDataListener[] l = getListDataListeners(); for (int i = l.length - 1; i >= 0; i--) { removeListDataListener(l[i]); } } public void setPreferences(Preferences prefs) { collData.clear(); if (prefs != null) { final String[] names; try { names = prefs.childrenNames(); } catch (BackingStoreException e1) { e1.printStackTrace(); return; } Arrays.sort(names); for (int i = 0; i < names.length; i++) { if (!names[i].equals(String.valueOf(i))) { collData.clear(); new IllegalStateException("Illegal preferences node '" + names[i] + "'").printStackTrace(); return; } collData.add(dataFromNode(prefs.node(names[i]))); } //System.err.println( "addNodeChangeListener: " + prefs ); // prefs.addNodeChangeListener( this ); } this.prefs = prefs; //System.err.println( "setPreferences. size = " + this.getSize() ); // dispatch( new ListDataEvent( this, ListDataEvent.CONTENTS_CHANGED, 0, collData.size() )); fireContentsChanged(this, 0, collData.size()); } // private void dispatch( final ListDataEvent e ) // { // EventQueue.invokeLater( new Runnable() { // public void run() // { // ListDataListener l; // for( Iterator iter = collListeners.iterator(); iter.hasNext(); ) { // l = (ListDataListener) iter.next(); // switch( e.getType() ) { // case ListDataEvent.CONTENTS_CHANGED: // l.contentsChanged( e ); // break; // case ListDataEvent.INTERVAL_ADDED: // l.contentsChanged( e ); // break; // case ListDataEvent.INTERVAL_REMOVED: // l.contentsChanged( e ); // break; // default: // throw new IllegalArgumentException( String.valueOf( e.getType() )); // } // } // } // }); // } public Object getElementAt( int index ) { return collData.get( index ); } /** // * Subclasses can override this method. // * By default the child prefs is returned directly. // */ // protected Object nodeToListData( Preferences child ) // { // return child; // } public int getSize() { return collData.size(); } public void remove( int index ) throws BackingStoreException { if( (index < 0) || (index >= collData.size()) ) throw new ArrayIndexOutOfBoundsException(); final Preferences node = prefs.node( String.valueOf( collData.size() - 1 )); node.removeNode(); collData.remove( index ); for( int i = index; i < collData.size(); i++ ) { dataToNode( i ); } } public void add( Object o ) { add( collData.size(), o ); } public void add( int index, Object o ) { collData.add( index, o ); for( int i = collData.size() - 1; i >= index; i-- ) { dataToNode( i ); } fireIntervalAdded( this, index, index + 1 ); } private void dataToNode( int index ) { if( prefs == null ) return; final Object data = collData.get( index ); final String name = String.valueOf( index ); final boolean existed; try { existed = prefs.nodeExists( name ); if( existed ) { prefs.node( name ).clear(); } } catch( BackingStoreException e1 ) { e1.printStackTrace(); } dataToNode( data, prefs.node( name )); } protected abstract Object dataFromNode(Preferences node); protected abstract void dataToNode(Object data, Preferences node); public Object get( int index ) { return getElementAt( index ); } // public void addListDataListener( ListDataListener l ) // { // collListeners.add( l ); // } // // public void removeListDataListener( ListDataListener l ) // { // collListeners.remove( l ); // } // public void childAdded( NodeChangeEvent e ) // { //System.err.println( "childAdded" ); // final Preferences child = e.getChild(); // collData.add( child ); // dispatch( new ListDataEvent( this, ListDataEvent.INTERVAL_ADDED, collData.size() - 1, collData.size() )); // } // // public void childRemoved( NodeChangeEvent e ) // { //System.err.println( "childRemoved" ); // final Preferences child = e.getChild(); // collData.remove( child ); // dispatch( new ListDataEvent( this, ListDataEvent.INTERVAL_REMOVED, collData.size() - 1, collData.size() )); // } }