Package de.sciss.eisenkraut.util

Source Code of de.sciss.eisenkraut.util.PrefsUtil

/*
*  PrefsUtil.java
*  Eisenkraut
*
*  Copyright (c) 2004-2014 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
*
*
*  Changelog:
*      25-Jan-05  created from de.sciss.meloncillo.util.PrefsUtil
*    13-May-05  updated from Meloncillo
*    22-Jul-05  suggests 57109 as default scsynth port ; no longer
*          uses 'Built-in Audio' device on Mac (sc will use
*          default system output instead) ; TEMPDIR refers to IOUtil
*/
package de.sciss.eisenkraut.util;

import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.KeyStroke;
import javax.swing.UIManager;

import org.w3c.dom.DOMException;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import net.roydesign.mac.MRJAdapter;

import de.sciss.app.AbstractApplication;
import de.sciss.eisenkraut.io.AudioBoxConfig;
import de.sciss.eisenkraut.io.RoutingConfig;
import de.sciss.eisenkraut.math.ConstQ;
import de.sciss.eisenkraut.net.OSCGUI;
import de.sciss.eisenkraut.net.OSCRoot;
import de.sciss.gui.CoverGrowBox;
import de.sciss.io.IOUtil;
import de.sciss.net.OSCChannel;
import de.sciss.util.Param;
import de.sciss.util.ParamSpace;

/**
*  A helper class for programme preferences. It
*  contains the globally known preferences keys,
*  adds support for default preferences generation
*  and some geometric object (de)serialization.
*  Has utility methods for clearing preferences trees
*  and importing and exporting from/to XML.
*
@author    Hanns Holger Rutz
@version  0.70, 04-Jul-08
*/
public class PrefsUtil
{
  // ------------ root node level ------------

  /**
   *  Value: Double representing the application
   *  version of Meloncillo last time prefs was saved.<br>
   *  Has default value: no!<br>
   *  Node: root
   */
  public static final String KEY_VERSION  = "version"// double : app version

//  /**
//   *  Value: String representing the path list of
//   *  a user's set favourite directories. See PathList
//   *  and PathField documentation.<br>
//   *  Has default value: no!<br>
//   *  Node: root
//   */
//  public static final String KEY_USERPATHS= "usrpaths";  // string : path list

  /**
   *  Value: String representing the path of
   *  the last used directory for opening a file.<br>
   *  Has default value: no!<br>
   *  Node: root
   */
  public static final String KEY_FILEOPENDIR = "fileopendir"// string : path

  /**
   *  Value: String representing the path of
   *  the last used directory for saving a file.<br>
   *  Has default value: no!<br>
   *  Node: root
   */
  public static final String KEY_FILESAVEDIR = "filesavedir"// string : path

  /**
   *  Value: String representing the path of
   *  the last used directory for saving a selection of a file.<br>
   *  Has default value: no!<br>
   *  Node: root
   */
  public static final String KEY_FILESAVESELDIR = "filesaveseldir"// string : path

  /**
   *  Value: Boolean stating whether frame bounds
   *  should be recalled a session file when it's
   *  loaded. Has default value: yes!<br>
   *  Node: root
   */
  public static final String KEY_LOOKANDFEEL = "lookandfeel"

  /**
   *  Value: Boolean indicating whether timeline position catch
   *  is active or not.<br>
   *  Has default value: yes!<br>
   *  Node: shared
   */
  public static final String KEY_CATCH    = "catch";    // boolean : catch on/off
  /**
   *  Value: Boolean indicating whether timeline position is
   *  adjusted after transport stop or not.<br>
   *  Has default value: yes!<br>
   *  Node:
   */
  public static final String KEY_INSERTIONFOLLOWSPLAY  = "insertionfollowsplay";    // boolean
  /**
   *  Value: Boolean indicating whether a null-line
   *  should be painted in the overviews or not.<br>
   *  Has default value: yes!<br>
   *  Node:
   */
  public static final String KEY_VIEWNULLLINIE  = "viewnulllinie";    // boolean
  /**
   *  Value: Boolean indicating whether a vertical
   *  (amplitude range) ruler should be display for each channel or not.<br>
   *  Has default value: yes!<br>
   *  Node:
   */
  public static final String KEY_VIEWVERTICALRULERS  = "viewverticalrulers";    // boolean
  /**
   *  Value: Boolean indicating whether a marker
   *  axis and flagsticks should be painted in the overviews or not.<br>
   *  Has default value: yes!<br>
   *  Node:
   */
  public static final String KEY_VIEWMARKERS  = "viewmarkers";    // boolean
  /**
   *  Value: Boolean indicating whether level meters
   *  per channel should be displayed or not.<br>
   *  Has default value: yes!<br>
   *  Node:
   */
  public static final String KEY_VIEWCHANMETERS  = "viewchanmeters";    // boolean
  /**
   *  Value: Integer indicating the dislayed time format.<br>
   *  Has default value: yes!<br>
   *  Node:
   */
  public static final String KEY_TIMEUNITS  = "timeunits";    // integer (TIME_SAMPLES, TIME_MINSECS)
  /**
   *  Value: Integer indicating the dislayed amplitude scaling.<br>
   *  Has default value: yes!<br>
   *  Node:
   */
  public static final String KEY_VERTSCALE  = "vertscale";    // integer (VSCALE_AMP_LIN etc.)

  public static final int TIME_SAMPLES    = 0;
  public static final int TIME_MINSECS    = 1;

  public static final int VSCALE_AMP_LIN    = 0;
  public static final int VSCALE_AMP_LOG    = 1;
  public static final int VSCALE_FREQ_SPECT  = 2;

  // ------------ audio node level ------------

  /**
   *  Child node of global prefs
   */
  public static final String NODE_AUDIO  = "audio";

  /**
   *  Value: String representing the osc port
   *  of the supercollider application.<br>
   *  Has default value: yes!<br>
   *  Node: audio
   */
//  public static final String KEY_SUPERCOLLIDEROSC  = "supercolliderosc";  // string : "ip:port"

  public static final String KEY_SCPROTOCOL    = "scprotocol";      // string : osc protocol
  public static final String KEY_SCPORT      = "scport";        // param : osc port

  /**
   *  Value: String representing the pathname
   *  of the supercollider application.<br>
   *  Has default value: yes!<br>
   *  Node: audio
   */
  public static final String KEY_SUPERCOLLIDERAPP  = "supercolliderapp"// string : pathname

//  /**
//   *  Value: String representing the name
//   *  of the audio hardware to use by supercollider.
//   *  On Mac OS X, the internal hardware is known
//   *  as 'Built-in Audio'. Another example is 'Mobile I/O 2882 [2600]'
//   *  Has default value: no!<br>
//   *  Node: audio
//   */
//  public static final String KEY_AUDIODEVICE = "audiodevice";    // string : name of audio driver
//  /**
//   *  Value: Param representing the number
//   *  of input channels supplied by the audio hardware
//   *  Has default value: yes!<br>
//   *  Node: audio
//   */
//  public static final String KEY_AUDIOINPUTS = "audioinputs";    // Param : number of audio interface input ch
//  /**
//   *  Value: Param representing the number
//   *  of output channels supplied by the audio hardware
//   *  Has default value: yes!<br>
//   *  Node: audio
//   */
//  public static final String KEY_AUDIOOUTPUTS = "audiooutputs";  // Param : number of audio interface output ch
  /**
   *  Value: Param representing the sample rate
   *  at which supercollider shall run (0 = default system rate)
   *  Has default value: yes!<br>
   *  Node: audio
   */
  public static final String KEY_AUDIORATE  = "audiorate";    // Param : sample rate for sc
  /**
   *  Value: Param representing the number of
   *  internal supercollider busses
   *  Has default value: yes!<br>
   *  Node: audio
   */
  public static final String KEY_AUDIOBUSSES  = "audiobusses"// Param : integer number of busses
  /**
   *  Value: Param representing the amount of
   *  realtime memory for supercollider (in MB)
   *  Has default value: yes!<br>
   *  Node: audio
   */
  public static final String KEY_SCMEMSIZE  = "scmemsize";    // Param : integer number MB realtime mem for supercollider
  /**
   *  Value: Param representing the number of
   *  audio samples per control period in supercollider
   *  Has default value: yes!<br>
   *  Node: audio
   */
  public static final String KEY_SCBLOCKSIZE  = "scblocksize"// Param : integer number samples per control period in supercollider
  /**
   *  Value: Boolean determining whether scsynth should be booted
   *  with Rendezvous enabled or not.
   *  Has default value: yes!<br>
   *  Node: audio
   */
  public static final String KEY_SCRENDEZVOUS  = "screndezvous"// Boolean
  /**
   *  Value: Boolean indicating whether scsynth shall
   *  be booted automatically when Eisenkraut launched or not
   *  Has default value: yes!<br>
   *  Node: audio
   */
  public static final String KEY_AUTOBOOT    = "autoboot"// boolean : automatic scsynth booting

    /**
      *  Value: String indicating whether Eisenkraut should start
     *  playing back a file if it is opened by double clicking
     *  in the Finder.
      *  Has default value: yes!<br>
      *  Node: audio
      */
    public static final String KEY_AUTOPLAYFROMFINDER       = "autoplay";

    public static final String AUTOPLAYFROMFINDER_NONE      = "none";
    public static final String AUTOPLAYFROMFINDER_PLAY      = "play";
    public static final String AUTOPLAYFROMFINDER_LOOP      = "loop";

  /**
   *  Value: String representing the name
   *  of the currently active output routine configuration
   *  Has default value: yes!<br>
   *  Node: audio
   */
  public static final String KEY_OUTPUTCONFIG  = "outputconfig"// string : active output configuration
  /**
   *  Value: String representing the name
   *  of the currently active audio box
   *  Has default value: ???<br>
   *  Node: audio
   */
  public static final String KEY_AUDIOBOX    = "audiobox"// string : active audio box configuration

  // ------------ audio->inputconfigs node level ------------

  /**
   *  Child node of audio prefs
   */
  public static final String NODE_INPUTCONFIGS  = "inputconfigs";

  // ------------ audio->outputconfigs node level ------------

  /**
   *  Child node of audio prefs
   */
  public static final String NODE_OUTPUTCONFIGS  = "outputconfigs";

  // ------------ audio->outputconfigs node level ------------

  /**
   *  Child node of audio prefs
   */
  public static final String NODE_AUDIOBOXES    = "audioboxes";

  // ------------ plugin node level ------------

  /**
   *  Child node of global prefs
   */
  public static final String NODE_PLUGINS  = "plugins";

  // ------------ view node level ------------

  /**
   *  Child node of global prefs
   */
  public static final String NODE_VIEW  = "view";

  /**
   *  Child node of view prefs
   */
  public static final String NODE_SONAGRAM  = "sonagram";
 
  public static final String KEY_SONAENABLED  = "sonaenabled";

  public static List createDefaults( Preferences mainPrefs, double lastVersion )
  {
    File      f;
    String      value;
    Preferences    childPrefs, childPrefs2;
    final String  fs      = File.separator;
    final boolean  isMacOS    = System.getProperty( "os.name" ).indexOf( "Mac OS" ) >= 0;
        final boolean  isWindows  = System.getProperty( "os.name" ).indexOf( "Windows" ) >= 0;
    final List    warnings  = new ArrayList();
 
    putDontOverwrite( IOUtil.getUserPrefs(), IOUtil.KEY_TEMPDIR, System.getProperty( "java.io.tmpdir" ));

    // general
    putDontOverwrite( mainPrefs, KEY_LOOKANDFEEL, UIManager.getSystemLookAndFeelClassName() );
    putBooleanDontOverwrite( mainPrefs, CoverGrowBox.KEY_INTRUDINGSIZE, isMacOS );
    putBooleanDontOverwrite( mainPrefs, KEY_INSERTIONFOLLOWSPLAY, true );
    putBooleanDontOverwrite( mainPrefs, KEY_VIEWCHANMETERS , true );
    putBooleanDontOverwrite( mainPrefs, KEY_VIEWMARKERS , true );
    putBooleanDontOverwrite( mainPrefs, KEY_VIEWNULLLINIE , true );
    putBooleanDontOverwrite( mainPrefs, KEY_VIEWVERTICALRULERS, true );
    putBooleanDontOverwrite( mainPrefs, KEY_CATCH, true );
   
    putIntDontOverwrite( mainPrefs, KEY_TIMEUNITS, TIME_MINSECS );
    putIntDontOverwrite( mainPrefs, KEY_VERTSCALE, VSCALE_AMP_LIN );

    // audio
    childPrefs  = mainPrefs.node( NODE_AUDIO );
    childPrefs.remove( "boottimeout" );    // not used any more
    childPrefs.remove( "audiodevice" );    // not used any more
    childPrefs.remove( "audioinputs" );    // not used any more
    childPrefs.remove( "audiooutputs" )// not used any more

        putDontOverwrite( childPrefs, KEY_AUTOPLAYFROMFINDER, AUTOPLAYFROMFINDER_NONE );

    // audioboxes
    value = AudioBoxConfig.ID_DEFAULT;
    putDontOverwrite( childPrefs, KEY_AUDIOBOX, value );
    try {
      if( !childPrefs.nodeExists( NODE_AUDIOBOXES )) {
        childPrefs2  = childPrefs.node( NODE_AUDIOBOXES );
        new AudioBoxConfig( value, "Default", 8, 8, true ).toPrefs( childPrefs2.node( value ));
      }
    }
    catch( BackingStoreException e1 ) {
      warnings.add( e1.toString() );
    }

    putDontOverwrite( childPrefs, KEY_AUDIORATE, new Param( 0, ParamSpace.FREQ | ParamSpace.HERTZ ).toString() );
    putDontOverwrite( childPrefs, KEY_AUDIOBUSSES, new Param( 256, ParamSpace.NONE ).toString() );
    putDontOverwrite( childPrefs, KEY_SCMEMSIZE, new Param( 8, ParamSpace.NONE ).toString() );
    putDontOverwrite( childPrefs, KEY_SCBLOCKSIZE, new Param( 64, ParamSpace.NONE ).toString() );
    putBooleanDontOverwrite( childPrefs, KEY_SCRENDEZVOUS, true );
//    putBooleanDontOverwrite( childPrefs, KEY_AUTOBOOT, false );

    // outputconfigs
    value = "out1to2";
    putDontOverwrite( childPrefs, KEY_OUTPUTCONFIG, value );
    try {
      if( !childPrefs.nodeExists( NODE_OUTPUTCONFIGS )) {
        childPrefs2 = childPrefs.node( NODE_OUTPUTCONFIGS );
        new RoutingConfig( value, "Out 1-2", new int[] { 0, 1 }, -90f ).toPrefs(
          childPrefs2.node( value ));
        value = "out1to8";
        new RoutingConfig( value, "Out 1-8", new int[] { 0, 1, 2, 3, 4, 5, 6, 7 }, -45f ).toPrefs(
          childPrefs2.node( value ));
//        // ok dis wan is rather for demonstration purpose
//        new RoutingConfig( value, 2, new int[] { 1, 0 }, -90f ).toPrefs(
//          childPrefs2.node( "Reversed Stereo" ));
      }
    }
    catch( BackingStoreException e1 ) {
      warnings.add( e1.toString() );
    }

    // inputconfigs
    try {
      if( !childPrefs.nodeExists( NODE_INPUTCONFIGS )) {
        childPrefs2 = childPrefs.node( NODE_INPUTCONFIGS );
        value = "in1";
        new RoutingConfig( value, "In 1", new int[] { 0 }, 0f ).toPrefs(
          childPrefs2.node( value ));
        value = "in1to2";
        new RoutingConfig( value, "In 1-2", new int[] { 0, 1 }, 0f ).toPrefs(
          childPrefs2.node( value ));
        value = "in1to8";
        new RoutingConfig( value, "In 1-8", new int[] { 0, 1, 2, 3, 4, 5, 6, 7 }, 0f ).toPrefs(
          childPrefs2.node( value ));
//        // ok dis wan is rather for demonstration purpose
//        new RoutingConfig( value, 2, new int[] { 1, 0 }, -90f ).toPrefs(
//          childPrefs2.node( "Reversed Stereo" ));
      }
    }
    catch( BackingStoreException e1 ) {
      warnings.add( e1.toString() );
    }

//    try {
//      value   = InetAddress.getLocalHost().getHostName() + ":57110";
//    }
//    catch( IOException e1 ) {
//      System.err.println( e1.toString() );
//      value   = "127.0.0.1:57109";  // not 57110 which may interfere with a running copy of sclang
//    }
//    putDontOverwrite( childPrefs, KEY_SUPERCOLLIDEROSC, value );
    putDontOverwrite( childPrefs, KEY_SCPROTOCOL, OSCChannel.TCP );
    putDontOverwrite( childPrefs, KEY_SCPORT, new Param( 0, ParamSpace.NONE | ParamSpace.ABS ).toString() );
   
    // sc app
    if( childPrefs.get( KEY_SUPERCOLLIDERAPP, null ) == null ) {
      f  = findFile( isWindows ? "scsynth.exe" : "scsynth", new String[] {
        fs + "Applications" + fs + "SuperCollider_f",
        fs + "Applications" + fs + "SuperCollider",
        fs + "usr" + fs + "local" + fs + "bin",
        fs + "usr" + fs + "bin",
        "C:\\Program Files\\SuperCollider_f",
        "C:\\Program Files\\PsyCollider"
      });
      if( f == null ) {
        if( isMacOS ) {
          try {
            f = MRJAdapter.findApplication( "SCjm" );
            if( f != null ) f = new File( f.getParentFile(), "scsynth" );
          }
          catch( IOException e1 ) { /* ignore */ }
        }
        if( f == null ) {
          warnings.add( AbstractApplication.getApplication().getResourceString( "errSCSynthAppNotFound" ));
        }
      }
      if( f != null ) putDontOverwrite( childPrefs, KEY_SUPERCOLLIDERAPP, f.getAbsolutePath() );
    }

    value = childPrefs.get( KEY_SUPERCOLLIDERAPP, null );
    putBooleanDontOverwrite( childPrefs, KEY_AUTOBOOT, (value != null) && new File( value ).isFile() );

    // OSC
    childPrefs  = OSCRoot.getInstance().getPreferences();
    if( childPrefs.get( OSCGUI.KEY_SWINGAPP, null ) == null ) {
      final String[] folders = new String[ value == null ? 2 : 4 ];
      folders[ 0 ] = fs + "Applications" + fs + "SwingOSC";
      folders[ 1 ] = "C:\\Program Files\\SwingOSC";
      if( value != null ) {
        folders[ 2 ] = new File( value ).getParentFile().getAbsolutePath();
        folders[ 3 ] = new File( new File( new File( value ).getParentFile(), "SwingOSC" ), "build" ).getAbsolutePath();
      }
      f  = findFile( "SwingOSC.jar", folders );
//      if( f == null ) {
//        warnings.add( AbstractApplication.getApplication().getResourceString( "errSCSynthAppNotFound" ));
//      }
      if( f != null ) putDontOverwrite( childPrefs, OSCGUI.KEY_SWINGAPP, f.getAbsolutePath() );
    }
   
    // view
    childPrefs  = mainPrefs.node( NODE_VIEW );
    try {
      if( !childPrefs.nodeExists( NODE_SONAGRAM )) {
        childPrefs2 = childPrefs.node( NODE_SONAGRAM );
        new ConstQ().writePrefs( childPrefs2 );
      }
    }
    catch( BackingStoreException e1 ) {
      warnings.add( e1.toString() );
    }
     
    // save current version
    mainPrefs.putDouble( KEY_VERSION, AbstractApplication.getApplication().getVersion() );

    return warnings;
  }

  private static File findFile( String fileName, String[] folders )
  {
    File f;
 
    for( int i = 0; i < folders.length; i++ ) {
      f = new File( folders[ i ], fileName );
      if( f.exists() ) return f;
    }
    return null;
  }

  // --- custom put/get methods ---

  private static boolean putDontOverwrite( Preferences prefs, String key, String value )
  {
    boolean overwrite = prefs.get( key, null ) == null;
   
    if( overwrite ) {
      prefs.put( key, value );
    }
   
    return overwrite;
  }
 
  private static boolean putIntDontOverwrite( Preferences prefs, String key, int value )
  {
    boolean overwrite = prefs.get( key, null ) == null;
   
    if( overwrite ) {
      prefs.putInt( key, value );
    }
   
    return overwrite;
  }
 
  private static boolean putBooleanDontOverwrite( Preferences prefs, String key, boolean value )
  {
    boolean overwrite = prefs.get( key, null ) == null;
   
    if( overwrite ) {
      prefs.putBoolean( key, value );
    }
   
    return overwrite;
  }

//  private static boolean putDoubleDontOverwrite( Preferences prefs, String key, double value )
//  {
//    boolean overwrite = prefs.get( key, null ) == null;
//   
//    if( overwrite ) {
//      prefs.putDouble( key, value );
//    }
//   
//    return overwrite;
//  }
 
  public static Rectangle stringToRectangle( String value )
  {
    Rectangle        rect  = null;
    final StringTokenizer  tok;
   
    if( value != null ) {
      try {
        tok    = new StringTokenizer( value );
        rect  = new Rectangle( Integer.parseInt( tok.nextToken() ), Integer.parseInt( tok.nextToken() ),
                     Integer.parseInt( tok.nextToken() ), Integer.parseInt( tok.nextToken() ));
      }
      catch( NoSuchElementException e1 ) { e1.printStackTrace(); }
      catch( NumberFormatException e2 ) { e2.printStackTrace(); }
    }
    return rect;
  }

  public static Point stringToPoint( String value )
  {
    Point          pt  = null;
    final StringTokenizer  tok;
   
    if( value != null ) {
      try {
        tok    = new StringTokenizer( value );
        pt    = new Point( Integer.parseInt( tok.nextToken() ), Integer.parseInt( tok.nextToken() ));
      }
      catch( NoSuchElementException e1 ) { e1.printStackTrace(); }
      catch( NumberFormatException e2 ) { e2.printStackTrace(); }
    }
    return pt;
  }

  public static Dimension stringToDimension( String value )
  {
    Dimension        dim  = null;
    final StringTokenizer  tok;
   
    if( value != null ) {
      try {
        tok    = new StringTokenizer( value );
        dim    = new Dimension( Integer.parseInt( tok.nextToken() ), Integer.parseInt( tok.nextToken() ));
      }
      catch( NoSuchElementException e1 ) { e1.printStackTrace(); }
      catch( NumberFormatException e2 ) { e2.printStackTrace(); }
    }
    return dim;
  }
 
  /**
   *  Rectangle, z.B. von Frame.getBounds() in
   *  einen String konvertieren, der als Prefs
   *  gespeichert werden kann. Bei Fehler wird
   *  null zurueckgeliefert. 'value' darf null sein.
   */
  public static String rectangleToString( Rectangle value )
  {
    return( value != null ? (value.x + " " + value.y + " " + value.width + " " + value.height) : null );
  }
 
  public static String pointToString( Point value )
  {
    return( value != null ? (value.x + " " + value.y) : null );
  }
 
  public static String dimensionToString( Dimension value )
  {
    return( value != null ? (value.width + " " + value.height) : null );
  }
 
//  public static String classToNodeName( Class c )
//  {
//    return( "/" + c.getName().replace( '.', '/' ));
//  }

  /**
   *  Converts a a key stroke's string representation as
   *  from preference storage into a KeyStroke object.
   *
   *  @param    prefsValue    a string representation of the form &quot;modifiers keyCode&quot;
   *                or <code>null</code>
   @return    the KeyStroke parsed from the prefsValue or null if the string was
   *        invalid or <code>null</code>
   */
  public static final KeyStroke prefsToStroke( String prefsValue )
  {
    if( prefsValue == null ) return null;
    int i = prefsValue.indexOf( ' ' );
    KeyStroke prefsStroke = null;
    try {
      if( i < 0 ) return null;
      prefsStroke = KeyStroke.getKeyStroke( Integer.parseInt( prefsValue.substring( i+1 )),
                          Integer.parseInt( prefsValue.substring( 0, i )));
    }
    catch( NumberFormatException e1 ) { e1.printStackTrace(); }

    return prefsStroke;
  }
 
  /**
   *  Converts a KeyStroke into a string representation for
   *  preference storage.
   *
   *  @param    prefsStroke  the KeyStroke to convert
   *  @return    a string representation of the form &quot;modifiers keyCode&quot;
   *        or <code>null</code> if the prefsStroke is invalid or <code>null</code>
   */
  public static final String strokeToPrefs( KeyStroke prefsStroke )
  {
    if( prefsStroke == null ) return null;
    else return String.valueOf( prefsStroke.getModifiers() ) + ' ' +
          String.valueOf( prefsStroke.getKeyCode() );
  }

  /**
   *  Traverse a preference node and optionally all
   *  children nodes and remove any keys found.
   */
  public static void removeAll( Preferences prefs, boolean deep )
  throws BackingStoreException
  {
    String[]  keys;
    String[]  children;
    int      i;

    keys = prefs.keys();
    for( i = 0; i < keys.length; i++ ) {
      prefs.remove( keys[i] );
    }
    if( deep ) {
      children  = prefs.childrenNames();
      for( i = 0; i < children.length; i++ ) {
        removeAll( prefs.node( children[i] ), deep );
      }
    }
  }

  /**
   *  Get an Action object that will dump the
   *  structure of the MultiTrackEditors of
   *  all selected transmitters
   */
  public static Action getDebugDumpAction()
  {
    AbstractAction a = new AbstractAction( "Dump preferences tree" ) {
      public void actionPerformed( ActionEvent e )
      {
        debugDump( AbstractApplication.getApplication().getUserPrefs() );
      }
     
      private void debugDump( Preferences prefs )
      {
        System.err.println( "------- debugDump prefs : "+prefs.name()+" -------" );
        String[]  keys;
        String[]  children;
        String    value;
        int      i;
       
        try {
          keys    = prefs.keys();
          for( i = 0; i < keys.length; i++ ) {
            value   = prefs.get( keys[i], null );
            System.err.println( "  key = '"+keys[i]+"' ; value = '"+value+"'" );
          }
          children  = prefs.childrenNames();
          for( i = 0; i < children.length; i++ ) {
            debugDump( prefs.node( children[i] ));
          }
        } catch( BackingStoreException e1 ) {
          System.err.println( e1.getLocalizedMessage() );
        }
      }
    };
    return a;
  }

  /**
   *  Similar to the XMLRepresentation interface,
   *  this method will append an XML representation
   *  of some preferences to an existing node.
   *
   *  @param  prefs   the preferences node to write out.
   *  @param  deep  - true to include a subtree with all
   *          child preferences nodes.
   *  @param  domDoc  the document in which the node will reside.
   *  @param  node  the node to which a child is applied.
   */
  public static void toXML( Preferences prefs, boolean deep, org.w3c.dom.Document domDoc,
                Element node, Map options )
  throws IOException
  {
    String[]  keys;
    String[]  children;
    Element    childElement, entry;
    String    value;
    int      i;

//System.err.println( "node = "+prefs.name() );
    try {
      keys      = prefs.keys();
      childElement  = (Element) node.appendChild( domDoc.createElement( "map" ));
      for( i = 0; i < keys.length; i++ ) {
        value   = prefs.get( keys[i], null );
//System.err.println( "  key = "+keys[i]+"; value = "+value );
        if( value == null ) continue;
        entry = (Element) childElement.appendChild( domDoc.createElement( "entry" ));
        entry.setAttribute( "key", keys[i] );
        entry.setAttribute( "value", value );
      }
      if( deep ) {
        children  = prefs.childrenNames();
        for( i = 0; i < children.length; i++ ) {
          childElement = (Element) node.appendChild( domDoc.createElement( "node" ));
          childElement.setAttribute( "name", children[i] );
          toXML( prefs.node( children[i] ), deep, domDoc, childElement, options );
        }
      }
    } catch( DOMException e1 ) {
      throw IOUtil.map( e1 );
    } catch( BackingStoreException e2 ) {
      throw IOUtil.map( e2 );
    }
  }

  /**
   *  Similar to the XMLRepresentation interface,
   *  this method will parse an XML representation
   *  of some preferences and restore it's values.
   *
   *  @param  prefs    the preferences node to import to.
   *  @param  domDoc    the document in which the node resides.
   *  @param  rootElement  the node whose children to parse.
   */
  public static void fromXML( Preferences prefs, org.w3c.dom.Document domDoc,
                Element rootElement, Map options )
  throws IOException
  {
    NodeList  nl, nl2;
    Element    childElement, entry;
    Node    node;
    int      i, j;

    try {
      nl  = rootElement.getChildNodes();
      for( i = 0; i < nl.getLength(); i++ ) {
        node      = nl.item( i );
        if( !(node instanceof Element) ) continue;
        childElement  = (Element) node;
        nl2        = childElement.getElementsByTagName( "entry" );
        for( j = 0; j < nl2.getLength(); j++ ) {
          entry    = (Element) nl2.item( j );
          prefs.put( entry.getAttribute( "key" ), entry.getAttribute( "value" ));
//System.err.println( "auto : node = "+(prefs.name() )+"; key = "+entry.getAttribute( "key" )+"; val = "+entry.getAttribute( "value" ) );

        }
        break;
      }
      for( ; i < nl.getLength(); i++ ) {
        node      = nl.item( i );
        if( !(node instanceof Element) ) continue;
        childElement  = (Element) node;
        fromXML( prefs.node( childElement.getAttribute( "name" )), domDoc, childElement, options );
      }
    } catch( DOMException e1 ) {
      throw IOUtil.map( e1 );
    }
  }
}
TOP

Related Classes of de.sciss.eisenkraut.util.PrefsUtil

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.