//----------------------------------------------------------------------------//
// //
// S c o r e A c t i o n s //
// //
//----------------------------------------------------------------------------//
// <editor-fold defaultstate="collapsed" desc="hdr"> //
// Copyright © Hervé Bitteur and others 2000-2013. All rights reserved. //
// This software is released under the GNU General Public License. //
// Goto http://kenai.com/projects/audiveris to report bugs or suggestions. //
//----------------------------------------------------------------------------//
// </editor-fold>
package omr.score.ui;
import omr.Main;
import omr.constant.Constant;
import omr.constant.ConstantSet;
import omr.score.Score;
import omr.score.ScoresManager;
import omr.score.entity.ScorePart;
import omr.script.Script;
import omr.sheet.Sheet;
import omr.sheet.ui.SheetsController;
import omr.step.Stepping;
import omr.step.Steps;
import omr.ui.MainGui;
import omr.ui.util.OmrFileFilter;
import omr.ui.util.UIUtil;
import omr.util.BasicTask;
import omr.util.WrappedBoolean;
import org.jdesktop.application.Action;
import org.jdesktop.application.Task;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
/**
* Class {@code ScoreActions} gathers user actions related to scores
*
* @author Hervé Bitteur
*/
public class ScoreActions
extends ScoreDependent
{
//~ Static fields/initializers ---------------------------------------------
/** Specific application parameters */
private static final Constants constants = new Constants();
/** Usual logger utility */
private static final Logger logger = LoggerFactory.getLogger(
ScoreActions.class);
/** Should we rebuild the score on each user action */
private static final String REBUILD_ALLOWED = "rebuildAllowed";
/** Should we persist any manual assignment (for later training) */
private static final String MANUAL_PERSISTED = "manualPersisted";
/** Singleton */
private static ScoreActions INSTANCE;
//~ Instance fields --------------------------------------------------------
//
/** Flag to allow automatic score rebuild on every user edition action */
private boolean rebuildAllowed = true;
/** Flag to indicate that manual assignments must be persisted */
private boolean manualPersisted = false;
//~ Constructors -----------------------------------------------------------
//
//--------------//
// ScoreActions //
//--------------//
/**
* Creates a new ScoreActions object.
*/
protected ScoreActions ()
{
}
//~ Methods ----------------------------------------------------------------
//-----------------//
// checkParameters //
//-----------------//
/**
* Make sure that the score parameters are properly set up, even by
* prompting the user for them, otherwise return false
*
* @param sheet the provided sheet
* @return true if OK, false otherwise
*/
public static boolean checkParameters (Sheet sheet)
{
if (constants.promptParameters.getValue()) {
return applyUserSettings(sheet);
} else {
return fillParametersWithDefaults(sheet.getScore());
}
}
//-------------//
// getInstance //
//-------------//
/**
* Report the singleton
*
* @return the unique instance of this class
*/
public static synchronized ScoreActions getInstance ()
{
if (INSTANCE == null) {
INSTANCE = new ScoreActions();
}
return INSTANCE;
}
//
//-------------//
// browseScore //
//-------------//
/**
* Launch the tree display of the current score.
*
* @param e
*/
@Action(enabledProperty = SCORE_AVAILABLE)
public void browseScore (ActionEvent e)
{
MainGui.getInstance()
.show(ScoreController.getCurrentScore().getBrowserFrame());
}
//------------//
// buildScore //
//------------//
/**
* Translate all sheet glyphs to score entities, or rebuild the
* sheet at end if SCORE step has already been reached.
* Actually, it's just a convenient way to launch the SCORE step
* or relaunch from the SYMBOLS step.
*
* @param e the event that triggered this action
* @return the task to launch in background
*/
@Action(enabledProperty = SCORE_IDLE)
public Task<Void, Void> buildScore (ActionEvent e)
{
Sheet sheet = SheetsController.getCurrentSheet();
if (sheet.isDone(Steps.valueOf(Steps.SCORE))) {
return new RebuildTask(sheet);
} else {
return new BuildTask(sheet);
}
}
//------------------//
// defineParameters //
//------------------//
/**
* Launch the dialog to set up score parameters.
*
* @param e the event that triggered this action
*/
@Action
public void defineParameters (ActionEvent e)
{
applyUserSettings(SheetsController.getCurrentSheet());
}
/**
* Dump the script of the sheet currently selected
*/
@Action(enabledProperty = "sheetAvailable")
public void dumpCurrentScript ()
{
Sheet sheet = SheetsController.getCurrentSheet();
if (sheet != null) {
Script script = sheet.getScore()
.getScript();
if (script != null) {
script.dump();
}
}
}
//-----------//
// dumpScore //
//-----------//
/**
* Dump the internals of a score to system output
*
* @param e the event that triggered this action
*/
@Action(enabledProperty = SCORE_AVAILABLE)
public void dumpScore (ActionEvent e)
{
ScoreController.getCurrentScore()
.dump();
}
//-------------------//
// isManualPersisted //
//-------------------//
public boolean isManualPersisted ()
{
return manualPersisted;
}
//------------------//
// isRebuildAllowed //
//------------------//
public boolean isRebuildAllowed ()
{
return rebuildAllowed;
}
//--------------------//
// setManualPersisted //
//--------------------//
public void setManualPersisted (boolean value)
{
boolean oldValue = this.manualPersisted;
this.manualPersisted = value;
firePropertyChange(MANUAL_PERSISTED, oldValue, value);
}
//-------------------//
// setRebuildAllowed //
//-------------------//
public void setRebuildAllowed (boolean value)
{
boolean oldValue = this.rebuildAllowed;
this.rebuildAllowed = value;
firePropertyChange(REBUILD_ALLOWED, oldValue, value);
}
//------------//
// storeScore //
//------------//
/**
* Export the currently selected score, using MusicXML format
*
* @param e the event that triggered this action
* @return the task to launch in background
*/
@Action(enabledProperty = SCORE_AVAILABLE)
public Task<Void, Void> storeScore (ActionEvent e)
{
final Sheet sheet = SheetsController.getCurrentSheet();
if (sheet == null) {
return null;
}
final File exportFile = sheet.getScore()
.getExportFile();
if (exportFile != null) {
return new StoreScoreTask(sheet, exportFile);
} else {
return storeScoreAs(e);
}
}
//--------------//
// storeScoreAs //
//--------------//
/**
* Export the currently selected score, using MusicXML format,
* to a user-provided file
*
* @param e the event that triggered this action
* @return the task to launch in background
*/
@Action(enabledProperty = SCORE_AVAILABLE)
public Task<Void, Void> storeScoreAs (ActionEvent e)
{
final Sheet sheet = SheetsController.getCurrentSheet();
if (sheet == null) {
return null;
}
// Let the user select a score output file
File exportFile = UIUtil.fileChooser(
true,
null,
ScoresManager.getInstance().getDefaultExportFile(
null,
sheet.getScore()),
new OmrFileFilter(
"XML files",
new String[]{ScoresManager.SCORE_EXTENSION}));
if (exportFile != null) {
return new StoreScoreTask(sheet, exportFile);
} else {
return null;
}
}
//---------------//
// togglePersist //
//---------------//
/**
* Action that toggles the persistency of manual assignments
*
* @param e the event that triggered this action
*/
@Action(selectedProperty = MANUAL_PERSISTED)
public void togglePersist (ActionEvent e)
{
logger.info(
"Persistency mode is {}",
(isManualPersisted() ? "on" : "off"));
}
//---------------//
// toggleRebuild //
//---------------//
/**
* Action that toggles the rebuild of score on every user edition
*
* @param e the event that triggered this action
*/
@Action(selectedProperty = REBUILD_ALLOWED)
public void toggleRebuild (ActionEvent e)
{
}
//------------------//
// writePhysicalPdf //
//------------------//
/**
* Write the currently selected score, as a PDF file
*
* @param e the event that triggered this action
* @return the task to launch in background
*/
@Action(enabledProperty = SCORE_AVAILABLE)
public Task<Void, Void> writeSheetPdf (ActionEvent e)
{
final Score score = ScoreController.getCurrentScore();
if (score == null) {
return null;
}
final File pdfFile = score.getPrintFile();
if (pdfFile != null) {
return new WriteSheetPdfTask(score, pdfFile);
} else {
return writeSheetPdfAs(e);
}
}
//-----------------//
// writeSheetPdfAs //
//-----------------//
/**
* Write the currently selected score, using PDF format,
* to a user-provided file
*
* @param e the event that triggered this action
* @return the task to launch in background
*/
@Action(enabledProperty = SCORE_AVAILABLE)
public Task<Void, Void> writeSheetPdfAs (ActionEvent e)
{
final Score score = ScoreController.getCurrentScore();
if (score == null) {
return null;
}
// Let the user select a PDF output file
File pdfFile = UIUtil.fileChooser(
true,
null,
ScoresManager.getInstance().getDefaultPrintFile(null, score),
new OmrFileFilter("PDF files", new String[]{".pdf"}));
if (pdfFile != null) {
return new WriteSheetPdfTask(score, pdfFile);
} else {
return null;
}
}
//-------------------//
// applyUserSettings //
//-------------------//
/**
* Prompts the user for interactive confirmation or modification of
* score/page parameters
*
* @param sheet the current sheet, or null
* @return true if parameters are applied, false otherwise
*/
private static boolean applyUserSettings (final Sheet sheet)
{
try {
final WrappedBoolean apply = new WrappedBoolean(false);
final ScoreParameters scoreParams = new ScoreParameters(sheet);
final JOptionPane optionPane = new JOptionPane(
scoreParams.getComponent(),
JOptionPane.QUESTION_MESSAGE,
JOptionPane.OK_CANCEL_OPTION);
final String frameTitle = (sheet != null)
? (sheet.getScore()
.getRadix()
+ " parameters")
: "General parameters";
final JDialog dialog = new JDialog(
Main.getGui().getFrame(),
frameTitle,
true); // Modal flag
dialog.setContentPane(optionPane);
dialog.setName("scoreParams");
optionPane.addPropertyChangeListener(
new PropertyChangeListener()
{
@Override
public void propertyChange (PropertyChangeEvent e)
{
String prop = e.getPropertyName();
if (dialog.isVisible()
&& (e.getSource() == optionPane)
&& (prop.equals(JOptionPane.VALUE_PROPERTY))) {
Object obj = optionPane.getValue();
int value = ((Integer) obj).intValue();
apply.set(value == JOptionPane.OK_OPTION);
// Exit only if user gives up or enters correct data
if (!apply.isSet()
|| scoreParams.commit(sheet)) {
dialog.setVisible(false);
dialog.dispose();
} else {
// Incorrect data, so don't exit yet
try {
// TODO: Is there a more civilized way?
optionPane.setValue(
JOptionPane.UNINITIALIZED_VALUE);
} catch (Exception ignored) {
}
}
}
}
});
dialog.pack();
MainGui.getInstance()
.show(dialog);
return apply.value;
} catch (Exception ex) {
logger.warn("Error in ScoreParameters", ex);
return false;
}
}
//----------------------------//
// fillParametersWithDefaults //
//----------------------------//
/**
* For some needed key parameters, fill them with default values if
* they are not yet set.
*
* @param score the related score
* @return true
*/
private static boolean fillParametersWithDefaults (Score score)
{
if (score.getPartList() != null) {
for (ScorePart scorePart : score.getPartList()) {
// Part name
if (scorePart.getName() == null) {
scorePart.setName(scorePart.getDefaultName());
}
// Part midi program
if (scorePart.getMidiProgram() == null) {
scorePart.setMidiProgram(scorePart.getDefaultProgram());
}
}
}
// Score global data
if (!score.hasVolume()) {
score.setVolume(Score.getDefaultVolume());
}
return true;
}
//~ Inner Classes ----------------------------------------------------------
//-------------------//
// WriteSheetPdfTask //
//-------------------//
public static class WriteSheetPdfTask
extends BasicTask
{
//~ Instance fields ----------------------------------------------------
final Score score;
final File pdfFile;
//~ Constructors -------------------------------------------------------
public WriteSheetPdfTask (Score score,
File pdfFile)
{
this.score = score;
this.pdfFile = pdfFile;
}
//~ Methods ------------------------------------------------------------
@Override
protected Void doInBackground ()
throws InterruptedException
{
Stepping.ensureScoreStep(Steps.valueOf(Steps.SCORE), score);
ScoresManager.getInstance()
.writePhysicalPdf(score, pdfFile);
return null;
}
}
//-----------//
// BuildTask //
//-----------//
private static class BuildTask
extends BasicTask
{
//~ Instance fields ----------------------------------------------------
private final Sheet sheet;
//~ Constructors -------------------------------------------------------
public BuildTask (Sheet sheet)
{
this.sheet = sheet;
}
//~ Methods ------------------------------------------------------------
@Override
protected Void doInBackground ()
throws InterruptedException
{
try {
Score score = sheet.getScore();
Stepping.ensureScoreStep(Steps.valueOf(Steps.SCORE), score);
} catch (Exception ex) {
logger.warn("Could not build score", ex);
}
return null;
}
}
//-----------//
// Constants //
//-----------//
private static final class Constants
extends ConstantSet
{
//~ Instance fields ----------------------------------------------------
Constant.Boolean promptParameters = new Constant.Boolean(
false,
"Should we prompt the user for score parameters?");
}
//-------------//
// RebuildTask //
//-------------//
private static class RebuildTask
extends BasicTask
{
//~ Instance fields ----------------------------------------------------
private final Sheet sheet;
//~ Constructors -------------------------------------------------------
public RebuildTask (Sheet sheet)
{
this.sheet = sheet;
}
//~ Methods ------------------------------------------------------------
@Override
protected Void doInBackground ()
throws InterruptedException
{
try {
Stepping.reprocessSheet(
Steps.valueOf(Steps.SYMBOLS),
sheet,
null,
true);
} catch (Exception ex) {
logger.warn("Could not refresh score", ex);
}
return null;
}
}
//----------------//
// StoreScoreTask //
//----------------//
private static class StoreScoreTask
extends BasicTask
{
//~ Instance fields ----------------------------------------------------
final Sheet sheet;
final Score score;
final File exportFile;
//~ Constructors -------------------------------------------------------
public StoreScoreTask (Sheet sheet,
File exportFile)
{
this.sheet = sheet;
this.score = sheet.getScore();
this.exportFile = exportFile;
}
//~ Methods ------------------------------------------------------------
@Override
protected Void doInBackground ()
throws InterruptedException
{
score.setExportFile(exportFile);
Stepping.ensureScoreStep(Steps.valueOf(Steps.SCORE), score);
if (checkParameters(sheet)) {
Stepping.ensureScoreStep(Steps.valueOf(Steps.EXPORT), score);
}
return null;
}
}
}