/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is NetBeans. The Initial Developer of the Original * Code is Sun Microsystems, Inc. Portions Copyright 1997-2004 Sun * Microsystems, Inc. All Rights Reserved. */ package org.netbeans.examples.modules.minicomposer; import java.awt.BorderLayout; import java.awt.Component; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.BeanInfo; import java.beans.PropertyChangeEvent; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.swing.DefaultCellEditor; import javax.swing.DefaultListCellRenderer; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.AbstractTableModel; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableColumnModel; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; import org.openide.ErrorManager; import org.openide.loaders.DataObject; import org.openide.loaders.MultiDataObject; import org.openide.nodes.Node; import org.openide.nodes.NodeAdapter; import org.openide.nodes.NodeListener; import org.openide.text.CloneableEditorSupport; import org.openide.util.HelpCtx; import org.openide.util.NbBundle; import org.openide.util.Task; import org.openide.util.TaskListener; import org.openide.util.WeakListener; import org.openide.windows.CloneableTopComponent; import org.openide.windows.Mode; import org.openide.windows.WindowManager; public class ScorePanel extends CloneableTopComponent { private static final long serialVersionUID = 7204432764586558961L; private MultiDataObject.Entry entry; private ScoreCookie cookie; private ScoreOpenSupport support; private Score score; private NodeListener listener; public ScorePanel(MultiDataObject.Entry entry) { super(/*XXX:entry.getDataObject()*/); this.entry = entry; init(); } protected CloneableTopComponent createClonedObject() { return new ScorePanel(entry); } /** * @serialData Super, then the MultiDataObject.Entry to represent. */ public void writeExternal(ObjectOutput oo) throws IOException { super.writeExternal(oo); oo.writeObject(entry); } /** for externalization only */ public ScorePanel() { } /** * @serialData #see writeExternal */ public void readExternal(ObjectInput oi) throws IOException, ClassNotFoundException { super.readExternal(oi); entry = (MultiDataObject.Entry)oi.readObject(); init(); } public void open() { Mode mode = WindowManager.getDefault().findMode(CloneableEditorSupport.EDITOR_MODE); if (mode != null) mode.dockInto(this); super.open(); } protected boolean closeLast() { if (support == null) { // Should not happen. ErrorManager.getDefault().log(ErrorManager.WARNING, "WARNING: no ScoreOpenSupport, will just close"); return true; } boolean ok = support.canClose(); return ok; } protected void updateNameAndIcon(DataObject o, Node n) { String displayName = n.getDisplayName(); if (o.isModified()) { setName(NbBundle.getMessage(ScorePanel.class, "LBL_modified_name", displayName)); } else { setName(displayName); } setIcon(n.getIcon(BeanInfo.ICON_COLOR_16x16)); } public HelpCtx getHelpCtx() { return new HelpCtx("org.netbeans.examples.modules.minicomposer.visual"); } private void init() { if (!SwingUtilities.isEventDispatchThread()) { SwingUtilities.invokeLater(new Runnable() { public void run() { init(); } }); return; } putClientProperty("PersistenceType", "OnlyOpened"); // [PENDING] Should also fire Env.PROP_VALID when DataObject.PROP_VALID // changes. Presumably editor supports do this for you, somewhere, though // it is not clear where. final DataObject o = entry.getDataObject(); final Node n = o.getNodeDelegate(); updateNameAndIcon(o, n); listener = new NodeAdapter() { public void propertyChange(PropertyChangeEvent ev) { String prop = ev.getPropertyName(); if (prop == null || prop.equals(Node.PROP_DISPLAY_NAME) || prop.equals(Node.PROP_ICON) || prop.equals(DataObject.PROP_MODIFIED)) { updateNameAndIcon(o, n); } } }; n.addNodeListener(WeakListener.node(listener, n)); o.addPropertyChangeListener(WeakListener.propertyChange(listener, o)); setLayout(new BorderLayout()); cookie = (ScoreCookie)entry.getDataObject().getCookie(ScoreCookie.class); if (cookie == null) { JLabel label = new JLabel(NbBundle.getMessage(ScorePanel.class, "LBL_cannot_load")); label.setHorizontalAlignment(SwingConstants.CENTER); add(label, BorderLayout.SOUTH); return; } // If you are having trouble compiling this line: Task t = cookie.prepare(); // Then see: // http://www.netbeans.org/servlets/ReadMsg?msgId=304601&listName=nbdev class DeferredRun implements TaskListener, Runnable { public void taskFinished(Task t2) { SwingUtilities.invokeLater(this); } public void run() { init2(); } } t.addTaskListener(new DeferredRun()); JLabel label = new JLabel(NbBundle.getMessage(ScorePanel.class, "LBL_loading")); label.setHorizontalAlignment(SwingConstants.CENTER); add(label, BorderLayout.SOUTH); // Just for safety: score = new Score(Collections.EMPTY_LIST); support = (ScoreOpenSupport)entry.getDataObject().getCookie(ScoreOpenSupport.class); } private void init2() { try { score = cookie.getScore(); } catch (IOException ioe) { ErrorManager.getDefault().notify(ioe); return; } TableColumnModel columns = new DefaultTableColumnModel(); TableColumn column = new TableColumn(0, 150, new PulldownRenderer(Score.TONES_LONG), new PulldownEditor(Score.TONES_LONG)); column.setHeaderValue(NbBundle.getMessage(ScorePanel.class, "LBL_header_tone")); columns.addColumn(column); column = new TableColumn(1, 150, new PulldownRenderer(Score.OCTAVES_LONG), new PulldownEditor(Score.OCTAVES_LONG)); column.setHeaderValue(NbBundle.getMessage(ScorePanel.class, "LBL_header_octave")); columns.addColumn(column); column = new TableColumn(2, 150, new PulldownRenderer(Score.DURATIONS_LONG), new PulldownEditor(Score.DURATIONS_LONG)); column.setHeaderValue(NbBundle.getMessage(ScorePanel.class, "LBL_header_duration")); columns.addColumn(column); final JTable table = new JTable(new Model(), columns); removeAll(); add(new JScrollPane(table), BorderLayout.CENTER); JButton add = new JButton(NbBundle.getMessage(ScorePanel.class, "LBL_add_row")); add.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ev) { addRow(); } }); final JButton del = new JButton(NbBundle.getMessage(ScorePanel.class, "LBL_remove_row")); del.setEnabled(false); del.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ev) { delRows(table.getSelectedRows()); } }); table.getSelectionModel().addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent ev) { del.setEnabled(table.getSelectedRows().length > 0); } }); JPanel buttons = new JPanel(); FlowLayout layout = new FlowLayout(); layout.setAlignment(FlowLayout.CENTER); layout.setHgap(15); buttons.setLayout(layout); buttons.add(add); buttons.add(del); add(buttons, BorderLayout.SOUTH); revalidate(); } private void addRow() { int size = score.getSize(); List notes = new ArrayList(size + 1); for (int i = 0; i < size; i++) { notes.add(score.getNote(i)); } notes.add(new Score.Note(Score.DEFAULT_TONE, Score.DEFAULT_OCTAVE, Score.DEFAULT_DURATION)); try { cookie.setScore(new Score(notes)); } catch (IOException ioe) { ErrorManager.getDefault().notify(ioe); } } private void delRows(int[] rows) { int size = score.getSize(); int size2 = size - rows.length; List notes = new ArrayList(size2); KEEPROW: for (int i = 0; i < size; i++) { for (int j = 0; j < rows.length; j++) { if (rows[j] == i) { continue KEEPROW; } } notes.add(score.getNote(i)); } try { cookie.setScore(new Score(notes)); } catch (IOException ioe) { ErrorManager.getDefault().notify(ioe); } } private class Model extends AbstractTableModel implements ChangeListener { public Model() { cookie.addChangeListener(WeakListener.change(this, cookie)); } public void stateChanged(ChangeEvent ev) { try { score = cookie.getScore(); fireTableDataChanged(); } catch (IOException ioe) { // keep previous Score object instead if (entry.getDataObject().isValid()) { ErrorManager.getDefault().notify(ioe); } } } public boolean isCellEditable(int row, int col) { return true; } public int getRowCount() { return score.getSize(); } public int getColumnCount() { return 3; } public Object getValueAt(int row, int column) { if (column == 0) return new Integer(score.getNote(row).getTone()); else if (column == 1) return new Integer(score.getNote(row).getOctave()); else if (column == 2) return new Integer(score.getNote(row).getDuration()); else throw new ArrayIndexOutOfBoundsException(); } public void setValueAt(Object val, int row, int col) { if (val.equals(getValueAt(row, col))) { return; } int size = score.getSize(); List notes = new ArrayList(size); for (int i = 0; i < size; i++) { Score.Note n = score.getNote(i); if (i == row) { int x = ((Integer)val).intValue(); switch (col) { case 0: n = new Score.Note(x, n.getOctave(), n.getDuration()); break; case 1: n = new Score.Note(n.getTone(), x, n.getDuration()); break; case 2: n = new Score.Note(n.getTone(), n.getOctave(), x); break; default: throw new ArrayIndexOutOfBoundsException(); } } notes.add(n); } Score nue = new Score(notes); try { cookie.setScore(nue); } catch (IOException ioe) { ErrorManager.getDefault().notify(ioe); } } } private static class PulldownRenderer extends DefaultTableCellRenderer { private String[] tokens; public PulldownRenderer(String[] tokens) { this.tokens = tokens; } protected void setValue(Object o) { int index = ((Integer)o).intValue(); setText(tokens[index]); } } private static class PulldownEditor extends DefaultCellEditor { public PulldownEditor(String[] tokens) { super(makeComboBox(tokens)); } private static JComboBox makeComboBox(final String[] tokens) { Object[] list = new Object[tokens.length]; for (int i = 0; i < list.length; i++) list[i] = new Integer(i); JComboBox combo = new JComboBox(list); combo.setMaximumRowCount(list.length); combo.setRenderer(new DefaultListCellRenderer() { public Component getListCellRendererComponent(JList list2, Object value, int index, boolean isSelected, boolean cellHasFocus) { int index2 = ((Integer)value).intValue(); return super.getListCellRendererComponent(list2, tokens[index2], index, isSelected, cellHasFocus); } }); return combo; } } }