reversound/src/gui/MainWindow.java
2014-06-16 16:48:34 +02:00

461 lines
16 KiB
Java

/*
Reversound is used to get the music sheet of a piece from a music file.
Copyright (C) 2014 Gabriel AUGENDRE
Copyright (C) 2014 Gabriel DIENY
Copyright (C) 2014 Arthur GAUCHER
Copyright (C) 2014 Gabriel LEPETIT-AIMON
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. If not, see <http://www.gnu.org/licenses/>.
*/
package gui;
import actions.ExpertModeAction;
import actions.ImportFileAction;
import actions.QuitAction;
import actions.ShowInternalFrameAction;
import generictools.Pair;
import gui.graphs.GraphicView;
import processing.AudioInputToBuffer;
import processing.ProcessControl;
import processing.buffer.Buffer;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.beans.PropertyVetoException;
import java.io.File;
import java.util.ArrayList;
/**
* La fenêtre principale du programme.
* @author Gabriel Augendre &lt;gabriel.augendre@insa-lyon.fr&gt;
*/
class MainWindow {
// Initialize constants
final private int INITIAL_WIDTH_NON_EXPERT = 700;
final private int INITIAL_HEIGHT_NON_EXPERT = 120;
final private int INITIAL_WIDTH_EXPERT = 1200;
final private int INITIAL_HEIGHT_EXPERT = 500;
final private boolean EXPERT_MODE_ENABLED_BY_DEFAULT = true;
private final ExpertModeAction expertModeAction = new ExpertModeAction(EXPERT_MODE_ENABLED_BY_DEFAULT);
private final JPanel mainPanel = new JPanel(new BorderLayout(2,2));
private final JFrame frame = new JFrame();
private final JMenuBar menuBar = new JMenuBar();
private final JMenu fileMenu = new JMenu("Fichier");
private final JToolBar toolBar = new JToolBar();
private final JMenu displayMenu = new JMenu("Affichage");
private final JComboBox<String> sourceList = new JComboBox<>();
private final JButton computeButton = new JButton("Compute");
private final JButton stopRecordButton = new JButton("Stop recording");
private final JButton stopComputeButton = new JButton("Stop computing");
private final JButton resetButton = new JButton("Reset");
private final JButton enableExpertMode = new JButton(expertModeAction);
private final ImportFileAction importFileAction = new ImportFileAction(frame, sourceList);
private final JButton targetFileButton = new JButton(importFileAction);
private final JDesktopPane expertDisplay = new JDesktopPane();
private final ArrayList<Pair<JInternalFrame, Integer>> iFrameList = new ArrayList<>();
private final TimeSlider slider = new TimeSlider();
private final QuitAction quitAction = new QuitAction(frame);
private final JMenuItem importItem = new JMenuItem(importFileAction);
private final JMenuItem quitItem = new JMenuItem(quitAction);
private final JMenuItem exportItem = new JMenuItem(new AbstractAction("Exporter") {
@Override
public void actionPerformed(ActionEvent e) {
ProcessControl.instance().launchPostProcess();
}
});
private final WindowListener exitListener = new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
super.windowClosing(e);
int confirm = JOptionPane.showOptionDialog(null,
"Êtes-vous certain de vouloir fermer la fenêtre ?\nToutes les modifications seront perdues.",
"Confirmer la sortie", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, null, null);
if (confirm == 0) {
ProcessControl.instance().kill();
frame.dispose();
}
}
};
// Set Look and Feel (Mac OS X > Nimbus > System)
static {
try {
boolean b = true;
for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
UIManager.setLookAndFeel(info.getClassName());
if ("Mac OS X".equals(info.getName())) {
b = false;
break;
}
}
if (b) {
for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
}
} catch (Exception d) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception f) {
f.printStackTrace(System.err);
}
}
}
/**
* Constructeur par défaut, le seul.
*/
private MainWindow() {
createMainFrame();
createExpertDisplay();
createToolBar();
createMenuBar();
createMagicWindow();
frame.setVisible(true);
mainPanel.repaint();
//ProcessControl.instance().clockTick();
}
/**
* Création de la fenêtre principale.
*/
private void createMainFrame() {
frame.setTitle("Reversound");
// The size depends on the expert mode state
frame.setSize(
EXPERT_MODE_ENABLED_BY_DEFAULT?INITIAL_WIDTH_EXPERT:INITIAL_WIDTH_NON_EXPERT,
EXPERT_MODE_ENABLED_BY_DEFAULT?INITIAL_HEIGHT_EXPERT:INITIAL_HEIGHT_NON_EXPERT);
if (EXPERT_MODE_ENABLED_BY_DEFAULT) frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
// Content for this frame> <
frame.setContentPane(mainPanel);
// Do nothing on close
frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
// A menu bar (because we need it) ;-)
frame.setJMenuBar(menuBar);
// Resizable depends on the expert mode state
frame.setResizable(EXPERT_MODE_ENABLED_BY_DEFAULT);
// Define what we do if expert mode is enabled or disabled
expertModeAction.addPropertyChangeListener(evt -> {
if(evt.getPropertyName().equals(ExpertModeAction.ACTIVE)){
frame.setResizable((Boolean)evt.getNewValue());
if (!(Boolean)evt.getNewValue()) {
frame.setSize(INITIAL_WIDTH_NON_EXPERT, INITIAL_HEIGHT_NON_EXPERT);
} else {
frame.setSize(INITIAL_WIDTH_EXPERT, INITIAL_HEIGHT_EXPERT);
}
}
});
//Set close operation
frame.addWindowListener(exitListener);
}
/**
* Initialize the toolbar and source list.
*/
private void createToolBar() {
// Put data into source list
sourceList.addItem("Micro");
sourceList.setPrototypeDisplayValue("Fichier");
// Transmettre au contrôleur la source choisie.
sourceList.addItemListener(e -> {
final int INDEX = sourceList.getSelectedIndex();
System.out.println(sourceList.getItemAt(INDEX));
if(INDEX == 0)
ProcessControl.instance().setInput(ProcessControl.instance().getMainInputID(), AudioInputToBuffer.fromMicro());
else
ProcessControl.instance().setInput(
ProcessControl.instance().getMainInputID(),
AudioInputToBuffer.fromFile(
(File) (importFileAction.getValue(ImportFileAction.FILE))
));
});
//Modifie légèrement le look des boutons, surtout sur Mac OS X
computeButton.putClientProperty("JButton.buttonType", "textured");
stopRecordButton.putClientProperty("JButton.buttonType", "segmentedTextured");
stopRecordButton.putClientProperty("JButton.segmentPosition", "first");
stopComputeButton.putClientProperty("JButton.buttonType", "segmentedTextured");
stopComputeButton.putClientProperty("JButton.segmentPosition", "last");
targetFileButton.putClientProperty("JButton.buttonType", "textured");
resetButton.putClientProperty("JButton.buttonType", "textured");
// Add elements to toolBar
toolBar.add(computeButton);
toolBar.add(stopRecordButton);
toolBar.add(stopComputeButton);
toolBar.add(resetButton);
toolBar.add(sourceList);
toolBar.add(targetFileButton);
// Configure le bouton reset
resetButton.setToolTipText("Réinitialise le programme à son état d'origine.");
resetButton.addActionListener(e -> reset());
// On n'affiche pas les boutons stop au début.
setStopButtonsState(false);
// On relie les boutons au contrôle.
computeButton.addActionListener(e -> {
ProcessControl.instance().start();
setStopButtonsState(true);
stopRecordButton.setText("Stop recording");
});
stopRecordButton.addActionListener(e -> {
if (stopRecordButton.getText().equals("Stop recording")) {
stopRecordButton.setText("Record");
ProcessControl.instance().stopRecord();
} else {
stopRecordButton.setText("Stop recording");
ProcessControl.instance().start();
}
});
stopComputeButton.addActionListener(e -> {
ProcessControl.instance().stop();
setStopButtonsState(false);
});
// Add button to enable/disable the expert mode
{
setExpertButtonText(EXPERT_MODE_ENABLED_BY_DEFAULT);
expertModeAction.addPropertyChangeListener(evt -> {
if(!evt.getPropertyName().equals(ExpertModeAction.ACTIVE))return;
setExpertButtonText((boolean)evt.getNewValue());
});
//enableExpertMode.setSelected(EXPERT_MODE_ENABLED_BY_DEFAULT);
enableExpertMode.putClientProperty("JButton.buttonType", "textured");
toolBar.add(enableExpertMode);
}
// Set not draggable
toolBar.setFloatable(false);
// Add the toolbar to the main panel
mainPanel.add(toolBar,BorderLayout.NORTH);
}
/**
* Setup the menus and addNote all elements.
*/
private void createMenuBar() {
// Setup the file menu
{
fileMenu.setMnemonic(KeyEvent.VK_F);
// Add items : Import, quit
{
//importItem.setText("Importer"); //Importer, sous-menu de Fichier
importItem.setMnemonic(KeyEvent.VK_I);
fileMenu.add(importItem);
exportItem.setMnemonic(KeyEvent.VK_E);
fileMenu.add(exportItem);
quitItem.setMnemonic(KeyEvent.VK_Q);
fileMenu.add(quitItem);
}
menuBar.add(fileMenu);
}
// Setup the display menu
{
displayMenu.setMnemonic(KeyEvent.VK_A);
// Add an item : Enable expert mode
{
final JCheckBoxMenuItem menuItem = new JCheckBoxMenuItem(expertModeAction);
menuItem.setSelected(EXPERT_MODE_ENABLED_BY_DEFAULT);
displayMenu.add(menuItem);
expertModeAction.addPropertyChangeListener(evt -> {
if(!evt.getPropertyName().equals(ExpertModeAction.ACTIVE))return;
menuItem.setSelected((boolean)evt.getNewValue());
});
}
menuBar.add(displayMenu);
}
}
/**
* Create the expert display.
*/
private void createExpertDisplay() {
// Hide or show the pane if mode enabled by default.
expertDisplay.setVisible(EXPERT_MODE_ENABLED_BY_DEFAULT);
// Add the pane to the main panel
mainPanel.add(expertDisplay, BorderLayout.CENTER);
// When the expertMode is enabled, display the panel
expertModeAction.addPropertyChangeListener(evt -> {
if(evt.getPropertyName().equals(ExpertModeAction.ACTIVE)) {
expertDisplay.setVisible((Boolean) evt.getNewValue());
}
});
mainPanel.add(slider, BorderLayout.SOUTH);
}
/**
* Display a buffer in a JInternalFrame. If the frame was previously created, show it. Else, create a new one.
* @param bufferID The ID of the buffer to be displayed.
*/
public void displayBuffer(int bufferID) {
for (Pair<JInternalFrame, Integer> paire : iFrameList) {
JInternalFrame iFr = paire.first();
int bID = paire.second();
if (bID == bufferID) {
if (!iFr.isVisible()) {
expertDisplay.add(iFr);
iFr.setVisible(true);
}
try {
iFr.setSelected(true);
} catch (PropertyVetoException e1) {
e1.printStackTrace(System.err);
}
return;
}
}
Buffer buffer = ProcessControl.instance().getBuffer(bufferID);
final JInternalFrame iFrame = new JInternalFrame();
GraphicView spectreView = GraphicView.createGraphicView(buffer,true);
addInternalFrame(iFrame, spectreView.getName(), bufferID, spectreView);
}
/**
* Ajoute la fenêtre de contrôle à l'affichage Expert.
* Appelle addInternalFrame(final JInternalFrame IFRAME, final String TITLE, final GraphicView CONTENT).
*/
private void createMagicWindow() {
JInternalFrame iFrame = new JInternalFrame();
GraphicView v = new ProcessSumUp(this);
addInternalFrame(iFrame, v.getName(), v);
}
/**
* Ajoute une fenêtre à l'affichage Expert et la configure selon les besoins de l'application.
* @param IFRAME La fenêtre à ajouter.
* @param TITLE Le titre de la fenêtre.
* @param BUFFER_ID L'identifiant du buffer à ajouter à la fenêtre pour l'affichage.
* @param CONTENT Le contenu de la fenêtre.
*/
private void addInternalFrame(final JInternalFrame IFRAME, final String TITLE, final int BUFFER_ID, final GraphicView CONTENT) {
IFRAME.setTitle(TITLE);
iFrameList.add(new Pair<>(IFRAME, BUFFER_ID));
IFRAME.setVisible(true);
expertDisplay.add(IFRAME);
final int WINDOW_WIDTH = 350;
IFRAME.setBounds((iFrameList.size() - 2) * 100 + 5, 310, WINDOW_WIDTH, 300);
IFRAME.setResizable(true);
IFRAME.setClosable(true);
IFRAME.setMaximizable(true);
IFRAME.setContentPane(CONTENT);
displayMenu.add(new ShowInternalFrameAction(expertDisplay, IFRAME));
}
/**
* Appelle addInternalFrame avec un BUFFER_ID de -1 (pour la fenêtre de contrôle uniquement.
* @param IFRAME La fenêtre à ajouter.
* @param TITLE Le titre de la fenêtre.
* @param CONTENT Le contenu de la fenêtre.
*/
private void addInternalFrame(final JInternalFrame IFRAME, final String TITLE, final GraphicView CONTENT) {
addInternalFrame(IFRAME, TITLE, -1, CONTENT);
IFRAME.setClosable(false);
final int WINDOW_WIDTH = (int)GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds().getWidth();
IFRAME.setBounds(5,5,WINDOW_WIDTH-10,300);
}
/**
* Change l'état des boutons stop, compute et de la liste des sources de l'application.
* @param state False si on souhaite cacher les boutons stop, true sinon.
*/
private void setStopButtonsState(final boolean state) {
stopRecordButton.setVisible(state);
stopRecordButton.setEnabled(state);
stopComputeButton.setVisible(state);
stopComputeButton.setEnabled(state);
computeButton.setVisible(!state);
computeButton.setEnabled(!state);
sourceList.setVisible(!state);
sourceList.setEnabled(!state);
targetFileButton.setVisible(!state);
targetFileButton.setEnabled(!state);
}
/**
* Change le texte du bouton Expert en fonction d'un booléen.
* @param b True si le mode expert est désactivé, false sinon.
*/
private void setExpertButtonText(boolean b) {
enableExpertMode.setText(
!b?
"Activer le mode expert":
"Désactiver le mode expert"
);
}
/**
* Réinitialise l'application à son état d'origine.
*/
private void reset() {
if (sourceList.getItemCount() > 1)
sourceList.removeItemAt(1);
sourceList.setPrototypeDisplayValue("Fichier");
ProcessControl.instance().reset();
setStopButtonsState(false);
}
/**
* Enter point to run this program.
* @param args None
*/
public static void main(String[] args) {
new MainWindow();
}
}