/* License see bottom */
package jpianotrain.gui;
import static jpianotrain.Constants.D_WITH_INSETS_PROPERTY;
import static jpianotrain.util.ConfigurationKeys.INFO_PANEL_LAST_LOCATION;
import static jpianotrain.util.ConfigurationKeys.INFO_PANEL_LOCATION;
import static jpianotrain.util.ConfigurationKeys.LOOK_AND_FEEL;
import static jpianotrain.util.ConfigurationKeys.WINDOW_BOUNDS;
import static jpianotrain.util.ResourceKeys.ACTION_CONFIGURE_GUI_NAME;
import static jpianotrain.util.ResourceKeys.ACTION_CONFIGURE_MIDI_NAME;
import static jpianotrain.util.ResourceKeys.ACTION_CONFIGURE_RANDOM_NAME;
import static jpianotrain.util.ResourceKeys.ACTION_CONFIGURE_SYNTHESIZER_NAME;
import static jpianotrain.util.ResourceKeys.ERROR_LOOK_AND_FEEL;
import static jpianotrain.util.ResourceKeys.FRAME_TITLE;
import static jpianotrain.util.ResourceKeys.MENU_APP_NAME;
import static jpianotrain.util.ResourceKeys.MENU_CONFIGURE_NAME;
import static jpianotrain.util.ResourceKeys.MENU_EXTRA_NAME;
import static jpianotrain.util.ResourceKeys.MENU_LOOK_AND_FEEL;
import static jpianotrain.util.ResourceKeys.MENU_MODE_NAME;
import static jpianotrain.util.ResourceKeys.MODE_LESSONS;
import static jpianotrain.util.ResourceKeys.MODE_MIDI_FILE;
import static jpianotrain.util.ResourceKeys.MODE_RANDOM_NOTES;
import static jpianotrain.util.ResourceKeys.START_COUNT_IN;
import static jpianotrain.util.ResourceKeys.START_ON_FIRST_KEY;
import static jpianotrain.util.ResourceKeys.TITLE_ERROR;
import static jpianotrain.util.ResourceKeys.TITLE_INFORMATION;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.text.MessageFormat;
import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import jpianotrain.ApplicationContext;
import jpianotrain.Constants;
import jpianotrain.gui.action.ChordAction;
import jpianotrain.gui.action.ChordScaleAction;
import jpianotrain.gui.action.CircleOfFifthsAction;
import jpianotrain.gui.action.CloseAction;
import jpianotrain.gui.action.ConfigurationAction;
import jpianotrain.gui.action.CreateStaffAction;
import jpianotrain.gui.action.HyperTonnetzAction;
import jpianotrain.gui.action.LookAndFeelAction;
import jpianotrain.gui.action.MajorTonnetzAction;
import jpianotrain.gui.action.ScalePaneAction;
import jpianotrain.midi.NoteDispatcher;
import jpianotrain.staff.Tune;
import jpianotrain.staff.TuneFactory;
import jpianotrain.util.ErrorHandler;
import jpianotrain.util.ResourceFactory;
import jpianotrain.util.ResourceKeys;
import jpianotrain.util.UserConfiguration;
import org.apache.log4j.Logger;
/**
* The main frame. This is the first thing a user
* will see.
*
* @since 0
* @author Alexander Methke
*/
public class JPianoTrainFrame extends JFrame
implements ActionListener,
ConfigurationAction.Configurator,
CloseAction.Closeable,
CreateStaffAction.TuneReceiver,
ErrorHandler.ErrorDisplay,
ErrorHandler.MessageDisplay,
WindowListener {
private static final Logger log=Logger.getLogger(JPianoTrainFrame.class);
/**
* Create instance with title and bounds initially set.
*/
public JPianoTrainFrame() {
super(ResourceFactory.getString(FRAME_TITLE)+" - "+Constants.VERSION);
setDefaultCloseOperation(EXIT_ON_CLOSE);
addWindowListener(this);
}
/**
* Init GUI like setting layout, adding panels
* and components.
*/
public void initGui() {
UserConfiguration uc=UserConfiguration.getInstance();
String lf=uc.getProperty(LOOK_AND_FEEL, null);
if (lf!=null) {
try {
UIManager.setLookAndFeel(lf);
SwingUtilities.updateComponentTreeUI(this);
} catch (Exception ex) {
log.error(ResourceFactory.getString(ERROR_LOOK_AND_FEEL), ex);
ErrorHandler.handleError(ERROR_LOOK_AND_FEEL, lf);
}
}
Rectangle bounds=uc.getRectProperty(WINDOW_BOUNDS,
Constants.DEFAULT_BOUNDS);
setBounds(bounds);
setJMenuBar(initMenu());
notationPanel=new NotationPanel();
JPanel mainPanel=new JPanel();
mainPanel.setLayout(new GridLayout(3,1));
mainPanel.add(notationPanel);
messagePanel=new JTextArea();
messagePanel.setText("Initiated\n"+
"Lesson Mode, both hands, Beginner\n"+
"MIDI active, Input/Output recognized\n"+
"Start with key press on your keyboard");
messagePanel.setEditable(false);
mainPanel.add(new JScrollPane(messagePanel));
keyboardPanel=new JKeyBoard(Constants.KEYBOARD_OCTAVE_RANGE);
ApplicationContext.getInstance().addListener(keyboardPanel);
Dimension d=new Dimension(getSize());
d.height=d.height/3;
keyboardPanel.setPreferredSize(d);
mainPanel.add(keyboardPanel);
InfoPanel helpPanel=new InfoPanel();
splitPanel=new JSplitPane(JSplitPane.VERTICAL_SPLIT,
mainPanel,
new JScrollPane(helpPanel));
splitPanel.setOneTouchExpandable(true);
if (uc.getIntProperty(INFO_PANEL_LOCATION, -1)!=-1) {
log.debug("re-minimizing info panel");
splitPanel.setDividerLocation(uc.getIntProperty(INFO_PANEL_LOCATION,0));
splitPanel.setLastDividerLocation(uc.getIntProperty(INFO_PANEL_LAST_LOCATION, 0));
}
Container contentPane=getContentPane();
contentPane.setLayout(new BorderLayout());
contentPane.add(splitPanel, BorderLayout.CENTER);
contentPane.add(new StatusPanel(), BorderLayout.SOUTH);
}
/**
* Creates the menu bar. Don't set it
* as frame's menu bar, frame does this
* itself.
*/
protected JMenuBar initMenu() {
JMenuBar bar=new JMenuBar();
JMenu appMenu=
new JMenu(ResourceFactory.getString(MENU_APP_NAME));
JMenuItem closeItem=
new JMenuItem(new CloseAction(this));
appMenu.add(closeItem);
JMenu modeMenu=
new JMenu(ResourceFactory.getString(MENU_MODE_NAME));
modeMidiFile=
new JRadioButtonMenuItem(ResourceFactory.getString(MODE_MIDI_FILE));
modeMidiFile.setEnabled(false);
modeMidiFile.addActionListener(this);
modeRandomNotes=
new JRadioButtonMenuItem(ResourceFactory.getString(MODE_RANDOM_NOTES));
modeRandomNotes.addActionListener(this);
modeLessons=
new JRadioButtonMenuItem(ResourceFactory.getString(MODE_LESSONS));
modeLessons.addActionListener(this);
modeLessons.setEnabled(false);
onFirstKey=
new JRadioButtonMenuItem(ResourceFactory.getString(START_ON_FIRST_KEY));
onFirstKey.addActionListener(this);
onFirstKey.setSelected(true);
countIn=
new JRadioButtonMenuItem(ResourceFactory.getString(START_COUNT_IN));
countIn.addActionListener(this);
countIn.setEnabled(false);
ButtonGroup startGroup=new ButtonGroup();
startGroup.add(onFirstKey);
startGroup.add(countIn);
modeGroup=new ButtonGroup();
modeGroup.add(modeMidiFile);
modeGroup.add(modeLessons);
modeGroup.add(modeRandomNotes);
modeRandomNotes.setSelected(true);
modeMenu.add(modeRandomNotes);
modeMenu.add(modeMidiFile);
modeMenu.add(modeLessons);
modeMenu.addSeparator();
modeMenu.add(new CreateStaffAction(this));
modeMenu.addSeparator();
JMenu extraMenu=
new JMenu(ResourceFactory.getString(MENU_EXTRA_NAME));
JMenu configureMenu=
new JMenu(ResourceFactory.getString(MENU_CONFIGURE_NAME));
JMenuItem configureGUIItem=
new JMenuItem(new ConfigurationAction(this,
ACTION_CONFIGURE_GUI_NAME,
ConfigurationDialog.Configurations.GUI));
JMenuItem configureMidiItem=
new JMenuItem(new ConfigurationAction(this,
ACTION_CONFIGURE_MIDI_NAME,
ConfigurationDialog.Configurations.MIDI));
JMenuItem configureRandomItem=
new JMenuItem(new ConfigurationAction(this,
ACTION_CONFIGURE_RANDOM_NAME,
ConfigurationDialog.Configurations.RANDOM));
JMenuItem configureSynthItem=
new JMenuItem(new ConfigurationAction(this,
ACTION_CONFIGURE_SYNTHESIZER_NAME,
ConfigurationDialog.Configurations.SYNTHESIZER));
configureMenu.add(configureGUIItem);
configureMenu.add(configureMidiItem);
configureMenu.add(configureRandomItem);
configureMenu.add(configureSynthItem);
JMenu lookAndFeelMenu=new JMenu(ResourceFactory.getString(MENU_LOOK_AND_FEEL));
for (UIManager.LookAndFeelInfo info:UIManager.getInstalledLookAndFeels()) {
lookAndFeelMenu.add(new LookAndFeelAction(info, this));
}
extraMenu.add(new CircleOfFifthsAction());
extraMenu.add(new ScalePaneAction());
extraMenu.add(new MajorTonnetzAction());
extraMenu.add(new HyperTonnetzAction());
extraMenu.add(new ChordAction());
extraMenu.add(new ChordScaleAction());
extraMenu.addSeparator();
extraMenu.add(configureMenu);
extraMenu.add(lookAndFeelMenu);
bar.add(appMenu);
bar.add(modeMenu);
bar.add(extraMenu);
return bar;
}
// ActionListener
public void actionPerformed(ActionEvent e) {
Object source=e.getSource();
ApplicationContext ctx=ApplicationContext.getInstance();
if (source==modeMidiFile) {
ctx.setMode(ApplicationContext.Mode.MIDI_FILES);
} else if (source==modeRandomNotes) {
ctx.setMode(ApplicationContext.Mode.RANDOM_NOTES);
} else if (source==modeLessons) {
ctx.setMode(ApplicationContext.Mode.LESSONS);
} else if (source==countIn) {
ctx.setStartMode(ApplicationContext.StartMode.COUNT_IN);
} else if (source==onFirstKey) {
ctx.setStartMode(ApplicationContext.StartMode.ON_FIRST_KEY);
}
}
// ErrorHandler.ErrorDisplay
public void handleError(ResourceKeys messageKey) {
JOptionPane.showMessageDialog(this,
ResourceFactory.getString(messageKey),
ResourceFactory.getString(TITLE_ERROR),
JOptionPane.ERROR_MESSAGE);
}
public void handleError(ResourceKeys messageKey, Object param) {
JOptionPane.showMessageDialog(this,
MessageFormat.format(ResourceFactory.getString(messageKey),param),
ResourceFactory.getString(TITLE_ERROR),
JOptionPane.ERROR_MESSAGE);
}
public void handleError(ResourceKeys messageKey, Object[] params) {
JOptionPane.showMessageDialog(this,
MessageFormat.format(ResourceFactory.getString(messageKey),params),
ResourceFactory.getString(TITLE_ERROR),
JOptionPane.ERROR_MESSAGE);
}
// ErrorHandler.MessageDisplay
public void handleMessage(ResourceKeys messageKey) {
JOptionPane.showMessageDialog(this,
ResourceFactory.getString(messageKey),
ResourceFactory.getString(TITLE_INFORMATION),
JOptionPane.INFORMATION_MESSAGE);
}
// ConfigurationAction.Configurator
public void configure(ConfigurationDialog.Configurations conf) {
if (configurationDialog==null) {
configurationDialog=new ConfigurationDialog(this);
}
configurationDialog.select(conf);
configurationDialog.setVisible(true);
}
// CloseAction.Closeable
/**
* Maybe in later releases this will be the
* hook to save dirty data.
*/
public boolean canClose() {
storeConfiguration();
return true;
}
/**
* Just hides this frame, VM may/will exit.
*/
public void doClose() {
setVisible(false);
dispose();
}
// CreateStaffAction.TuneReceiver
public void setTune(Tune t) {
notationPanel.display(t);
NoteDispatcher.getInstance().setTune(t);
}
// WindowListener
public void windowActivated(WindowEvent e) {
}
public void windowClosed(WindowEvent e) {
}
public void windowClosing(WindowEvent e) {
storeConfiguration();
}
public void windowDeactivated(WindowEvent e) {
}
public void windowDeiconified(WindowEvent e) {
}
public void windowIconified(WindowEvent e) {
}
public void windowOpened(WindowEvent e) {
}
protected void storeConfiguration() {
Rectangle r=getBounds();
Insets i=getInsets();
if (System.getProperties().get(D_WITH_INSETS_PROPERTY)!=null) {
r.width+=i.right;
r.height+=i.bottom;
} else {
r.x-=i.left;
r.y-=i.top;
}
TuneFactory.storeConfiguration();
UserConfiguration uc=UserConfiguration.getInstance();
log.debug("saving bounds: "+r);
log.debug("insets "+getInsets());
uc.putProperty(WINDOW_BOUNDS, r);
uc.putProperty(LOOK_AND_FEEL, UIManager.getLookAndFeel().getClass().getName());
log.debug("info panel minimized: "+(splitPanel.getDividerLocation()>=splitPanel.getMaximumDividerLocation()));
uc.putProperty(INFO_PANEL_LOCATION, splitPanel.getDividerLocation());
uc.putProperty(INFO_PANEL_LAST_LOCATION, splitPanel.getLastDividerLocation());
uc.done();
}
private ButtonGroup modeGroup;
private ConfigurationDialog configurationDialog;
private JRadioButtonMenuItem modeMidiFile;
private JRadioButtonMenuItem modeRandomNotes;
private JRadioButtonMenuItem modeLessons;
private JRadioButtonMenuItem countIn;
private JRadioButtonMenuItem onFirstKey;
private JSplitPane splitPanel;
private JTextArea messagePanel;
private NotationPanel notationPanel;
private JKeyBoard keyboardPanel;
}
/*
Copyright (C) 2008 Alexander Methke
This program 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 3 of the License, or
(at your option) any later version.
This program 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 this program (gplv3.txt).
*/