/* Copyright (C) 2006 Christian Schneider
*
* This file is part of Nomad.
*
* Nomad is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Nomad is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Nomad; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.sf.nmedit.nordmodular;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.Arrays;
import javax.swing.AbstractAction;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
import net.sf.nmedit.jpatch.PModule;
import net.sf.nmedit.jpatch.clavia.nordmodular.Format;
import net.sf.nmedit.jpatch.clavia.nordmodular.Header;
import net.sf.nmedit.jpatch.clavia.nordmodular.NMPatch;
import net.sf.nmedit.jpatch.clavia.nordmodular.VoiceArea;
import net.sf.nmedit.jsynth.Slot;
import net.sf.nmedit.jsynth.Synthesizer;
import net.sf.nmedit.nomad.core.Nomad;
import net.sf.nmedit.nomad.core.forms.PropertyDialogForm;
import net.sf.nmedit.nomad.core.service.fileService.FileService;
public class PatchSettingsDialog
{
private NMPatch patch;
private PropertyDialogForm dialog;
private DialogPane settingsDlgPane;
private PatchSettingsFrm frm;
private FileService service;
JTextArea notesTextArea = new JTextArea();
private PatchSettingsDialog(NMPatch patch, FileService service)
{
this.service = service;
this.patch = patch ;
dialog = new PropertyDialogForm();
String path;
path = "info";
DialogPane fileInfo = new DialogPane(patch, path, "Info")
{
@Override
protected JComponent createDialogComponent()
{
return new JScrollPane(createInfoDialog());
}
};
fileInfo.install(dialog);
path = "settings";
settingsDlgPane = new DialogPane(patch, path, "Settings")
{
@Override
protected JComponent createDialogComponent()
{
return new JScrollPane(createSettingsDialog());
}
};
settingsDlgPane.install(dialog);
dialog.setSelectedPath(path);
path = "notes";
DialogPane notesPane = new DialogPane(patch, path, "Notes")
{
@Override
protected JComponent createDialogComponent()
{
return new JScrollPane(createNotesDialog());
}
};
notesPane.install(dialog);
}
protected JComponent createNotesDialog()
{
notesTextArea.setFont(new Font("monospaced", Font.PLAIN, 11));
notesTextArea.setText(patch.getNote());
return notesTextArea;
}
private JComponent text(String text)
{
JTextField tf = new JTextField(text);
tf.setEditable(false);
tf.setBorder(null);
return tf;
}
protected JComponent createInfoDialog()
{
File file = patch.getFile();
Slot slot = patch.getSlot();
Synthesizer synth = slot == null ? null : slot.getSynthesizer();
JPanel cont = new JPanel();
cont.setLayout(new BoxLayout(cont, BoxLayout.Y_AXIS));
Box box;
// TODO fix layout
// path
box = Box.createHorizontalBox();
box.add(new JLabel("Path:"));
box.add(text(file == null ? "-" : file.getAbsolutePath()));
cont.add(box);
// file type
box = Box.createHorizontalBox();
box.add(new JLabel("Type:"));
box.add(text(service == null ? "-" : service.getFileFilter().getDescription()));
cont.add(box);
// synth
box = Box.createHorizontalBox();
box.add(new JLabel("Synthesizer:"));
box.add(text(synth == null ? "-" : (synth.getVendor()+" "+synth.getName())));
cont.add(box);
// slot
box = Box.createHorizontalBox();
box.add(new JLabel("Slot:"));
box.add(text(slot == null ? "-" : slot.getName()));
cont.add(box);
return cont;
}
private JComponent createSettingsDialog()
{
frm = new PatchSettingsFrm();
setValues(frm, patch.getHeader());
return frm;
}
private SpinnerNumberModel model(int value)
{
return model(0, 127, value);
}
private SpinnerNumberModel model(int min, int max, int value)
{
return new SpinnerNumberModel(value, min, max, 1);
}
private void setValues(PatchSettingsFrm frm, Header header)
{
frm.btnGetCurrentNotes.setEnabled(false);
frm.cbOctaveShift.setSelectedIndex(header.getOctaveShift());
frm.cbVoiceReCommon.setSelected(header.isVoiceRetriggerCommonActive());
frm.cbVoiceRePoly.setSelected(header.isVoiceRetriggerPolyActive());
frm.rbPedalModeOnOff.setEnabled(false);
frm.rbPedalModeSustain.setEnabled(false);
frm.rbPortaAuto.setSelected(header.isPortamentoAutoEnabled());
frm.spPortaTime.setModel(model(header.getPortamentoTime()));
frm.spBendRange.setModel(model(Format.HEADER_BEND_RANGE_MIN, Format.HEADER_BEND_RANGE_MAX, header.getBendRange()));
// TODO min<=max
frm.spKbRangeMin.setModel(model(header.getKeyboardRangeMin()));
frm.spKbRangeMax.setModel(model(header.getKeyboardRangeMax()));
// TODO min<=max
frm.spVelRangeMin.setModel(model(header.getVelocityRangeMin()));
frm.spVelRangeMax.setModel(model(header.getVelocityRangeMax()));
frm.spRequestedVoices.setModel(model(0, 32, header.getRequestedVoices()));
double[] svp = stats(patch.getPolyVoiceArea());
double[] svc = stats(patch.getCommonVoiceArea());
frm.lblCycles.setText(svp[0]+"/"+svc[0]);
frm.lblXmem.setText(svp[1]+"/"+svc[1]);
frm.lblYmem.setText(svp[2]+"/"+svc[2]);
frm.lblProgMem.setText(svp[3]+"/"+svc[3]);
frm.lblDynMem.setText(svp[4]+"/"+svc[4]);
frm.lblZeroPage.setText(svp[5]+"/"+svc[5]);
}
private void apply()
{
Header header = patch.getHeader();
header.setValueWithoutNotification(Format.HEADER_OCTAVE_SHIFT, frm.cbOctaveShift.getSelectedIndex());
header.setValueWithoutNotification(Format.HEADER_VOICE_RETRIGGER_COMMON, frm.cbVoiceReCommon.isSelected()?1:0);
header.setValueWithoutNotification(Format.HEADER_VOICE_RETRIGGER_POLY, frm.cbVoiceRePoly.isSelected()?1:0);
// frm.rbPedalModeOnOff.setEnabled(false);
// frm.rbPedalModeSustain.setEnabled(false);
header.setValueWithoutNotification(Format.HEADER_PORTAMENTO, frm.rbPortaAuto.isSelected()?1:0);
header.setValueWithoutNotification(Format.HEADER_PORTAMENTO_TIME, (Integer) frm.spPortaTime.getValue());
header.setValueWithoutNotification(Format.HEADER_BEND_RANGE, (Integer) frm.spBendRange.getValue());
header.setValueWithoutNotification(Format.HEADER_KEYBOARD_RANGE_MIN, (Integer) frm.spKbRangeMin.getValue());
header.setValueWithoutNotification(Format.HEADER_KEYBOARD_RANGE_MAX, (Integer) frm.spKbRangeMax.getValue());
header.setValueWithoutNotification(Format.HEADER_VELOCITY_RANGE_MIN, (Integer) frm.spVelRangeMin.getValue());
header.setValueWithoutNotification(Format.HEADER_VELOCITY_RANGE_MAX, (Integer) frm.spVelRangeMax.getValue());
header.setValueWithoutNotification(Format.HEADER_REQUESTED_VOICES, (Integer) frm.spRequestedVoices.getValue());
header.firePatchSettingsChanged(false);
patch.setNote(notesTextArea.getText());
}
double[] stats(VoiceArea va)
{
double[] stats = new double[6];
Arrays.fill(stats, 0);
stats[0] = va.getTotalCycles();
for (PModule m: va)
{
stats[1] += m.getDoubleAttribute("x-mem", 0);
stats[2] += m.getDoubleAttribute("y-mem", 0);
stats[3] += m.getDoubleAttribute("prog-mem", 0);
stats[4] += m.getDoubleAttribute("dyn-mem", 0);
stats[5] += m.getDoubleAttribute("zero-page", 0);
}
return stats;
}
public static void invoke(FileService service, NMPatch patch)
{
PatchSettingsDialog dlg = new PatchSettingsDialog(patch, service);
dlg.invoke();
}
private void invoke()
{
final JDialog d = new JDialog(Nomad.sharedInstance().getWindow(), "Properties for "+patch.getName());
d.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
Dimension ss = Toolkit.getDefaultToolkit().getScreenSize();
Dimension ds = new Dimension(ss.width/2, ss.height*2/5);
d.getContentPane().setLayout(new BorderLayout());
d.getContentPane().add(dialog, BorderLayout.CENTER);
d.setBounds((ss.width-ds.width)/2, (ss.height-ds.height)/2, ds.width, ds.height);
dialog.addButton(new AbstractAction(){
/**
*
*/
private static final long serialVersionUID = 3024495863362168958L;
{
putValue(NAME, "Apply");
}
public void actionPerformed(ActionEvent e)
{
apply();
}
});
dialog.addButton(new AbstractAction(){
/**
*
*/
private static final long serialVersionUID = 1653037659655851257L;
{
putValue(NAME, "Close");
}
public void actionPerformed(ActionEvent e)
{
d.dispose();
}});
d.setVisible(true);
}
public abstract static class DialogPane implements ActionListener, Runnable
{
protected NMPatch patch;
protected String path;
protected String title;
protected JComponent component;
protected PropertyDialogForm dialog;
public DialogPane(NMPatch patch, String path, String title)
{
this.patch = patch;
this.path = path;
this.title = title;
}
public void install(PropertyDialogForm dialog)
{
this.dialog = dialog;
dialog.addEntry(path, title);
dialog.addActionListener(this);
}
public void actionPerformed(ActionEvent e)
{
if (path == e.getActionCommand() || path.equals(e.getActionCommand()))
{
setDialogComponentLater();
}
}
private void setDialogComponentLater()
{
SwingUtilities.invokeLater(this);
}
private void setDialogComponent()
{
if (component == null)
component = createDialogComponent();
if (component != null)
dialog.setEditor(component);
}
public void run()
{
setDialogComponent();
}
protected abstract JComponent createDialogComponent();
}
}