package de.javasoft.synthetica.democenter.examples.jypropertytable;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.Font;
import java.lang.reflect.Method;

import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableCellEditor;

import de.javasoft.swing.JYPropertyTable;
import de.javasoft.swing.table.ColorComboBoxTableCellEditor;
import de.javasoft.swing.table.JYComboBoxTableCellEditor;
import de.javasoft.swing.table.PropertyTableModel;
import de.javasoft.swing.table.TableSeparator;

/**
 * Demonstrates how to create and install a custom 
 * ComboBox-TableCellEditor.
 */
@SuppressWarnings("serial")
public class CustomComboBoxTableCellEditor extends JFrame
{
  private JLabel testLabel;
  
  public CustomComboBoxTableCellEditor()
  {
    super("JYPropertyTable - Custom ComboBox-TableCellEditor");
    createAndAddComponents(getContentPane());

    //setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);      
    setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    setSize(400,350);
    setLocationRelativeTo(null);
    setVisible(true);
  }

  /**
   * Create components and add them to the container.
   */
  private void createAndAddComponents(final Container container)
  {
    testLabel = new JLabel("TestLabel");
    testLabel.setBorder(new EmptyBorder(10,10,10,10));    
    testLabel.setOpaque(true);
    testLabel.setBackground(new Color(0xBFFFFF));
    testLabel.setForeground(new Color(0x202020));
    testLabel.setBorder(new LineBorder(Color.ORANGE, 2));
    testLabel.setFont(new Font("Dialog", Font.PLAIN, 20));
    container.add(testLabel, BorderLayout.NORTH);
    
    JYPropertyTable table = new JYPropertyTable()
    {
      //override installEditors() to support runtime LAF-switch
      @Override
      protected void installEditors()
      {
        super.installEditors();
//@highlight
        //we use a custom comboBox model to increase usability by readable values (i.e. 2 will be displayed as LEFT)
        setPropertyEditor(HAlignmentComboModel.class, new HAlignmentCellEditor(defaultEditor));
        //replace default color editor with non-editable editor (means combo text field isn't editable)
        setPropertyEditor(Color.class, new ColorComboBoxTableCellEditor(getDefaultEditor(), false, false, false));
//@/highlight
      }
    };

    //add listener to update testLabel properties
    table.getModel().addTableModelListener(new ModelListener());
    initTable(table);

    //workaround to avoid border fallback to default scrollpane-border after a LAF switch - Java 1.5/JTable bug.
    JScrollPane scrollPane = new JScrollPane(table){
      @Override
      public void updateUI()
      {
        super.updateUI();
        setBorder(UIManager.getBorder("Table.scrollPaneBorder"));
      }
    };
    container.add(scrollPane);    
  }

  private void initTable(JYPropertyTable table)
  {
    table.addProperty("Text", testLabel.getText());
    table.addProperty("Font", testLabel.getFont());
    table.addSeparator();
    table.addProperty("Foreground", testLabel.getForeground());
    table.addProperty("Background", testLabel.getBackground());    
    table.addProperty("Opaque", testLabel.isOpaque());
    LineBorder border = (LineBorder)testLabel.getBorder();
    table.addProperty("BorderColor", border.getLineColor());
    table.addProperty("BorderSize", new SpinnerNumberModel(border.getThickness(), 0, 8, 1));
    table.addSeparator();
//@highlight
    table.addProperty("HorizontalAlignment", new HAlignmentComboModel());
//@/highlight
    table.addProperty("PreferredSize", testLabel.getPreferredSize());    
    table.addProperty("Visible", testLabel.isVisible());    
  }
  
  /**
   * Static main method for application startup. 
   */
  public static void main(String[] args)
  {
    EventQueue.invokeLater(new Runnable()
    {
      public void run()
      {
        try
        {
          UIManager.setLookAndFeel("de.javasoft.plaf.synthetica.SyntheticaStandardLookAndFeel");
          new CustomComboBoxTableCellEditor();
        }
        catch (Exception e)
        {
          e.printStackTrace();
        }
      }
    });
  }
  
  //
  //TableListener Class to apply testLabel settings
  //
  private class ModelListener implements TableModelListener
  {      
    public void tableChanged(TableModelEvent evt)
    {
      if (evt.getColumn() == 0)
        return;
      
      int row = evt.getFirstRow();
      PropertyTableModel model = (PropertyTableModel)evt.getSource();
      Object val = model.getPropertyValue(row);

      if (val instanceof TableSeparator)
        return;
//@highlight
      //convert model alignment value to integer
      else if (val instanceof HAlignmentComboModel)
      {  
        HAlignmentComboModel.Alignment align = (HAlignmentComboModel.Alignment)((ComboBoxModel)val).getSelectedItem();
        val = new Integer(align.toInt());
      }        
//@/highlight
      else if (model.getPropertyKey(row).toString().equals("BorderSize"))
      {
        int size = (Integer)((SpinnerNumberModel)val).getValue();
        LineBorder border = (LineBorder)testLabel.getBorder();        
        testLabel.setBorder(new LineBorder(border.getLineColor(), size));
        return;
      }
      else if (model.getPropertyKey(row).toString().equals("BorderColor"))
      {
        Color color = (Color)val; 
        LineBorder border = (LineBorder)testLabel.getBorder();
        testLabel.setBorder(new LineBorder(color, border.getThickness()));
        return;
      }

      //set value via reflection 
      try
      {
        Class<?> clazz = val.getClass();
        if (val instanceof Boolean)
          clazz = boolean.class;
        else if (val instanceof Integer)
          clazz = int.class;
        Method m = testLabel.getClass().getMethod("set"+model.getPropertyKey(row), clazz);
        m.invoke(testLabel, val);
      }
      catch (Exception e)
      {
        throw new RuntimeException(e);
      }
      
      testLabel.revalidate();
      testLabel.repaint();
    }
  }
  
  //
  //Horizontal Alignment TableCellEditor Class
  //
//@highlight
  static class HAlignmentCellEditor extends JYComboBoxTableCellEditor
  {
    public HAlignmentCellEditor(TableCellEditor defaultEditor)
    {
      super(defaultEditor, false, false);
      editorComponent.setModel(new HAlignmentComboModel());
    }
  }  
//@/highlight

  //
  //Horizontal Alignment ComboBox Model Class - has to be public or must implement Cloneable
  //
  public static class HAlignmentComboModel extends DefaultComboBoxModel
  {
//@highlight
    public static enum Alignment
    {
      LEFT(SwingConstants.LEFT),
      CENTER(SwingConstants.CENTER),
      RIGHT(SwingConstants.RIGHT),
      LEADING(SwingConstants.LEADING),
      TRAILING(SwingConstants.TRAILING);
          
      private int alignment;
      
      private Alignment(int alignment)
      {
        this.alignment = alignment;
      }
      
      public int toInt()
      {
        return alignment;
      }
    }
//@/highlight
    
    //initialize model
    {
      for (Alignment align : Alignment.values())
        super.addElement(align);
    }
    
    @Override
    public void addElement(Object object)
    {
    }
    
    @Override
    public void removeElement(Object object)
    {
    }
  }
}
