import java.awt.*;
import javax.swing.*;

import java.awt.event.*;

// Anzeige zweier identischer Bilder
// Alle Änderungen werden im rechten Fenster geändert
// Funktion:
/*        if aktueller Wert  < Fixpunkt
           then neuerWert=Minimum
           else neuerWert=Maximum


          |
maximum-  |                  |----------
          |                  |
          |                  |
          |                  |
minimum-  |------------------|
          |
          ----------------------------->
          0                  |       255
                             |
                          Fixpunkt

*/


// mit dem Schalter load, kann man beliebige Bilder laden
// Startpfad ist c:\picture


// Beispiel aus: Java 2D Graphics
// O´Reilly, Jonathan Knudsen, Seite 223 ff 

import java.awt.geom.*;

import java.io.*;
import java.awt.image.*;

import java.awt.color.*;

// import com.sun.image.codec.jpeg.*;


// für Opendialog
import java.io.File;
import javax.swing.JFileChooser;
import javax.swing.filechooser.*;
import java.util.Hashtable;
import java.util.Enumeration;


public class Dialog_Picture4_2D extends JFrame {


  JLabel LFixpoint = new JLabel("Fixpoint");
  JTextField TFixpoint= new JTextField("200");

  JLabel LMin = new JLabel("Minimum");
  JTextField TMin= new JTextField("10");

  JLabel LMax = new JLabel("Maximum");
  JTextField TMax= new JTextField("245");


  JSlider sliderFixpoint = new JSlider();
  JSlider sliderMin = new JSlider();
  JSlider sliderMax = new JSlider();

  JCheckBox checkRed = new JCheckBox("Farbe Rot",true);
  JCheckBox checkGreen = new JCheckBox("Farbe Green",true);
  JCheckBox checkBlue = new JCheckBox("Farbe Blue",true);

  JButton BnDraw= new JButton("Draw");

  JButton BnOpenPicture= new JButton("Load");

  CCanvas4 _canvasL = new CCanvas4(this, true, "grundfarben.jpg"); // bld.jpg"); //Stonehenge.jpg");
  CCanvas4 _canvasR = new CCanvas4(this, false, "grundfarben.jpg"); // bld.jpg"); //Stonehenge.jpg");


  public Dialog_Picture4_2D(String caption) {
    setTitle(caption);
    setGUI();
  }


  private void setGUI() {
    this.getContentPane().setLayout( new GridBagLayout() );

    JPanel pnTop = new JPanel();
    pnTop.setLayout( new GridBagLayout() );

    this.getContentPane().add(pnTop,
        new GridBagConstraints(0, 0, 2, 1, 0.0, 0.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.HORIZONTAL,
            new Insets(20,20,20,20), 0, 0));

  // -----------------------------
    pnTop.add(LFixpoint,
        new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.NONE,
            new Insets(0,10,20,20), 0, 0));

    pnTop.add(TFixpoint,
        new GridBagConstraints(1, 0, 1, 1, 100.0, 0.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.HORIZONTAL,
            new Insets(0,10,20,20), 0, 0));


    pnTop.add(LMin,
        new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.NONE,
            new Insets(0,10,20,20), 0, 0));

    pnTop.add(TMin,
        new GridBagConstraints(3, 0, 1, 1, 100.0, 0.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.HORIZONTAL,
            new Insets(0,10,20,20), 0, 0));


    pnTop.add(LMax,
        new GridBagConstraints(4, 0, 1, 1, 0.0, 0.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.NONE,
            new Insets(0,10,20,20), 0, 0));

    pnTop.add(TMax,
        new GridBagConstraints(5, 0, 1, 1, 100.0, 0.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.HORIZONTAL,
            new Insets(0,10,20,20), 0, 0));



   // ------------------------------
    pnTop.add(BnDraw,
        new GridBagConstraints(6, 0, 1, 3, 0.0, 0.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.NONE,
            new Insets(0,20,20,20), 0, 0));

    pnTop.add(BnOpenPicture,
        new GridBagConstraints(7, 0, 1, 3, 0.0, 0.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.NONE,
            new Insets(0,20,20,20), 0, 0));




    BnDraw.addActionListener(new java.awt.event.ActionListener() {

      public void actionPerformed(ActionEvent e) {
        BnDraw_Click();
      }
    });

    BnOpenPicture.addActionListener(new java.awt.event.ActionListener() {

      public void actionPerformed(ActionEvent e) {
        BnOpenPicture_Click();
      }
    });



    sliderFixpoint.setMinimum(0);
    sliderFixpoint.setMaximum(255); // hunderstels
    sliderFixpoint.setValue(200);
    pnTop.add(sliderFixpoint,
        new GridBagConstraints(0, 1, 2, 1, 100.0, 0.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.HORIZONTAL,
            new Insets(0,10,20,20), 0, 0));


   sliderFixpoint.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                sliderFixpointchangeState1(evt);
            }
   });
    // -----------------------------

    sliderMin.setMaximum(255);
    sliderMin.setMinimum(0);
    sliderMin.setValue(10);
    pnTop.add(sliderMin,
        new GridBagConstraints(2, 1, 2, 1, 100.0, 0.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.HORIZONTAL,
            new Insets(0,10,20,20), 0, 0));


   sliderMin.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                sliderMinchangeState1(evt);
            }
   });
    // -----------------------------
    sliderMax.setMaximum(255);
    sliderMax.setMinimum(0);
    sliderMax.setValue(245);
    pnTop.add(sliderMax,
        new GridBagConstraints(4, 1, 2, 1, 100.0, 0.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.HORIZONTAL,
            new Insets(0,10,20,20), 0, 0));


   sliderMax.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                sliderMaxchangeState1(evt);
            }
   });

   // ------------
    checkRed.addActionListener(new java.awt.event.ActionListener() {

      public void actionPerformed(ActionEvent e) {
        checkRed_click();
      }
    });
    checkGreen.addActionListener(new java.awt.event.ActionListener() {

      public void actionPerformed(ActionEvent e) {
        checkGreen_click();
      }
    });
    checkBlue.addActionListener(new java.awt.event.ActionListener() {

      public void actionPerformed(ActionEvent e) {
        checkBlue_click();
      }
    });
   // ------------


    pnTop.add(checkRed,
        new GridBagConstraints(1, 2, 2, 1, 100.0, 0.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.HORIZONTAL,
            new Insets(0,10,20,20), 0, 0));
    pnTop.add(checkGreen,
        new GridBagConstraints(3, 2, 2, 1, 100.0, 0.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.HORIZONTAL,
            new Insets(0,10,20,20), 0, 0));
    pnTop.add(checkBlue,
        new GridBagConstraints(5, 2, 2, 1, 100.0, 0.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.HORIZONTAL,
            new Insets(0,10,20,20), 0, 0));


   // ------------

    this.getContentPane().add(_canvasL,
        new GridBagConstraints(0, 3, 1, 1, 100.0, 100.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.BOTH,
            new Insets(0,20,20,20), 0, 0));
    this.getContentPane().add(_canvasR,
        new GridBagConstraints(1, 3, 1, 1, 100.0, 100.0
            ,GridBagConstraints.WEST,
            GridBagConstraints.BOTH,
            new Insets(0,20,20,20), 0, 0));

  }


  private void BnOpenPicture_Click() {
   JFileChooser jFileChooser1 = new JFileChooser();
   String sFileName;

   MyFileFilter4 pictFilter;

	pictFilter = new MyFileFilter4( "jpg", "Bilder");

   jFileChooser1.setMultiSelectionEnabled(false);
   jFileChooser1.setCurrentDirectory( new File("D:\\hs-harz\\Vorlesungen\\java\\Grafik2D\\") );
   jFileChooser1.addChoosableFileFilter(pictFilter);

   if (JFileChooser.APPROVE_OPTION == jFileChooser1.showOpenDialog(this)) {
      sFileName = jFileChooser1.getSelectedFile().getPath();
      _canvasL.setPicture(sFileName);
      _canvasR.setPicture(sFileName);
      _canvasR.updateUI();
      _canvasL.updateUI();
    }
  }

  void checkRed_click() {
    _canvasR.bRed = checkRed.isSelected();
    _canvasR.updateUI();
  }

  void checkGreen_click() {
    _canvasR.bGreen = checkGreen.isSelected();
    _canvasR.updateUI();
  }

  void checkBlue_click() {
    _canvasR.bBlue = checkBlue.isSelected();
    _canvasR.updateUI();
  }

  // wird aufgerufen, wenn der linke Slider verändert wird
  private void sliderFixpointchangeState1(javax.swing.event.ChangeEvent evt) {
     int i = (int) sliderFixpoint.getValue();
     TFixpoint.setText( Integer.toString(i) );
     _canvasR.Fixpoint = (int)i;


    if ( CBasis.IVal( TMin.getText() ) ) {
      _canvasR.Min = (int) CBasis.getIValResult();
    }

    if ( CBasis.IVal( TMax.getText() ) ) {
      _canvasR.Max = (int) CBasis.getIValResult();
    }
    
    _canvasR.bRed = checkRed.isSelected();
    _canvasR.bGreen = checkGreen.isSelected();
    _canvasR.bBlue = checkBlue.isSelected();

    _canvasR.updateUI();
    _canvasL.updateUI();
  }

  // wird aufgerufen, wenn der rechte Slider verändert wird
  private void sliderMinchangeState1(javax.swing.event.ChangeEvent evt) {
     int i = sliderMin.getValue();
     TMin.setText( Integer.toString(i) );
     _canvasR.Min = i;

    if ( CBasis.IVal( TFixpoint.getText() ) ) {
      _canvasR.Fixpoint = (int) CBasis.getIValResult();
    }

    if ( CBasis.IVal( TMax.getText() ) ) {
      _canvasR.Max = (int) CBasis.getIValResult();
    }

    _canvasR.bRed = checkRed.isSelected();
    _canvasR.bGreen = checkGreen.isSelected();
    _canvasR.bBlue = checkBlue.isSelected();

    _canvasR.updateUI();
    _canvasL.updateUI();

        /*  ab jdk 1.3 dieser Source Code */
        /*
          Integer I = (Integer) slider1.getValue();
          System.out.println( I.intValue() );
        */
        /*  bis jdk 1.2 dieser Source Code */
        /*
          int i = slider1.getValue();
          System.out.println( i );
         */
  }



  // wird aufgerufen, wenn der rechte Slider verändert wird
  private void sliderMaxchangeState1(javax.swing.event.ChangeEvent evt) {
     int i = sliderMax.getValue();
     TMax.setText( Integer.toString(i) );
     _canvasR.Max = i;

    if ( CBasis.IVal( TFixpoint.getText() ) ) {
      _canvasR.Fixpoint = (int) CBasis.getIValResult();
    }

    if ( CBasis.IVal( TMin.getText() ) ) {
      _canvasR.Min = (int) CBasis.getIValResult();
    }

    _canvasR.bRed = checkRed.isSelected();
    _canvasR.bGreen = checkGreen.isSelected();
    _canvasR.bBlue = checkBlue.isSelected();
    
    _canvasR.updateUI();
    _canvasL.updateUI();

        /*  ab jdk 1.3 dieser Source Code */
        /*
          Integer I = (Integer) slider1.getValue();
          System.out.println( I.intValue() );
        */
        /*  bis jdk 1.2 dieser Source Code */
        /*
          int i = slider1.getValue();
          System.out.println( i );
         */
  }



  private void BnDraw_Click() {
    if ( CBasis.DVal( TFixpoint.getText() ) ) {
      _canvasR.Fixpoint = (int) CBasis.getDValResult();
    }
    if ( CBasis.IVal( TMin.getText() ) ) {
      _canvasR.Min = (int) CBasis.getIValResult();
    }
    if ( CBasis.IVal( TMax.getText() ) ) {
      _canvasR.Max = (int) CBasis.getIValResult();
    }


    sliderFixpoint.setValue( _canvasR.Fixpoint );
    sliderMin.setValue( _canvasR.Min );
    sliderMax.setValue( _canvasR.Max );

    _canvasR.bRed = checkRed.isSelected();
    _canvasR.bGreen = checkGreen.isSelected();
    _canvasR.bBlue = checkBlue.isSelected();
    
    _canvasR.updateUI();

    _canvasL.updateUI();
  }




    // dient zum Beenden
  protected void processWindowEvent(WindowEvent e) {
    super.processWindowEvent(e);
    if(e.getID() == WindowEvent.WINDOW_CLOSING) {
      System.exit(0);
    }
  }



    public static void main(String args[]) {
      Dialog_Picture4_2D f = new Dialog_Picture4_2D("Dialog_Picture4_2D");
     	f.setSize(900,700);
    	f.setVisible(true);
    }


}


class CCanvas4 extends JPanel {

  private Component cmp;
  private BufferedImage image;

  public int Fixpoint=200;
  public int Min=10;
  public int Max=245;
  public boolean bFixed=true;

  public boolean bRed=true;
  public boolean bGreen=true;
  public boolean bBlue=true;

  public CCanvas4(Component cmp, boolean bFixed, String sFilename) {
    this.cmp = cmp;
    image = loadPicture(sFilename);
    this.bFixed = bFixed;
  }

  public void setPicture(String sFilename) {
    image = loadPicture(sFilename);
  }

  private BufferedImage loadPicture(String filename)  {
    BufferedImage image=null;
    try {
     	FileInputStream in = new FileInputStream(filename);
      JPEGImageDecoder decoder = JPEGCodec.createJPEGDecoder(in);
      image = decoder.decodeAsBufferedImage();
      in.close();
    }
    catch (IOException e) {
    }
    return image;
  }

  public void paint (Graphics g) {
    // holt die Abmessungen des Canvas
    Rectangle r = new Rectangle();  // double wert
    g.getClipBounds(r);
        // Löschen des Bildschirms
    g.setColor(Color.white);
    g.fillRect(0,0, (int)r.getWidth(), (int)r.getHeight() );

    Graphics2D g2 = (Graphics2D) g;


    if (bFixed) {
      g2.drawImage(image,0,0, Color.red, cmp);
    }
    else {

      int iw = image.getWidth(this);
      int ih = image.getHeight(this);
      int x = 0;
      int y = 0;
      int w = (int)r.getWidth();
      int h = (int)r.getHeight();

      BufferedImageOp biop = null;
      BufferedImage bimg = new BufferedImage(iw,ih,BufferedImage.TYPE_INT_RGB);
                                 //BufferedImage.TYPE_INT_RGB);

      ThresholdOp myOp = new ThresholdOp(Fixpoint, Min,Max, bRed, bGreen, bBlue);
      myOp.filter(image,bimg);

      g2.drawImage(bimg,0,0, Color.red, cmp);
    }

  }

}


class ThresholdOp implements BufferedImageOp {
  private int Fixpoint=100;
  private int Min=50;
  private int Max=200;

  private boolean bRed=true;
  private boolean bGreen=true;
  private boolean bBlue=true;

  public ThresholdOp(int Fixpoint, int Min, int Max,
                      boolean bRed, boolean bGreen, boolean bBlue) {
    this.Fixpoint = Fixpoint;
    this.Min = Min;
    this.Max = Max;
    this.bRed = bRed;
    this.bGreen = bGreen;
    this.bBlue = bBlue;
    //System.out.println(bRed+"   "+bGreen+"   "+bBlue);
  }

  public int myFunction(int color) {
    if (color<Fixpoint)
      return Min;
    else
     return Max;
  }

  public BufferedImage filter(BufferedImage src, BufferedImage dst) {
    if (dst == null) dst = createCompatibleDestImage(src,null);
    int red, green, blue;
    for (int x=0; x<src.getWidth(); x++) {
      for (int y=0; y<src.getHeight(); y++) {
        int srcPixel = src.getRGB(x,y); // Farbwert
        Color c = new Color(srcPixel);
        // Farben trennen und die Funktion einzeln aufrufen
        if (bRed)
         red = myFunction( c.getRed() );
        else
         red = c.getRed();

        if (bGreen)
         green = myFunction( c.getGreen() );
        else
         green = c.getGreen();

        if (bBlue)
         blue = myFunction( c.getBlue() );
        else
         blue = c.getBlue();

        // Farben zusammensetzen
        dst.setRGB(x,y, new Color(red,green,blue).getRGB() );

      }
    }
    return dst;
  }


  // muss public sein
  public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel dstCM) {
    BufferedImage image;
    if (dstCM == null) dstCM = src.getColorModel();

    int width = src.getWidth();
    int height = src.getHeight();
    image = new BufferedImage(dstCM,
           dstCM.createCompatibleWritableRaster(width, height),
           dstCM.isAlphaPremultiplied(),
           null
    );

    return image;
  } // createCompatibleDestImage


  public final Rectangle2D getBounds2D(BufferedImage image) {
    return image.getRaster().getBounds();
  }

  public final Point2D getPoint2D(Point2D srcPoint, Point2D dstPoint) {
    if (dstPoint==null) {
       dstPoint = new Point2D.Float();
    }
    dstPoint.setLocation( srcPoint.getX(), srcPoint.getY() );
    return dstPoint;
  }

  // tut nichts
  public final RenderingHints getRenderingHints() {
    return null;
  }


}


class CBasis {
    public static final int C_LEER = 1;
    public static final int C_KEINEZAHL = 2;
    public static final int C_ZUKLEIN = 3;
    public static final int C_ZUGROSS = 4;

      // Konstanten für den Error Code als String
    public static final String SZ_LEER = "Leerer Text";
    public static final String SZ_KEINEZAHL = "Konvertierung schlug fehl";
    public static final String SZ_ZUKLEIN = "Für den Bereich zu klein";
    public static final String SZ_ZUGROSS = "Für den Bereich zu groß";

    private static int intVal;          // speichert das Ergebnis
    private static long longVal;        // speichert das Ergebnis
    private static double dblVal;       // speichert das Ergebnis

    private static int ValError = 0;   // speichert den Konvertierungfehler


    /**
    * description: überprüft, ob der String eine Integerzahl ist
    * Verwendet eine interne Variable zum Speichern des Wertes
    * @see DVal, LVal, getErrorCode
    *
    * @version     1.0  07.07.2002
    * @author      Michael Wilhelm HS Harz, FB AI
    * @param String sText
    * @return boolean
    * @exception keine
    */
    public static boolean IVal(String sText) {
        // erläuterung von iIVal = Integer.valueOf(szText).intValue();
        boolean result = true;
        String s;
        s = new String(sText); // neues Objekt
        s.trim();
        if (s.length() == 0) {
            ValError = C_LEER;
            intVal = 0;
            result = false;
        }
        else {
            try {
                intVal = Integer.valueOf(sText).intValue();
                ValError = 0;
            }
            catch (NumberFormatException e) {
                // Check ob die "Zahl" für den Integerbereich zu klein oder zu groß
                // System.err.println(e);
                try {
                    dblVal = Double.valueOf(sText).doubleValue();
                    if ( dblVal<Integer.MIN_VALUE) {
                      ValError = C_ZUKLEIN;
                    }
                    if ( dblVal>Integer.MAX_VALUE) {
                      ValError = C_ZUGROSS;
                    }
                }
                catch (NumberFormatException e2) {
                    // Hier könnte noch eine genauere Abfrage integriert werde,
                    // ob die Zahl nicht zu groß für den int-Bereich ist
                    // System.err.println(e);
                    ValError = C_KEINEZAHL;
                    intVal = 0;
                    result = false;
                }
                intVal = 0;
                result = false;
            }
        }
        return result;
    } // IVal


    /**
    * description: gibt den konvertierten Wert aus
    * @see IVal, DVal, LVal, getErrorCode
    *
    * @version     1.0  07.07.2002
    * @author Michael Wilhelm HS Harz, FB AI
    * @param String sText
    * @return String
    * @exception keine
    * @use gibt den Wert der Konvertierung aus
    * @see #setIValError
    * @see #setLValError
    * @see #setDValError
    */
    public static int getIValResult() {
       return intVal;
    }



    /**
    * DVal
    * description: überprüft, ob der String eine Double-Zahl ist
    * Verwendet eine interne Variable zum Speichern des Wertes
    * @see IVal, LVal, getErrorCode
    *
    * @version     1.0  07.07.2002
    * @author      Michael Wilhelm HS Harz, FB AI
    * @param String sText
    * @return boolean
    * @exception keine
    */
    public static boolean DVal(String sText) {
        // erläuterung von iIVal = Integer.valueOf(szText).intValue();
        boolean result = true;
        String s;
        s = new String(sText); // neues Objekt
        s.trim();
        if (s.length() == 0) {
            ValError = C_LEER;
            dblVal = 0;
            result = false;
        }
        else {
            try {
                sText = sText.replace(',','.');
                dblVal = Double.valueOf(sText).doubleValue();
                ValError = 0;
            }
            catch (NumberFormatException e) {
                ValError = C_KEINEZAHL;
                dblVal = 0;
                result = false;
            }
        }
        return result;
    } // DVal


    /**
    * description: gibt den konvertierten Wert aus
    * @see IVal, DVal, LVal, getErrorCode
    *
    * @version     1.0  07.07.2002
    * @author Michael Wilhelm HS Harz, FB AI
    * @param keinen
    * @return double
    * @exception keine
    * @use gibt den Wert der Konvertierung aus
    * @see #getIValError
    * @see #setLValError
    * @see #setDValError
    */
    public static double getDValResult() {
       return dblVal;
    }


}






class MyFileFilter4 extends javax.swing.filechooser.FileFilter {

    private static String TYPE_UNKNOWN = "Type Unknown";
    private static String HIDDEN_FILE = "Hidden File";

    private Hashtable filters = null;
    private String description = null;
    private String fullDescription = null;
    private boolean useExtensionsInDescription = true;

    /**
     * Creates a file filter. If no filters are added, then all
     * files are accepted.
     *
     * @see #addExtension
     */
    public MyFileFilter4() {
     	this((String) null, (String) null);
    }

    /**
     * Creates a file filter that accepts files with the given extension.
     * Example: new ExampleFileFilter("jpg");
     *
     * @see #addExtension
     */
    public MyFileFilter4(String extension) {
     	this(extension,null);
    }

    /**
     * Creates a file filter that accepts the given file type.
     * Example: new ExampleFileFilter("jpg", "JPEG Image Images");
     *
     * Note that the "." before the extension is not needed. If
     * provided, it will be ignored.
     *
     * @see #addExtension
     */
    public MyFileFilter4(String extension, String description) {
     	this(new String[] {extension}, description);
    }

    /**
     * Creates a file filter from the given string array.
     * Example: new ExampleFileFilter(String {"gif", "jpg"});
     *
     * Note that the "." before the extension is not needed adn
     * will be ignored.
     *
     * @see #addExtension
     */
    public MyFileFilter4(String[] filters) {
     	this(filters, null);
    }

    /**
     * Creates a file filter from the given string array and description.
     * Example: new ExampleFileFilter(String {"gif", "jpg"}, "Gif and JPG Images");
     *
     * Note that the "." before the extension is not needed and will be ignored.
     *
     * @see #addExtension
     */
    public MyFileFilter4(String[] filters, String description) {
      this.filters = new Hashtable(filters.length);
      for (int i = 0; i < filters.length; i++) {
          // add filters one by one
          addExtension(filters[i]);
      }
      setDescription(description);
    }

    /**
     * Return true if this file should be shown in the directory pane,
     * false if it shouldn't.
     *
     * Files that begin with "." are ignored.
     *
     * @see #getExtension
     * @see FileFilter#accepts
     */
    public boolean accept(File f) {
      if(f != null) {
          if(f.isDirectory()) {
        return true;
          }
          String extension = getExtension(f);
          if(extension != null && filters.get(getExtension(f)) != null) {
        return true;
          };
      }
      return false;
    }

    /**
     * Return the extension portion of the file's name .
     *
     * @see #getExtension
     * @see FileFilter#accept
     */
     public String getExtension(File f) {
        if(f != null) {
            String filename = f.getName();
            int i = filename.lastIndexOf('.');
            if(i>0 && i<filename.length()-1) {
          return filename.substring(i+1).toLowerCase();
            };
        }
        return null;
    }

    /**
     * Adds a filetype "dot" extension to filter against.
     *
     * For example: the following code will create a filter that filters
     * out all files except those that end in ".jpg" and ".tif":
     *
     *   ExampleFileFilter filter = new ExampleFileFilter();
     *   filter.addExtension("jpg");
     *   filter.addExtension("tif");
     *
     * Note that the "." before the extension is not needed and will be ignored.
     */
    public void addExtension(String extension) {
      if(filters == null) {
          filters = new Hashtable(5);
      }
      filters.put(extension.toLowerCase(), this);
      fullDescription = null;
    }


    /**
     * Returns the human readable description of this filter. For
     * example: "JPEG and GIF Image Files (*.jpg, *.gif)"
     *
     * @see setDescription
     * @see setExtensionListInDescription
     * @see isExtensionListInDescription
     * @see FileFilter#getDescription
     */
    public String getDescription() {
      if(fullDescription == null) {
          if(description == null || isExtensionListInDescription()) {
        if(description != null) {
            fullDescription = description;
        }
        fullDescription += " (";
        // build the description from the extension list
        Enumeration extensions = filters.keys();
        if(extensions != null) {
            fullDescription += "." + (String) extensions.nextElement();
            while (extensions.hasMoreElements()) {
          fullDescription += ", " + (String) extensions.nextElement();
            }
        }
        fullDescription += ")";
          } else {
        fullDescription = description;
          }
      }
      return fullDescription;
    }

    /**
     * Sets the human readable description of this filter. For
     * example: filter.setDescription("Gif and JPG Images");
     *
     * @see setDescription
     * @see setExtensionListInDescription
     * @see isExtensionListInDescription
     */
    public void setDescription(String description) {
   	  this.description = description;
    	fullDescription = null;
    }

    /**
     * Determines whether the extension list (.jpg, .gif, etc) should
     * show up in the human readable description.
     *
     * Only relevent if a description was provided in the constructor
     * or using setDescription();
     *
     * @see getDescription
     * @see setDescription
     * @see isExtensionListInDescription
     */
    public void setExtensionListInDescription(boolean b) {
      useExtensionsInDescription = b;
      fullDescription = null;
    }

    /**
     * Returns whether the extension list (.jpg, .gif, etc) should
     * show up in the human readable description.
     *
     * Only relevent if a description was provided in the constructor
     * or using setDescription();
     *
     * @see getDescription
     * @see setDescription
     * @see setExtensionListInDescription
     */
    public boolean isExtensionListInDescription() {
     	return useExtensionsInDescription;
    }
}  // MyFilter




