/* 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 . */ 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 <gabriel.augendre@insa-lyon.fr> */ 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 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> 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 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(); } }