marytts.tools.voiceimport.DatabaseImportMain.java Source code

Java tutorial

Introduction

Here is the source code for marytts.tools.voiceimport.DatabaseImportMain.java

Source

/**
 * Portions Copyright 2006 DFKI GmbH.
 * Portions Copyright 2001 Sun Microsystems, Inc.
 * Portions Copyright 1999-2001 Language Technologies Institute, 
 * Carnegie Mellon University.
 * All Rights Reserved.  Use is subject to license terms.
 * 
 * Permission is hereby granted, free of charge, to use and distribute
 * this software and its documentation without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of this work, and to
 * permit persons to whom this work is furnished to do so, subject to
 * the following conditions:
 * 
 * 1. The code must retain the above copyright notice, this list of
 *    conditions and the following disclaimer.
 * 2. Any modifications must be clearly marked as such.
 * 3. Original authors' names are not deleted.
 * 4. The authors' names are not used to endorse or promote products
 *    derived from this software without specific prior written
 *    permission.
 *
 * DFKI GMBH AND THE CONTRIBUTORS TO THIS WORK DISCLAIM ALL WARRANTIES WITH
 * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DFKI GMBH NOR THE
 * CONTRIBUTORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
 * THIS SOFTWARE.
 */
package marytts.tools.voiceimport;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;

import org.apache.commons.io.FileUtils;

import marytts.util.io.BasenameList;

/**
 * The single purpose of the DatabaseImportMain class is to provide a main
 * which executes the sequence of database import and conversion operations.
 * 
 * @author sacha, anna
 *
 */
public class DatabaseImportMain extends JFrame {
    protected VoiceImportComponent[] components;
    protected String[][] groups2Comps;
    protected JCheckBox[] checkboxes;
    protected JButton runButton;
    protected DatabaseLayout db = null;
    protected BasenameList bnl = null;
    protected String currentComponent;

    public DatabaseImportMain(String title, VoiceImportComponent[] components, DatabaseLayout db,
            String[][] groups2Comps) {
        super(title);
        this.components = components;
        this.checkboxes = new JCheckBox[components.length];
        this.db = db;
        this.bnl = db.getBasenames();
        this.groups2Comps = groups2Comps;
        currentComponent = "global properties";
        setupGUI();
    }

    protected void setupGUI() {
        // A scroll pane containing one labelled checkbox per component,
        // and a "run selected components" button below.
        GridBagLayout gridBagLayout = new GridBagLayout();
        GridBagConstraints gridC = new GridBagConstraints();
        getContentPane().setLayout(gridBagLayout);

        JPanel checkboxPane = new JPanel();
        checkboxPane.setLayout(new BoxLayout(checkboxPane, BoxLayout.Y_AXIS));
        //checkboxPane.setPreferredSize(new Dimension(300, 300));
        int compIndex = 0;
        for (int j = 0; j < groups2Comps.length; j++) {
            String[] nextGroup = groups2Comps[j];
            JPanel groupPane = new JPanel();
            groupPane.setLayout(new BoxLayout(groupPane, BoxLayout.Y_AXIS));
            groupPane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder(nextGroup[0]),
                    BorderFactory.createEmptyBorder(1, 1, 1, 1)));
            for (int i = 1; i < nextGroup.length; i++) {
                JButton configButton = new JButton();
                Icon configIcon = new ImageIcon(DatabaseImportMain.class.getResource("configure.png"), "Configure");
                configButton.setIcon(configIcon);
                configButton.setPreferredSize(new Dimension(configIcon.getIconWidth(), configIcon.getIconHeight()));
                configButton.addActionListener(new ConfigButtonActionListener(nextGroup[i]));
                configButton.setBorderPainted(false);
                //System.out.println("Adding checkbox for "+components[i].getClass().getName());
                checkboxes[compIndex] = new JCheckBox(nextGroup[i]);
                checkboxes[compIndex].setFocusable(true);
                //checkboxes[i].setPreferredSize(new Dimension(200, 30));
                JPanel line = new JPanel();
                line.setLayout(new BorderLayout(5, 0));
                line.add(configButton, BorderLayout.WEST);
                line.add(checkboxes[compIndex], BorderLayout.CENTER);
                groupPane.add(line);
                compIndex++;
            }
            checkboxPane.add(groupPane);
        }
        gridC.gridx = 0;
        gridC.gridy = 0;
        gridC.fill = GridBagConstraints.BOTH;
        JScrollPane scrollPane = new JScrollPane(checkboxPane);
        scrollPane.setPreferredSize(new Dimension(450, 300));
        gridBagLayout.setConstraints(scrollPane, gridC);
        getContentPane().add(scrollPane);

        JButton helpButton = new JButton("Help");
        helpButton.setMnemonic(KeyEvent.VK_H);
        helpButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                displayHelpGUI();
            }
        });
        JButton settingsButton = new JButton("Settings");
        settingsButton.setMnemonic(KeyEvent.VK_S);
        settingsButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                currentComponent = "Global properties";
                displaySettingsGUI();
            }
        });
        runButton = new JButton("Run");
        runButton.setMnemonic(KeyEvent.VK_R);
        runButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                runSelectedComponents();
            }
        });

        JButton quitAndSaveButton = new JButton("Quit");
        quitAndSaveButton.setMnemonic(KeyEvent.VK_Q);
        quitAndSaveButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                try {
                    askIfSave();
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                }
                System.exit(0);
            }
        });

        gridC.gridy = 1;
        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout(new FlowLayout());
        //buttonPanel.setLayout(new BoxLayout(buttonPanel,BoxLayout.X_AXIS));
        //runButton.setAlignmentX(JButton.LEFT_ALIGNMENT);
        buttonPanel.add(runButton);
        //helpButton.setAlignmentX(JButton.LEFT_ALIGNMENT);
        buttonPanel.add(helpButton);
        //settingsButton.setAlignmentX(JButton.LEFT_ALIGNMENT);
        buttonPanel.add(settingsButton);
        //buttonPanel.add(Box.createHorizontalGlue());
        //quitAndSaveButton.setAlignmentX(JButton.RIGHT_ALIGNMENT);
        buttonPanel.add(quitAndSaveButton);
        gridBagLayout.setConstraints(buttonPanel, gridC);
        getContentPane().add(buttonPanel);

        //getContentPane().setPreferredSize(new Dimension(300, 300));
        // End program when closing window:
        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent evt) {
                try {
                    askIfSave();
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                }
                System.exit(0);
            }
        });
    }

    protected void displayHelpGUI() {
        Thread helpGUIThread = new Thread("DisplayHelpGUIThread") {
            public void run() {
                boolean ok = new HelpGUI(DatabaseImportMain.class.getResourceAsStream("help_import_main.html"))
                        .display();
                if (!ok) {
                    System.out.println("Error displaying helpfile " + "help_import_main.html");
                }
            }
        };
        helpGUIThread.start();
    }

    protected void displaySettingsGUI() {
        new Thread("DisplaySettingsGUIThread") {
            public void run() {
                Map<String, String> comps2HelpText = db.getComps2HelpText();
                new SettingsGUI(db, db.getAllPropsForDisplay(), currentComponent, comps2HelpText);
            }
        }.start();
    }

    /**
     * Run the selected components in a different thread.
     *
     */
    protected void runSelectedComponents() {
        new Thread("RunSelectedComponentsThread") {
            public void run() {
                try {
                    runButton.setEnabled(false);
                    for (int i = 0; i < components.length; i++) {
                        if (checkboxes[i].isSelected()) {
                            boolean success = false;
                            Container parent = checkboxes[i].getParent();
                            final JProgressBar progress = new JProgressBar();
                            final VoiceImportComponent oneComponent = components[i];
                            if (oneComponent.getProgress() != -1) {
                                progress.setStringPainted(true);
                                new Thread("ProgressThread") {
                                    public void run() {
                                        int percent = 0;
                                        while (progress.isVisible()) {
                                            progress.setValue(percent);
                                            try {
                                                Thread.sleep(500);
                                            } catch (InterruptedException ie) {
                                            }
                                            percent = oneComponent.getProgress();
                                        }
                                    }
                                }.start();
                            } else {
                                progress.setIndeterminate(true);
                            }
                            parent.add(progress, BorderLayout.EAST);
                            progress.setVisible(true);
                            parent.validate();
                            try {
                                success = oneComponent.compute();
                            } catch (Exception exc) {
                                checkboxes[i].setBackground(Color.RED);
                                throw new Exception("The component " + checkboxes[i].getText()
                                        + " produced the following exception: ", exc);
                            } finally {
                                checkboxes[i].setSelected(false);
                                progress.setVisible(false);
                            }
                            if (success) {
                                checkboxes[i].setBackground(Color.GREEN);
                            } else {
                                checkboxes[i].setBackground(Color.RED);
                            }
                        }
                    }
                } catch (Throwable e) {
                    e.printStackTrace();
                } finally {
                    runButton.setEnabled(true);
                }

            }
        }.start();
    }

    protected void askIfSave() throws IOException {
        if (bnl.hasChanged()) {
            int answer = JOptionPane.showOptionDialog(this, "Do you want to save the list of basenames?", "Save?",
                    JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, null, null);
            if (answer == JOptionPane.YES_OPTION) {
                JFileChooser fc = new JFileChooser();
                fc.setSelectedFile(new File(db.getProp(db.BASENAMEFILE)));
                int returnVal = fc.showSaveDialog(this);
                if (returnVal == JFileChooser.APPROVE_OPTION) {
                    bnl.write(fc.getSelectedFile());
                }
            }
        } else {
            System.exit(0);
        }
    }

    protected void closeGUI() {
        // This doesn't work because Java cannot close the X11 connection, see
        // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4420885
        int answer = JOptionPane.showOptionDialog(this,
                "Do you want to close this GUI?\n\n"
                        + "The components that are currently running will continue to run,\n"
                        + "but you will not be able to save settings or select/deselect\n" + "components to run.\n"
                        + "This may be useful when running this tool using 'nohup' on a server\n"
                        + "because it allows you to log off without stopping the process.",
                "Really close GUI?", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, null, null);
        if (answer == JOptionPane.YES_OPTION) {
            this.setVisible(false);
            this.dispose();
        }
    }

    public static String[][] readComponentList(InputStream fileIn) throws IOException {
        List<String> groups = new ArrayList<String>();
        Map<String, String> groups2Names = new HashMap<String, String>();
        Map<String, List<String>> groups2Components = new HashMap<String, List<String>>();
        try {
            BufferedReader in = new BufferedReader(new InputStreamReader(fileIn, "UTF-8"));
            String line;
            while ((line = in.readLine()) != null) {
                line = line.trim();
                if (line.startsWith("#") || line.equals(""))
                    continue;
                //System.out.println(line);
                String[] lineSplit = line.split(" ");
                if (lineSplit[0].equals("group")) {
                    //we have a group
                    //line looks like "group basic_data basic data files"
                    groups.add(lineSplit[1]);
                    StringBuilder nameBuf = new StringBuilder();
                    for (int i = 2; i < lineSplit.length; i++) {
                        nameBuf.append(lineSplit[i] + " ");
                    }
                    groups2Names.put(lineSplit[1], nameBuf.toString().trim());
                } else {
                    //we have a component
                    //line looks like 
                    //"marytts.tools.voiceimport.WaveformTimelineMaker basic_data"
                    if (groups2Components.containsKey(lineSplit[1])) {
                        List<String> comps = groups2Components.get(lineSplit[1]);
                        comps.add(lineSplit[0]);
                    } else {
                        List<String> comps = new ArrayList<String>();
                        comps.add(lineSplit[0]);
                        groups2Components.put(lineSplit[1], comps);
                    }
                }
            }
            in.close();
        } catch (IOException e) {
            throw new IOException(
                    "Problem reading list of voice import components -- importMain.config seems broken", e);
        }
        String[][] result = new String[groups.size()][];
        for (int i = 0; i < groups.size(); i++) {
            String groupKey = groups.get(i);
            String groupName = groups2Names.get(groupKey);
            List<String> components = groups2Components.get(groupKey);
            if (components == null) //group is empty
                continue;
            String[] group = new String[components.size() + 1];
            group[0] = groupName;
            for (int j = 0; j < components.size(); j++) {
                group[j + 1] = components.get(j);
            }
            result[i] = group;
        }
        return result;
    }

    public static void main(String[] args) throws Exception {
        File voiceDir = determineVoiceBuildingDir(args);
        if (voiceDir == null) {
            throw new IllegalArgumentException("Cannot determine voice building directory.");
        }
        File wavDir = new File(voiceDir, "wav");
        //System.out.println(System.getProperty("user.dir")+System.getProperty("file.separator")+"wav");
        assert wavDir.exists() : "no wav dir at " + wavDir.getAbsolutePath();

        /* Read the list of components */
        File importMainConfigFile = new File(voiceDir, "importMain.config");
        if (!importMainConfigFile.exists()) {
            FileUtils.copyInputStreamToFile(DatabaseImportMain.class.getResourceAsStream("importMain.config"),
                    importMainConfigFile);
        }
        assert importMainConfigFile.exists();

        String[][] groups2comps = readComponentList(new FileInputStream(importMainConfigFile));

        VoiceImportComponent[] components = createComponents(groups2comps);

        /* Load DatabaseLayout */
        File configFile = new File(voiceDir, "database.config");

        DatabaseLayout db = new DatabaseLayout(configFile, components);
        if (!db.isInitialized())
            return;

        if (args.length > 0) { // non-gui mode: arguments are expected to be component names, in order or application
            for (String compName : args) {
                VoiceImportComponent component = null;
                for (VoiceImportComponent comp : components) {
                    if (comp.getName().equals(compName)) {
                        component = comp;
                        break;
                    }
                }
                if (component != null) {
                    System.out.println("Running " + compName);
                    component.compute();
                } else {
                    throw new IllegalArgumentException("No such voice import component: " + compName);
                }

            }
        } else {
            /* Display GUI */
            String voicename = db.getProp(db.VOICENAME);
            DatabaseImportMain importer = new DatabaseImportMain("Database import: " + voicename, components, db,
                    groups2comps);
            importer.pack();
            // Center window on screen:
            importer.setLocationRelativeTo(null);
            importer.setVisible(true);
        }

    }

    /**
     * @param groups2comps
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws ClassNotFoundException
     */
    private static VoiceImportComponent[] createComponents(String[][] groups2comps)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        /* Create component classes */
        List<VoiceImportComponent> compsList = new ArrayList<VoiceImportComponent>();
        //loop over the groups
        for (int i = 0; i < groups2comps.length; i++) {
            //get the components for this group
            String[] nextComps = groups2comps[i];
            //loop over the components (first element is group name; ignore)
            for (int j = 1; j < nextComps.length; j++) {
                //get the class name of this component  
                String className = nextComps[j];
                //System.out.println(className);
                //create a new instance of this class and store in compsList
                compsList.add((VoiceImportComponent) Class.forName(className).newInstance());
                //remove "de.dfki...." from class name and store in groups2comps
                nextComps[j] = className.substring(className.lastIndexOf('.') + 1);
            }
        }
        return compsList.toArray(new VoiceImportComponent[compsList.size()]);
    }

    private static File determineVoiceBuildingDir(String[] args) {
        // Determine the voice building directory in the following order:
        // 1. System property "user.dir"
        // 2. First command line argument
        // 3. current directory
        // 4. Prompt user via gui.
        // Do a sanity check -- do they exist, do they have a wav/ subdirectory?

        String voiceBuildingDir = null;
        Vector<String> candidates = new Vector<String>();
        candidates.add(System.getProperty("user.dir"));
        if (args.length > 0)
            candidates.add(args[0]);
        candidates.add("."); // current directory
        for (String dir : candidates) {
            if (dir != null && new File(dir).isDirectory() && new File(dir + "/wav").isDirectory()) {
                voiceBuildingDir = dir;
                break;
            }
        }
        if (voiceBuildingDir == null) { // need to ask user
            JFrame window = new JFrame("This is the Frames's Title Bar!");
            JFileChooser fc = new JFileChooser();
            fc.setDialogTitle("Choose Voice Building Directory");
            fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
            System.out.println("Opening GUI....... ");
            //outDir.setText(file.getAbsolutePath());
            //System.exit(0);
            int returnVal = fc.showOpenDialog(window);
            if (returnVal == JFileChooser.APPROVE_OPTION) {
                File file = fc.getSelectedFile();
                if (file != null)
                    voiceBuildingDir = file.getAbsolutePath();
            }
        }
        System.setProperty("user.dir", voiceBuildingDir);
        if (voiceBuildingDir != null) {
            return new File(voiceBuildingDir);
        } else {
            return null;
        }
    }

    class ConfigButtonActionListener implements ActionListener {
        private String comp;

        public ConfigButtonActionListener(String comp) {
            this.comp = comp;
        }

        public void actionPerformed(ActionEvent ae) {
            currentComponent = comp;
            displaySettingsGUI();
        }
    }

}