import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;

import java.util.*;
import java.awt.*;
import java.awt.event.*;

public class SharedModelDemo extends JApplet {
    JTextArea output;
    JList list; 
    JTable table;
    String newline = "\n";
    ListSelectionModel listSelectionModel;

    private boolean inAnApplet = true;

    //Hack to avoid ugly message about system event access check.
    public SharedModelDemo() {
        this(true);
    }

    public SharedModelDemo(boolean inAnApplet) {
        this.inAnApplet = inAnApplet;
        if (inAnApplet) {
            getRootPane().putClientProperty("defeatSystemEventQueueCheck",
                                            Boolean.TRUE);
        }
    }

    public void init() {
        //newline = System.getProperty("line.separator");

        //The data 
	Vector data = new Vector(7);
	String[] columnNames = { "French", "Spanish", "Italian" };
        String[] oneData =     { "un",     "uno",     "uno"     };
        String[] twoData =     { "deux",   "dos",     "due"     };
        String[] threeData =   { "trois",  "tres",    "tre"     };
        String[] fourData =    { "quatre", "cuatro",  "quattro" };
        String[] fiveData =    { "cinq",   "cinco",   "cinque"  };
        String[] sixData =     { "six",    "seis",    "sei"     };
        String[] sevenData =   { "sept",   "siete",   "sette"   };

	//Build the model.
	SharedDataModel dataModel = new SharedDataModel(columnNames);
	dataModel.addElement(oneData);
	dataModel.addElement(twoData);
        dataModel.addElement(threeData);
        dataModel.addElement(fourData);
        dataModel.addElement(fiveData);
        dataModel.addElement(sixData);
        dataModel.addElement(sevenData);

        list = new JList(dataModel);
	list.setCellRenderer(new DefaultListCellRenderer() {
	    public Component getListCellRendererComponent(JList l, 
							  Object value,
							  int i,
							  boolean s,
							  boolean f) {
		String[] array = (String[])value;
		return super.getListCellRendererComponent(l,
							  array[0],
							  i, s, f);
	    }
	});

	listSelectionModel = list.getSelectionModel();
        listSelectionModel.addListSelectionListener(
				new SharedListSelectionHandler());
        JScrollPane listPane = new JScrollPane(list);

        table = new JTable(dataModel);
        table.setSelectionModel(listSelectionModel);
        JScrollPane tablePane = new JScrollPane(table);

	//build control area (use default FlowLayout)
	JPanel controlPane = new JPanel();
	String[] modes = { "SINGLE_SELECTION",
	    		   "SINGLE_INTERVAL_SELECTION",
			   "MULTIPLE_INTERVAL_SELECTION" };

	final JComboBox comboBox = new JComboBox(modes);
	comboBox.setSelectedIndex(2);
	comboBox.addActionListener(new ActionListener() {
	    public void actionPerformed(ActionEvent e) {
		String newMode = (String)comboBox.getSelectedItem();
		if (newMode.equals("SINGLE_SELECTION")) {
		    listSelectionModel.setSelectionMode(
			ListSelectionModel.SINGLE_SELECTION);
		} else if (newMode.equals("SINGLE_INTERVAL_SELECTION")) {
		    listSelectionModel.setSelectionMode(
			ListSelectionModel.SINGLE_INTERVAL_SELECTION);
		} else {
		    listSelectionModel.setSelectionMode(
			ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
		}
		output.append("----------"
		              + "Mode: " + newMode
		              + "----------" + newline);
	    }
	});
	controlPane.add(new JLabel("Selection mode:"));
	controlPane.add(comboBox);

        //build output area
        output = new JTextArea(10, 40);
        output.setEditable(false);
        JScrollPane outputPane = new JScrollPane(output,
                         ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
                         ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);

        //do the layout
        JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
        setContentPane(splitPane);

        //XXX: used a Box at first, but you can't call setMinimumSize on it
        JPanel topHalf = new JPanel();
        topHalf.setLayout(new BoxLayout(topHalf, BoxLayout.X_AXIS));
	JPanel listContainer = new JPanel(new GridLayout(1,1));
	listContainer.setBorder(BorderFactory.createTitledBorder(
						"List"));
	listContainer.add(listPane);
	JPanel tableContainer = new JPanel(new GridLayout(1,1));
	tableContainer.setBorder(BorderFactory.createTitledBorder(
						"Table"));
	tableContainer.add(tablePane);
        tablePane.setPreferredSize(new Dimension(300, 100));
	topHalf.setBorder(BorderFactory.createEmptyBorder(5,5,0,5));
        topHalf.add(listContainer);
        topHalf.add(tableContainer);

        topHalf.setMinimumSize(new Dimension(400, 50));
        topHalf.setPreferredSize(new Dimension(400, 110));
        splitPane.add(topHalf);

	JPanel bottomHalf = new JPanel(new BorderLayout());
	bottomHalf.add(controlPane, BorderLayout.NORTH);
	bottomHalf.add(outputPane, BorderLayout.CENTER);
	//XXX: the next line is necessary if bottomHalf is a scroll pane:
        //bottomHalf.setMinimumSize(new Dimension(400, 50));
        bottomHalf.setPreferredSize(new Dimension(450, 135));
        splitPane.add(bottomHalf);
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame("SharedModelDemo");
        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });

        SharedModelDemo modelDemo = new SharedModelDemo(false);
        modelDemo.init();

        frame.setContentPane(modelDemo);
        frame.pack();
        frame.setVisible(true);
    }

    class SharedListSelectionHandler implements ListSelectionListener {
        public void valueChanged(ListSelectionEvent e) { 
	    ListSelectionModel lsm = (ListSelectionModel)e.getSource();

            int firstIndex = e.getFirstIndex();
            int lastIndex = e.getLastIndex();
	    boolean isAdjusting = e.getValueIsAdjusting(); 
            output.append("Event for indexes "
			  + firstIndex + " - " + lastIndex
	   		  + "; isAdjusting is " + isAdjusting
			  + "; selected indexes:");

	    if (lsm.isSelectionEmpty()) {
		output.append(" <none>");
	    } else {
	        // Find out which indexes are selected.
	        int minIndex = lsm.getMinSelectionIndex();
	        int maxIndex = lsm.getMaxSelectionIndex();
	        for (int i = minIndex; i <= maxIndex; i++) {
		    if (lsm.isSelectedIndex(i)) {
                        output.append(" " + i);
		    }
		}
	    }
            output.append(newline);
        }
    }

    class SharedDataModel extends DefaultListModel
   			  implements TableModel {

	public String[] columnNames;

	public SharedDataModel(String[] columnNames) {
	    super();
	    this.columnNames = columnNames;
	}

	private TableModel tableModel = new AbstractTableModel() {
            public String getColumnName(int column) {
	        return columnNames[column];
	    }
            public int getRowCount() { 
		return size();
	    }
            public int getColumnCount() {
	        return columnNames.length;
	    }
            public Object getValueAt(int row, int column) {
		String[] rowData = (String [])elementAt(row);
                return rowData[column];
            }
            public boolean isCellEditable(int row, int column) {
		return true;
	    }
            public void setValueAt(Object value, int row, int column) {
		String newValue = (String)value;
		String[] rowData = (String [])elementAt(row);
                rowData[column] = newValue;
		list.revalidate(); 
            }
        };

	//Implement the TableModel interface.
	public int getRowCount() {
	    return tableModel.getRowCount();
	}
	public int getColumnCount() {
	    return tableModel.getColumnCount();
	}
	public String getColumnName(int columnIndex) {
	    return tableModel.getColumnName(columnIndex);
	}
	public Class getColumnClass(int columnIndex) {
	    return tableModel.getColumnClass(columnIndex);
	}
	public boolean isCellEditable(int rowIndex, int columnIndex) {
	    return tableModel.isCellEditable(rowIndex, columnIndex);
	}
	public Object getValueAt(int rowIndex, int columnIndex) {
	    return tableModel.getValueAt(rowIndex, columnIndex);
	}
	public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
	    tableModel.setValueAt(aValue, rowIndex, columnIndex);
	}
	public void addTableModelListener(TableModelListener l) {
	    tableModel.addTableModelListener(l);
	}
	public void removeTableModelListener(TableModelListener l) {
	    tableModel.removeTableModelListener(l);
	}
    }
}
