/*
* Created on Mar 9, 2007
*
* Copyright (c) 2007 Jens Gulden
*
* http://www.frinika.com
*
* This file is part of Frinika.
*
* Frinika 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 2 of the License, or
* (at your option) any later version.
* Frinika 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 Frinika; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.frinika.sequencer.gui;
import java.text.ParseException;
import javax.swing.SpinnerNumberModel;
import com.frinika.sequencer.model.util.TimeUtils;
/**
* Model for TickSpinner.
*
* @see TickSpinner
* @author Jens Gulden
*/
public class TickSpinnerModel extends SpinnerNumberModel {
protected TimeFormat format;
protected TimeUtils timeUtils;
public TickSpinnerModel(TimeUtils timeUtils) {
this(TimeFormat.BAR_BEAT_TICK, 0L, timeUtils);
}
public TickSpinnerModel(TimeFormat format, TimeUtils timeUtils) {
this(format, 0L, timeUtils);
}
public TickSpinnerModel(long value, TimeUtils timeUtils) {
this(timeUtils);
setValue(value);
}
public TickSpinnerModel(TimeFormat format, long value, TimeUtils timeUtils) {
this(format, value, false, timeUtils);
}
public TickSpinnerModel(TimeFormat format, long value, boolean allowNegative, TimeUtils timeUtils) {
super(value, allowNegative ? null : 0L, null, 1L);
this.format = format;
this.timeUtils = timeUtils;
}
public TimeFormat getFormat() {
return format;
}
public long stringToTicks(String s) throws ParseException {
try {
switch (format) {
case BEAT: return Math.round( Float.parseFloat(s) * timeUtils.ticksPerBeat() );
case NOTE_LENGTH: return -1; // TODO (but currently not used with Spinner)
default:
if (s.indexOf(':') == -1) {
s += ":000";
}
if (s.indexOf('.') == -1) {
//s = "0." + s;
return timeUtils.beatTickToTick(s);
}
return timeUtils.barBeatTickToTick(s);
}
} catch (Exception e) {
e.printStackTrace();
throw new ParseException(e.getMessage(),0);
}
}
public String ticksToString(long tick) {
switch (format) {
case BAR_BEAT_TICK: return timeUtils.tickToBarBeatTick(tick);
case BEAT_TICK: return timeUtils.tickToBeatTick(tick);
case BAR_BEAT: return timeUtils.tickToBarBeat(tick);
case BEAT: return String.valueOf((float)tick / timeUtils.ticksPerBeat());
case NOTE_LENGTH: return null; // TODO (but currently not used with Spinner)
default: assert false; return null;
}
}
public void updateStepSize(String currentValue, int caretPos) {
final int s = getStepSize(currentValue, caretPos);
//(new Thread() {
// public void run() {
setStepSizeNoStateChange( s ); // must happen in different thread - no longer since firing event is disabled
// }
//}).start();
}
private boolean suppressFireStateChange = false;
private synchronized void setStepSizeNoStateChange(Number stepSize) { // synchronized!
suppressFireStateChange = true; // cheap hack to avoid firing a state-changed event which would confuse cursor-position etc., and also would lead to an error due to chnging state in reaction to a state change event
super.setStepSize(stepSize);
suppressFireStateChange = false;
}
@Override
protected void fireStateChanged() {
if ( ! suppressFireStateChange ) { // hack
super.fireStateChanged();
}
}
public int getStepSize(String currentValue, int caretPos) {
if (format == TimeFormat.BEAT) {
return (int)timeUtils.ticksPerBeat();
} else {
int colonPos = currentValue.lastIndexOf(':');
if (caretPos > colonPos) { // editing ticks (also if ':' is missing)
return 1;
} else {
int dotPos = currentValue.lastIndexOf('.');
if (caretPos > dotPos) { // editing beats (also if '.' is missing)
return (int)timeUtils.ticksPerBeat();
} else { // editing bars
return (int)(timeUtils.ticksPerBeat() * timeUtils.beatsPerBar((Long)this.getValue()));
}
}
}
}
}