//----------------------------------------------------------------------------//
// //
// I n s e r t T a s k //
// //
//----------------------------------------------------------------------------//
// <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.script;
import omr.glyph.Shape;
import omr.glyph.VirtualGlyph;
import omr.glyph.facets.Glyph;
import omr.grid.StaffInfo;
import omr.selection.GlyphSetEvent;
import omr.selection.MouseMovement;
import omr.selection.SelectionHint;
import omr.sheet.Sheet;
import omr.sheet.SystemInfo;
import omr.util.PointFacade;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
/**
* Class {@code InsertTask} inserts a set of (virtual) glyphs into the
* sheet environment.
*
* @author Hervé Bitteur
*/
public class InsertTask
extends GlyphTask
{
//~ Instance fields --------------------------------------------------------
/** Shape of the inserted glyphs */
@XmlAttribute
private final Shape shape;
/** Locations */
private List<Point> locations;
/** Wrapping of the collections of points */
@XmlElementWrapper(name = "locations")
@XmlElement(name = "point")
private PointFacade[] points;
//~ Constructors -----------------------------------------------------------
//------------//
// InsertTask //
//------------//
/**
* Create an glyph insertion task.
*
* @param sheet the sheet impacted
* @param shape the inserted shape
* @param locations the locations for insertion
* @throws IllegalArgumentException if any of the arguments is not valid
*/
public InsertTask (Sheet sheet,
Shape shape,
Collection<Point> locations)
{
super(sheet);
// Check parameters
if (shape == null) {
throw new IllegalArgumentException(
getClass().getSimpleName() + " needs a non-null shape");
}
if ((locations == null) || locations.isEmpty()) {
throw new IllegalArgumentException(
getClass().getSimpleName() + " needs at least one location");
}
this.shape = shape;
this.locations = new ArrayList<>(locations);
}
//------------//
// InsertTask //
//------------//
/** No-arg constructor for JAXB only */
private InsertTask ()
{
shape = null; // Dummy value
}
//~ Methods ----------------------------------------------------------------
//------//
// core //
//------//
@Override
public void core (Sheet sheet)
throws Exception
{
// Nothing to do
}
//--------//
// epilog //
//--------//
@Override
public void epilog (Sheet sheet)
{
super.epilog(sheet);
logger.debug("{}", this);
// Take inserted glyph(s) as selected glyph(s)
sheet.getNest().getGlyphService().publish(
new GlyphSetEvent(
this,
SelectionHint.GLYPH_INIT,
MouseMovement.PRESSING,
glyphs));
}
//------------------//
// getInsertedShape //
//------------------//
/**
* Report the inserted shape.
*
* @return the insertedShape
*/
public Shape getInsertedShape ()
{
return shape;
}
//-----------------//
// internalsString //
//-----------------//
@Override
protected String internalsString ()
{
StringBuilder sb = new StringBuilder(super.internalsString());
sb.append(" insert");
sb.append(" ").append(shape);
if (!locations.isEmpty()) {
sb.append(" locations[");
for (Point point : locations) {
sb.append(" ").append(point.toString());
}
sb.append("]");
} else {
sb.append(" no-locations");
}
return sb.toString();
}
//-----------------------//
// retrieveCurrentImpact //
//-----------------------//
@Override
protected SortedSet<SystemInfo> retrieveCurrentImpact (Sheet sheet)
{
SortedSet<SystemInfo> impactedSystems = new TreeSet<>();
for (Point location : locations) {
SystemInfo system = sheet.getSystemOf(location);
if (system != null) {
// Include this system
impactedSystems.add(system);
}
if (shape.isPersistent()) {
// Include all following systems as well
impactedSystems.addAll(remaining(system));
}
}
return impactedSystems;
}
//----------------//
// retrieveGlyphs //
//----------------//
/**
* Here, we have to build virtual glyphs, based on the desired
* shape and the locations.
*/
@Override
protected void retrieveGlyphs ()
{
glyphs = new LinkedHashSet<>();
for (Point location : locations) {
Glyph glyph = new VirtualGlyph(
shape,
sheet.getScale().getInterline(),
location);
// TODO: Some location other than the areacenter may be desired
// (depending on the shape)?
SystemInfo system = sheet.getSystemOf(glyph.getAreaCenter());
glyph = system.addGlyph(glyph);
system.computeGlyphFeatures(glyph);
// Specific for LEDGERs: add them to related staff
if (shape == Shape.LEDGER) {
StaffInfo staff = system.getStaffAt(glyph.getAreaCenter());
staff.addLedger(glyph);
}
glyphs.add(glyph);
}
}
//----------------//
// afterUnmarshal //
//----------------//
/**
* Called after all the properties (except IDREF) are unmarshalled
* for this object, but before this object is set to the parent object.
*/
private void afterUnmarshal (Unmarshaller um,
Object parent)
{
// Convert array of point facades -> locations
if (locations == null) {
locations = new ArrayList<>();
for (PointFacade facade : points) {
locations.add(new Point(facade.getX(), facade.getY()));
}
}
}
//---------------//
// beforeMarshal //
//---------------//
/**
* Called immediately before the marshalling of this object begins.
*/
private void beforeMarshal (Marshaller m)
{
// Convert locations -> array of point facades
if (points == null) {
List<PointFacade> facades = new ArrayList<>();
for (Point point : locations) {
facades.add(new PointFacade(point));
}
points = facades.toArray(new PointFacade[0]);
}
}
}