//----------------------------------------------------------------------------//
// //
// S y m b o l M e n u //
// //
//----------------------------------------------------------------------------//
// <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.glyph.ui;
import omr.glyph.Evaluation;
import omr.glyph.Grades;
import omr.glyph.Shape;
import omr.glyph.ShapeEvaluator;
import omr.glyph.facets.Glyph;
import omr.sheet.SystemInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.awt.event.ActionEvent;
import java.util.Collections;
import java.util.Set;
/**
* Class {@code SymbolMenu} defines the menu which is linked to
* the current selection of one or several glyphs.
*
* @author Hervé Bitteur
*/
public class SymbolMenu
extends GlyphMenu
{
//~ Static fields/initializers ---------------------------------------------
/** Usual logger utility */
private static final Logger logger = LoggerFactory.getLogger(
SymbolMenu.class);
//~ Instance fields --------------------------------------------------------
// Links to partnering entities
private final ShapeFocusBoard shapeFocus;
private final ShapeEvaluator evaluator;
// To handle proposed compound shape
private Glyph proposedGlyph;
private Shape proposedShape;
//~ Constructors -----------------------------------------------------------
//------------//
// SymbolMenu //
//------------//
/**
* Create the Symbol menu.
*
* @param symbolsController the top companion
* @param evaluator the glyph evaluator
* @param shapeFocus the current shape focus
*/
public SymbolMenu (final SymbolsController symbolsController,
ShapeEvaluator evaluator,
ShapeFocusBoard shapeFocus)
{
super(symbolsController);
this.evaluator = evaluator;
this.shapeFocus = shapeFocus;
}
//~ Methods ----------------------------------------------------------------
//-----------------//
// registerActions //
//-----------------//
@Override
protected void registerActions ()
{
// Copy & Paste actions
register(0, new PasteAction());
register(0, new CopyAction());
// Deassign selected glyph(s)
register(0, new DeassignAction());
// Manually assign a shape
register(0, new AssignAction());
// Build a compound, with menu for shape selection
register(0, new CompoundAction());
// Segment the glyph into stems & leaves
register(0, new StemSegmentAction());
// Segment the glyph into short stems & leaves
register(0, new ShortStemSegmentAction());
// Build a compound, with proposed shape
register(0, new ProposedAction());
// Trim large slur glyphs
register(0, new TrimSlurAction());
// Dump current glyph
register(0, new DumpAction());
// Dump current glyph text info
register(0, new DumpTextAction());
// Display score counterpart
register(0, new TranslationAction());
// Display all glyphs of the same shape
register(0, new ShapeAction());
// Display all glyphs similar to the current glyph
register(0, new SimilarAction());
}
//~ Inner Classes ----------------------------------------------------------
//----------------//
// DumpTextAction //
//----------------//
/**
* Dump the text information of each glyph in the selected
* collection of glyphs.
*/
private class DumpTextAction
extends DynAction
{
//~ Constructors -------------------------------------------------------
public DumpTextAction ()
{
super(40);
}
//~ Methods ------------------------------------------------------------
@Override
public void actionPerformed (ActionEvent e)
{
for (Glyph glyph : nest.getSelectedGlyphSet()) {
logger.info(glyph.dumpOf());
}
}
@Override
public void update ()
{
if (glyphNb > 0) {
setEnabled(true);
StringBuilder sb = new StringBuilder();
sb.append("Dump text of ")
.append(glyphNb)
.append(" glyph");
if (glyphNb > 1) {
sb.append("s");
}
putValue(NAME, sb.toString());
putValue(SHORT_DESCRIPTION, "Dump text of selected glyphs");
} else {
setEnabled(false);
putValue(NAME, "Dump text");
putValue(SHORT_DESCRIPTION, "No glyph to dump text");
}
}
}
//----------------//
// ProposedAction //
//----------------//
/**
* Accept the proposed compound with its evaluated shape.
*/
private class ProposedAction
extends DynAction
{
//~ Constructors -------------------------------------------------------
public ProposedAction ()
{
super(30);
}
//~ Methods ------------------------------------------------------------
@Override
public void actionPerformed (ActionEvent e)
{
Glyph glyph = nest.getSelectedGlyph();
if ((glyph != null) && (glyph == proposedGlyph)) {
controller.asyncAssignGlyphs(
Collections.singleton(glyph),
proposedShape,
false);
}
}
@Override
public void update ()
{
// Proposed compound?
Glyph glyph = nest.getSelectedGlyph();
if ((glyphNb > 0) && (glyph != null) && (glyph.getId() == 0)) {
SystemInfo system = sheet.getSystemOf(glyph);
Evaluation vote = evaluator.vote(
glyph,
system,
Grades.symbolMinGrade);
if (vote != null) {
proposedGlyph = glyph;
proposedShape = vote.shape;
setEnabled(true);
putValue(NAME, "Build compound as " + proposedShape);
putValue(SHORT_DESCRIPTION, "Accept the proposed compound");
return;
}
}
// Nothing to propose
proposedGlyph = null;
proposedShape = null;
setEnabled(false);
putValue(NAME, "Build compound");
putValue(SHORT_DESCRIPTION, "No proposed compound");
}
}
//-------------//
// ShapeAction //
//-------------//
/**
* Set the focus on all glyphs with the same shape.
*/
private class ShapeAction
extends DynAction
{
//~ Constructors -------------------------------------------------------
public ShapeAction ()
{
super(70);
}
//~ Methods ------------------------------------------------------------
@Override
public void actionPerformed (ActionEvent e)
{
Set<Glyph> glyphs = nest.getSelectedGlyphSet();
if ((glyphs != null) && (glyphs.size() == 1)) {
Glyph glyph = glyphs.iterator()
.next();
if (glyph.getShape() != null) {
shapeFocus.setCurrentShape(glyph.getShape());
}
}
}
@Override
public void update ()
{
Glyph glyph = nest.getSelectedGlyph();
if ((glyph != null) && (glyph.getShape() != null)) {
setEnabled(true);
putValue(NAME, "Show all " + glyph.getShape() + "'s");
putValue(SHORT_DESCRIPTION, "Display all glyphs of this shape");
} else {
setEnabled(false);
putValue(NAME, "Show all");
putValue(SHORT_DESCRIPTION, "No shape defined");
}
}
}
//------------------------//
// ShortStemSegmentAction //
//------------------------//
/**
* Perform a segmentation on the selected glyphs, into short stems
* and leaves.
*/
private class ShortStemSegmentAction
extends DynAction
{
//~ Constructors -------------------------------------------------------
public ShortStemSegmentAction ()
{
super(50);
}
//~ Methods ------------------------------------------------------------
@Override
public void actionPerformed (ActionEvent e)
{
Set<Glyph> glyphs = nest.getSelectedGlyphSet();
((SymbolsController) controller).asyncSegment(glyphs, true); // isShort
}
@Override
public void update ()
{
putValue(NAME, "Look for short verticals");
if (sheet.hasSystemBoundaries() && (glyphNb > 0) && noVirtuals) {
setEnabled(true);
putValue(SHORT_DESCRIPTION, "Extract short stems and leaves");
} else {
setEnabled(false);
putValue(SHORT_DESCRIPTION, "No glyph to segment");
}
}
}
//---------------//
// SimilarAction //
//---------------//
/**
* Set the focus on all glyphs similar to the selected glyph.
*/
private class SimilarAction
extends DynAction
{
//~ Constructors -------------------------------------------------------
public SimilarAction ()
{
super(70);
}
//~ Methods ------------------------------------------------------------
@Override
public void actionPerformed (ActionEvent e)
{
Set<Glyph> glyphs = nest.getSelectedGlyphSet();
if ((glyphs != null) && (glyphs.size() == 1)) {
Glyph glyph = glyphs.iterator()
.next();
if (glyph != null) {
shapeFocus.setSimilarGlyph(glyph);
}
}
}
@Override
public void update ()
{
Glyph glyph = nest.getSelectedGlyph();
if (glyph != null) {
setEnabled(true);
putValue(NAME, "Show similar glyphs");
putValue(
SHORT_DESCRIPTION,
"Display all glyphs similar to this one");
} else {
setEnabled(false);
putValue(NAME, "Show similar");
putValue(SHORT_DESCRIPTION, "No glyph selected");
}
}
}
//-------------------//
// StemSegmentAction //
//-------------------//
/**
* Perform a segmentation on the selected glyphs, into stems and
* leaves.
*/
private class StemSegmentAction
extends DynAction
{
//~ Constructors -------------------------------------------------------
public StemSegmentAction ()
{
super(50);
}
//~ Methods ------------------------------------------------------------
@Override
public void actionPerformed (ActionEvent e)
{
Set<Glyph> glyphs = nest.getSelectedGlyphSet();
((SymbolsController) controller).asyncSegment(glyphs, false); // isShort
}
@Override
public void update ()
{
putValue(NAME, "Look for verticals");
if (sheet.hasSystemBoundaries() && (glyphNb > 0) && noVirtuals) {
setEnabled(true);
putValue(SHORT_DESCRIPTION, "Extract stems and leaves");
} else {
setEnabled(false);
putValue(SHORT_DESCRIPTION, "No glyph to segment");
}
}
}
//-------------------//
// TranslationAction //
//-------------------//
/**
* Display the score entity that translates this glyph.
*/
private class TranslationAction
extends DynAction
{
//~ Constructors -------------------------------------------------------
public TranslationAction ()
{
super(40);
}
//~ Methods ------------------------------------------------------------
@Override
public void actionPerformed (ActionEvent e)
{
Set<Glyph> glyphs = nest.getSelectedGlyphSet();
((SymbolsController) controller).showTranslations(glyphs);
}
@Override
public void update ()
{
if (glyphNb > 0) {
for (Glyph glyph : nest.getSelectedGlyphSet()) {
if (glyph.isTranslated()) {
setEnabled(true);
StringBuilder sb = new StringBuilder();
sb.append("Show translations");
putValue(NAME, sb.toString());
putValue(
SHORT_DESCRIPTION,
"Show translations related to the glyph(s)");
return;
}
}
}
// No translation to show
setEnabled(false);
putValue(NAME, "Translations");
putValue(SHORT_DESCRIPTION, "No translation");
}
}
//----------------//
// TrimSlurAction //
//----------------//
/**
* Cleanup a glyph with focus on its slur shape.
*/
private class TrimSlurAction
extends DynAction
{
//~ Constructors -------------------------------------------------------
public TrimSlurAction ()
{
super(60);
}
//~ Methods ------------------------------------------------------------
@Override
public void actionPerformed (ActionEvent e)
{
Set<Glyph> glyphs = nest.getSelectedGlyphSet();
((SymbolsController) controller).asyncTrimSlurs(glyphs);
}
@Override
public void update ()
{
putValue(NAME, "Trim slur");
if (sheet.hasSystemBoundaries() && (glyphNb > 0) && noVirtuals) {
setEnabled(true);
putValue(SHORT_DESCRIPTION, "Extract slur from large glyph");
} else {
setEnabled(false);
putValue(SHORT_DESCRIPTION, "No slur to fix");
}
}
}
}