mirror of
https://github.com/peterdell/wudsn-ide.git
synced 2024-05-29 05:41:33 +00:00
675 lines
21 KiB
Java
675 lines
21 KiB
Java
/**
|
|
* Copyright (C) 2009 - 2021 <a href="https://www.wudsn.com" target="_top">Peter Dell</a>
|
|
*
|
|
* This file is part of WUDSN IDE.
|
|
*
|
|
* WUDSN IDE 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.
|
|
*
|
|
* WUDSN IDE 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 WUDSN IDE. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
package com.wudsn.ide.snd.editor;
|
|
|
|
import java.io.File;
|
|
import java.text.DateFormat;
|
|
import java.text.DecimalFormat;
|
|
import java.text.SimpleDateFormat;
|
|
import java.util.Date;
|
|
import java.util.List;
|
|
|
|
import org.eclipse.core.resources.IFile;
|
|
import org.eclipse.core.runtime.CoreException;
|
|
import org.eclipse.core.runtime.IProgressMonitor;
|
|
import org.eclipse.core.runtime.IStatus;
|
|
import org.eclipse.jface.dialogs.IInputValidator;
|
|
import org.eclipse.jface.dialogs.InputDialog;
|
|
import org.eclipse.jface.window.Window;
|
|
import org.eclipse.swt.SWT;
|
|
import org.eclipse.swt.events.SelectionEvent;
|
|
import org.eclipse.swt.events.SelectionListener;
|
|
import org.eclipse.swt.layout.FillLayout;
|
|
import org.eclipse.swt.layout.GridData;
|
|
import org.eclipse.swt.layout.GridLayout;
|
|
import org.eclipse.swt.layout.RowLayout;
|
|
import org.eclipse.swt.widgets.Composite;
|
|
import org.eclipse.swt.widgets.Display;
|
|
import org.eclipse.swt.widgets.FileDialog;
|
|
import org.eclipse.swt.widgets.Label;
|
|
import org.eclipse.swt.widgets.Scale;
|
|
import org.eclipse.swt.widgets.ToolBar;
|
|
import org.eclipse.swt.widgets.ToolItem;
|
|
import org.eclipse.ui.IEditorInput;
|
|
import org.eclipse.ui.IEditorSite;
|
|
import org.eclipse.ui.IFileEditorInput;
|
|
import org.eclipse.ui.PartInitException;
|
|
import org.eclipse.ui.part.EditorPart;
|
|
|
|
import com.wudsn.ide.base.common.FileUtility;
|
|
import com.wudsn.ide.base.common.HexUtility;
|
|
import com.wudsn.ide.base.common.MessageQueue;
|
|
import com.wudsn.ide.base.common.NumberUtility;
|
|
import com.wudsn.ide.base.common.StringUtility;
|
|
import com.wudsn.ide.base.common.TextUtility;
|
|
import com.wudsn.ide.base.gui.Action;
|
|
import com.wudsn.ide.base.gui.Application;
|
|
import com.wudsn.ide.base.gui.IntegerField;
|
|
import com.wudsn.ide.base.gui.MessageManager;
|
|
import com.wudsn.ide.base.gui.SWTFactory;
|
|
import com.wudsn.ide.base.gui.TextField;
|
|
import com.wudsn.ide.snd.SoundPlugin;
|
|
import com.wudsn.ide.snd.Texts;
|
|
import com.wudsn.ide.snd.player.Clock;
|
|
import com.wudsn.ide.snd.player.EmptyPlayer;
|
|
import com.wudsn.ide.snd.player.FileType;
|
|
import com.wudsn.ide.snd.player.SoundInfo;
|
|
import com.wudsn.ide.snd.player.SoundPlayer;
|
|
import com.wudsn.ide.snd.player.SoundPlayerListener;
|
|
|
|
/**
|
|
* Sound file editor, i.e. editor part for the visualization of the
|
|
* {@link SoundPlayer}.
|
|
*
|
|
* @author Peter Dell
|
|
*
|
|
* @since 1.6.1
|
|
*/
|
|
public final class SoundEditor extends EditorPart implements Application, SoundPlayerListener {
|
|
|
|
public final class MessageIds {
|
|
|
|
/**
|
|
* Creation is private.
|
|
*/
|
|
private MessageIds() {
|
|
}
|
|
|
|
public static final int TITLE = 1;
|
|
public static final int FORMAT = 2;
|
|
}
|
|
|
|
public final class Actions {
|
|
|
|
/**
|
|
* Creation is private.
|
|
*/
|
|
private Actions() {
|
|
}
|
|
|
|
public static final int PLAY = 100;
|
|
public static final int TOGGLE_PAUSE = 101;
|
|
public static final int STOP = 102;
|
|
public static final int EXPORT = 103;
|
|
|
|
}
|
|
|
|
private static class PositionScaleSelectionListener implements SelectionListener {
|
|
private Scale scale;
|
|
private SoundPlayer player;
|
|
|
|
public PositionScaleSelectionListener(Scale scale, SoundPlayer player) {
|
|
if (scale == null) {
|
|
throw new IllegalArgumentException("Parameter 'scale' must not be null.");
|
|
}
|
|
if (player == null) {
|
|
throw new IllegalArgumentException("Parameter 'player' must not be null.");
|
|
}
|
|
this.scale = scale;
|
|
this.player = player;
|
|
}
|
|
|
|
@Override
|
|
public void widgetSelected(SelectionEvent e) {
|
|
int position = scale.getSelection();
|
|
if ((e.stateMask & SWT.BUTTON1) != 0) {
|
|
if (Math.abs(position - player.getPosition()) < SoundPlayerListener.POSITION_UPDATE_INCREMENT) {
|
|
return;
|
|
}
|
|
}
|
|
player.seekPosition(scale.getSelection());
|
|
|
|
if (player.isPaused()) {
|
|
player.togglePause();
|
|
}
|
|
|
|
}
|
|
|
|
@Override
|
|
public void widgetDefaultSelected(SelectionEvent e) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// ID of the editor in the plugin manifest.
|
|
public static final String ID = "com.wudsn.ide.snd.editor.SoundEditor"; //$NON-NLS-1$
|
|
|
|
private MessageQueue messageQueue;
|
|
private MessageManager messageManager;
|
|
private SoundPlayer player;
|
|
|
|
private boolean partControlCreated;
|
|
private Composite mainComposite;
|
|
private TextField titleField;
|
|
private TextField formatField;
|
|
|
|
private TextField authorField;
|
|
private TextField dateField;
|
|
private TextField channelsField;
|
|
private DecimalFormat playerFrequencyFieldHertzFormat;
|
|
private TextField playerFrequencyField;
|
|
|
|
private TextField initAddressField;
|
|
private IntegerField playerAddressField;
|
|
private TextField musicAddressField;
|
|
|
|
private SongTableView songTableView;
|
|
|
|
private DateFormat positionFieldFormat;
|
|
private TextField positionField;
|
|
private Scale positionScale;
|
|
|
|
private VUMeterField vuMeterField;
|
|
|
|
private ToolItem playButton;
|
|
private ToolItem pauseButton;
|
|
private ToolItem stopButton;
|
|
private ToolItem exportButton;
|
|
private FileDialog exportFileDialog;
|
|
|
|
public SoundEditor() {
|
|
super();
|
|
messageQueue = new MessageQueue();
|
|
messageManager = new MessageManager(messageQueue, this);
|
|
}
|
|
|
|
// @Override
|
|
@Override
|
|
public MessageManager getMessageManager() {
|
|
return messageManager;
|
|
}
|
|
|
|
// @Override
|
|
@Override
|
|
public void performAction(Action action) {
|
|
if (action == null) {
|
|
throw new IllegalArgumentException("Parameter 'action' must not be null."); //$NON-NLS-1$
|
|
}
|
|
messageManager.clearMessages();
|
|
switch (action.getId()) {
|
|
case Actions.PLAY:
|
|
try {
|
|
player.play(songTableView.getSelectedSong(), SoundEditor.this);
|
|
} catch (CoreException ex) {
|
|
messageManager.sendMessage(MessageIds.TITLE, ex);
|
|
}
|
|
break;
|
|
case Actions.TOGGLE_PAUSE:
|
|
player.togglePause();
|
|
break;
|
|
case Actions.STOP:
|
|
player.stop();
|
|
break;
|
|
case Actions.EXPORT:
|
|
exportFileContentAs();
|
|
break;
|
|
|
|
}
|
|
dataToUI();
|
|
messageManager.displayMessages();
|
|
}
|
|
|
|
@Override
|
|
public void dispose() {
|
|
player.stop();
|
|
mainComposite.dispose();
|
|
partControlCreated = false;
|
|
}
|
|
|
|
@Override
|
|
public void doSave(IProgressMonitor monitor) {
|
|
|
|
}
|
|
|
|
@Override
|
|
public void doSaveAs() {
|
|
|
|
}
|
|
|
|
@Override
|
|
public void init(IEditorSite site, IEditorInput input) throws PartInitException {
|
|
if (site == null) {
|
|
throw new IllegalArgumentException("Parameter 'site' must not be null."); //$NON-NLS-1$
|
|
}
|
|
setSite(site);
|
|
setInput(input);
|
|
|
|
if (input != null) {
|
|
setPartName(input.getName());
|
|
} else {
|
|
setPartName(""); //$NON-NLS-1$
|
|
}
|
|
|
|
messageManager.clearMessages();
|
|
try {
|
|
if (input instanceof IFileEditorInput) {
|
|
IFileEditorInput fileEditorInput = (IFileEditorInput) input;
|
|
IFile file = fileEditorInput.getFile();
|
|
String fileName = file.getName();
|
|
player = SoundPlugin.getInstance().createSoundPlayer(file.getName());
|
|
|
|
if (player == null) {
|
|
// ERROR: MESSAGE_E500: No player registered for sound file
|
|
// {0}.
|
|
messageManager.sendMessage(MessageIds.TITLE, IStatus.ERROR, Texts.MESSAGE_E500, fileName);
|
|
player = new EmptyPlayer(fileName);
|
|
} else {
|
|
try {
|
|
player.load(fileName, file.getContents());
|
|
} catch (CoreException ex) {
|
|
// If loading fails, there should not be a real player.
|
|
player = new EmptyPlayer(fileName);
|
|
messageManager.sendMessage(MessageIds.TITLE, ex);
|
|
|
|
}
|
|
}
|
|
if (partControlCreated) {
|
|
dataToUI();
|
|
}
|
|
|
|
// If a module was loaded successfully, then there is a defaul
|
|
// song.
|
|
if (player.getInfo().getDefaultSong() >= 0) {
|
|
try {
|
|
player.play(player.getInfo().getDefaultSong(), this);
|
|
|
|
} catch (CoreException ex) {
|
|
messageManager.sendMessage(MessageIds.TITLE, ex);
|
|
}
|
|
}
|
|
}
|
|
} catch (RuntimeException ex) {
|
|
SoundPlugin.getInstance().logError("Error during initilization of SoundEditor", null, ex);
|
|
}
|
|
|
|
messageManager.displayMessages();
|
|
}
|
|
|
|
@Override
|
|
public boolean isDirty() {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean isSaveAsAllowed() {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public void createPartControl(Composite parent) {
|
|
|
|
parent.setLayout(new FillLayout(SWT.VERTICAL));
|
|
// parent.setLayout(new RowLayout(SWT.VERTICAL));
|
|
// parent.setLayoutData(null);
|
|
|
|
mainComposite = new Composite(parent, SWT.NONE);
|
|
mainComposite.setLayout(new FillLayout(SWT.VERTICAL));
|
|
|
|
Composite topComposite = createRowComposite(mainComposite, SWT.VERTICAL);
|
|
|
|
// Fields
|
|
Composite fieldsComposite = new Composite(topComposite, SWT.NONE);
|
|
fieldsComposite.setLayout(new GridLayout(4, true));
|
|
|
|
titleField = new TextField(fieldsComposite, Texts.SOUND_EDITOR_TITLE_LABEL, SWT.READ_ONLY);
|
|
messageManager.registerField(titleField, MessageIds.TITLE);
|
|
formatField = new TextField(fieldsComposite, Texts.SOUND_EDITOR_FORMAT_LABEL, SWT.READ_ONLY);
|
|
messageManager.registerField(formatField, MessageIds.FORMAT);
|
|
|
|
authorField = new TextField(fieldsComposite, Texts.SOUND_EDITOR_AUTHOR_LABEL, SWT.READ_ONLY);
|
|
dateField = new TextField(fieldsComposite, Texts.SOUND_EDITOR_DATE_LABEL, SWT.READ_ONLY);
|
|
|
|
channelsField = new TextField(fieldsComposite, Texts.SOUND_EDITOR_CHANNELS_LABEL, SWT.READ_ONLY);
|
|
playerFrequencyFieldHertzFormat = new DecimalFormat(Texts.SOUND_EDITOR_FREQUENCY_HERTZ_PATTERN);
|
|
playerFrequencyField = new TextField(fieldsComposite, Texts.SOUND_EDITOR_FREQUENCY_LABEL, SWT.READ_ONLY);
|
|
|
|
initAddressField = new TextField(fieldsComposite, Texts.SOUND_EDITOR_INIT_ADDRESS_LABEL, SWT.READ_ONLY);
|
|
playerAddressField = new IntegerField(fieldsComposite, Texts.SOUND_EDITOR_PLAYER_ADDRESS_LABEL, null, true, 4,
|
|
SWT.READ_ONLY);
|
|
musicAddressField = new TextField(fieldsComposite, Texts.SOUND_EDITOR_MUSIC_ADDRESS_LABEL, SWT.READ_ONLY);
|
|
SWTFactory.createLabels(fieldsComposite, 2);
|
|
|
|
// Position
|
|
positionFieldFormat = new SimpleDateFormat(Texts.SOUND_EDITOR_DURATION_PATTERN);
|
|
positionField = new TextField(fieldsComposite, Texts.SOUND_EDITOR_PLAYING_TIME_LABEL, SWT.READ_ONLY);
|
|
Label label = new Label(fieldsComposite, SWT.NONE);
|
|
label.setText(Texts.SOUND_EDITOR_PLAYYING_POSITION_LABEL);
|
|
positionScale = new Scale(fieldsComposite, SWT.HORIZONTAL);
|
|
positionScale.addSelectionListener(new PositionScaleSelectionListener(positionScale, player));
|
|
positionScale.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false));
|
|
|
|
ToolBar toolbar = new ToolBar(topComposite, SWT.HORIZONTAL);
|
|
|
|
playButton = new ToolItem(toolbar, SWT.PUSH);
|
|
playButton.setImage(Icons.PLAY);
|
|
playButton.setToolTipText(Texts.SOUND_EDITOR_PLAY_BUTTON_TOOLTIP);
|
|
playButton.addSelectionListener(new Action(Actions.PLAY, SoundEditor.this));
|
|
|
|
pauseButton = new ToolItem(toolbar, SWT.PUSH);
|
|
pauseButton.setImage(Icons.PAUSE);
|
|
pauseButton.setToolTipText(Texts.SOUND_EDITOR_PAUSE_BUTTON_TOOLTIP);
|
|
pauseButton.addSelectionListener(new Action(Actions.TOGGLE_PAUSE, SoundEditor.this));
|
|
|
|
stopButton = new ToolItem(toolbar, SWT.PUSH);
|
|
stopButton.setImage(Icons.STOP);
|
|
stopButton.setToolTipText(Texts.SOUND_EDITOR_STOP_BUTTON_TOOLTIP);
|
|
stopButton.addSelectionListener(new Action(Actions.STOP, SoundEditor.this));
|
|
|
|
exportButton = new ToolItem(toolbar, SWT.PUSH);
|
|
exportButton.setImage(Icons.EXPORT);
|
|
exportButton.setToolTipText(Texts.SOUND_EDITOR_EXPORT_BUTTON_TOOLTIP);
|
|
exportButton.addSelectionListener(new Action(Actions.EXPORT, SoundEditor.this));
|
|
|
|
songTableView = new SongTableView(topComposite, this);
|
|
songTableView.setInfo(player.getInfo());
|
|
|
|
// Volume control
|
|
vuMeterField = new VUMeterField(mainComposite, false, Texts.SOUND_EDITOR_VOLUME_LABEL, SWT.NONE);
|
|
|
|
partControlCreated = true;
|
|
dataToUI();
|
|
playerUpdated(SoundPlayerListener.ALL);
|
|
}
|
|
|
|
private Composite createRowComposite(Composite parent, int type) {
|
|
Composite result = new Composite(parent, SWT.NONE);
|
|
RowLayout layout = new RowLayout(type);
|
|
layout.spacing = layout.marginLeft = layout.marginRight = layout.marginTop = layout.marginBottom = 0;
|
|
layout.wrap = false;
|
|
layout.justify = false;
|
|
result.setLayout(layout);
|
|
return result;
|
|
}
|
|
|
|
@Override
|
|
public void setFocus() {
|
|
mainComposite.setFocus();
|
|
}
|
|
|
|
private void dataToUI() {
|
|
SoundInfo info;
|
|
info = player.getInfo();
|
|
|
|
titleField.setValue(StringUtility.isSpecified(info.getTitle()) ? info.getTitle() : getPartName());
|
|
if (StringUtility.isSpecified(info.getModuleFileType())) {
|
|
formatField.setValue(TextUtility.format(Texts.SOUND_EDITOR_FORMAT_PATTERN, info.getModuleTypeDescription(),
|
|
info.getModuleFileType()));
|
|
} else {
|
|
formatField.setValue(Texts.SOUND_EDITOR_UNKNOWN);
|
|
}
|
|
authorField
|
|
.setValue(StringUtility.isSpecified(info.getAuthor()) ? info.getAuthor() : Texts.SOUND_EDITOR_UNKNOWN);
|
|
dateField.setValue(StringUtility.isSpecified(info.getDate()) ? info.getDate() : Texts.SOUND_EDITOR_UNKNOWN);
|
|
String channels;
|
|
switch (info.getChannels()) {
|
|
case 0:
|
|
channels = "";
|
|
break;
|
|
case 1:
|
|
channels = Texts.SOUND_EDITOR_CHANNELS_MONO;
|
|
break;
|
|
case 2:
|
|
channels = Texts.SOUND_EDITOR_CHANNELS_STEREO;
|
|
break;
|
|
default:
|
|
channels = NumberUtility.getLongValueDecimalString(info.getChannels());
|
|
}
|
|
channelsField.setValue(channels);
|
|
|
|
String scanLines = String.valueOf(info.getPlayerRateScanLines());
|
|
String hertz = playerFrequencyFieldHertzFormat.format(info.getPlayerRateHertz());
|
|
String norm = info.getPlayerClock() == Clock.NTSC ? Texts.SOUND_EDITOR_NORM_NTSC : Texts.SOUND_EDITOR_NORM_PAL;
|
|
playerFrequencyField.setValue(TextUtility.format(Texts.SOUND_EDITOR_FREQUENCY_PATTERN, hertz, scanLines, norm));
|
|
|
|
String value = HexUtility.getLongValueHexString(info.getInitAddress(), 4);
|
|
if (info.isInitFulltime()) {
|
|
value = value + Texts.SOUND_EDITOR_INIT_ADDRESS_FULLTIME;
|
|
}
|
|
initAddressField.setValue(value);
|
|
playerAddressField.setValue(info.getPlayerAddress());
|
|
|
|
value = info.getMusicAddress() >= 0 ? HexUtility.getLongValueHexString(info.getMusicAddress(), 4) : "";
|
|
musicAddressField.setValue(value);
|
|
|
|
playButton.setEnabled(player.isLoaded());
|
|
pauseButton.setEnabled(player.isPlaying());
|
|
stopButton.setEnabled(player.isPlaying());
|
|
|
|
positionScale.setEnabled(player.isPlaying() && player.getMaximumPosition() > 0 && player.isSeekSupported());
|
|
List<FileType> fileTypes = info.getSupportedExportFileTypes();
|
|
exportButton.setEnabled(!fileTypes.isEmpty());
|
|
|
|
if (player.isPlaying()) {
|
|
songTableView.setSelectedSong(player.getPlayingSong());
|
|
}
|
|
|
|
}
|
|
|
|
// @Override
|
|
@Override
|
|
public void playerUpdated(int mode) {
|
|
|
|
final boolean stateUpdated;
|
|
final boolean positionUpdated;
|
|
final String position;
|
|
final int maxPositionValue;
|
|
final int positionValue;
|
|
final String positionText;
|
|
final boolean volumeUpdated;
|
|
final int[] channelVolumnes;
|
|
|
|
if (partControlCreated) {
|
|
stateUpdated = (mode & SoundPlayerListener.STATE) != 0;
|
|
positionUpdated = (mode & SoundPlayerListener.POSITION) != 0;
|
|
volumeUpdated = (mode & SoundPlayerListener.VOLUME) != 0;
|
|
|
|
// State dependent
|
|
maxPositionValue = player.getMaximumPosition();
|
|
|
|
// Position dependent
|
|
if ((stateUpdated || positionUpdated) && (player.isPlaying() || player.isPaused())) {
|
|
if (maxPositionValue > 0) {
|
|
positionValue = player.getPosition() % maxPositionValue; // Modulo
|
|
// for
|
|
// looping
|
|
// sounds
|
|
} else {
|
|
positionValue = player.getPosition();
|
|
}
|
|
synchronized (positionFieldFormat) {
|
|
position = positionFieldFormat.format(new Date(positionValue));
|
|
}
|
|
if (player.isPaused()) {
|
|
positionText = position + Texts.SOUND_EDITOR_PAUSED;
|
|
} else {
|
|
positionText = position;
|
|
}
|
|
|
|
} else {
|
|
positionValue = 0;
|
|
positionText = Texts.SOUND_EDITOR_STOPPED;
|
|
}
|
|
|
|
// Volume dependent
|
|
channelVolumnes = player.getChannelVolumes();
|
|
|
|
Runnable updater = new Runnable() {
|
|
// @Override
|
|
@Override
|
|
public void run() {
|
|
playerUpdatedWithValues(stateUpdated, maxPositionValue, positionUpdated, positionValue,
|
|
positionText, volumeUpdated, channelVolumnes);
|
|
}
|
|
};
|
|
// Updates to widgets must be performed in the display
|
|
// thread.
|
|
Display.getDefault().asyncExec(updater);
|
|
|
|
}
|
|
}
|
|
|
|
void playerUpdatedWithValues(final boolean stateUpdated, final int maxPositionValue, final boolean positionUpdated,
|
|
final int positionValue, final String positionText, final boolean volumeUpdated,
|
|
final int[] channelVolumnes) {
|
|
if (partControlCreated) {
|
|
if (stateUpdated) {
|
|
pauseButton.setEnabled(player.isPlaying());
|
|
stopButton.setEnabled(player.isPlaying());
|
|
positionScale.setMaximum(maxPositionValue);
|
|
positionScale.setIncrement(SoundPlayerListener.POSITION_UPDATE_INCREMENT);
|
|
positionScale.setPageIncrement(maxPositionValue > 0 ? maxPositionValue / 10 + 1 : 0);
|
|
}
|
|
|
|
if (positionUpdated) {
|
|
positionScale.setSelection(maxPositionValue > 0 ? positionValue : 0);
|
|
}
|
|
|
|
if (stateUpdated || positionUpdated) {
|
|
positionField.setValue(positionText);
|
|
positionField.getControl().pack();
|
|
}
|
|
|
|
if (volumeUpdated) {
|
|
vuMeterField.setValue(channelVolumnes);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void exportFileContentAs() {
|
|
|
|
// ASCIIfy title to obtain a valid file name
|
|
SoundInfo info = player.getInfo();
|
|
String title = info.getTitle();
|
|
StringBuilder builder = new StringBuilder();
|
|
for (int i = 0; i < title.length(); i++) {
|
|
char c = title.charAt(i);
|
|
if (Character.isLetter(c) || Character.isDigit(c) || c == '-' || c == '_') {
|
|
builder.append(c);
|
|
}
|
|
}
|
|
|
|
// Appending the module file type does unfortunately not have any effect
|
|
// on the default selected in the dialog. So we stick to the first
|
|
// selected type.
|
|
String fileName = builder.toString();
|
|
|
|
// Create the file dialog only once, so it keeps the selected folder
|
|
// when exporting multiple times.
|
|
if (exportFileDialog == null) {
|
|
exportFileDialog = new FileDialog(getSite().getShell(), SWT.SAVE);
|
|
}
|
|
exportFileDialog.setFileName(fileName);
|
|
|
|
// Get list of file type sorted by description.
|
|
List<FileType> fileTypes = player.getInfo().getSupportedExportFileTypes();
|
|
if (fileTypes.isEmpty()) {
|
|
throw new IllegalStateException("Method must not be called if there are no supported export file types.");
|
|
}
|
|
// Convert list to dialog format.
|
|
int size = fileTypes.size();
|
|
String[] extensions = new String[size];
|
|
String[] descriptions = new String[size];
|
|
for (int i = 0; i < size; i++) {
|
|
FileType fileType = fileTypes.get(i);
|
|
extensions[i] = "*" + fileType.getExtension();
|
|
descriptions[i] = fileType.getDescription() + " (" + fileType.getExtension() + ")";
|
|
}
|
|
exportFileDialog.setFilterExtensions(extensions);
|
|
exportFileDialog.setFilterNames(descriptions);
|
|
|
|
fileName = exportFileDialog.open();
|
|
if (fileName == null) {
|
|
return; // Canceled
|
|
}
|
|
|
|
// Find selected file type.
|
|
String extension = FileUtility.getFileExtension(fileName);
|
|
FileType selectedFileType = null;
|
|
for (FileType fileType : fileTypes) {
|
|
if (fileType.getExtension().equalsIgnoreCase(extension)) {
|
|
selectedFileType = fileType;
|
|
break;
|
|
}
|
|
}
|
|
if (selectedFileType == null) {
|
|
// ERROR: Cannot export sound file as '{0}'. {1}
|
|
messageManager.sendMessage(MessageIds.FORMAT, IStatus.ERROR,
|
|
TextUtility.format(Texts.MESSAGE_E506, extension), "");
|
|
return;
|
|
}
|
|
|
|
int musicAddress = info.getMusicAddress();
|
|
if (selectedFileType.isMusicAddressChangeable()) {
|
|
String initialValue = "";
|
|
if (musicAddress >= 0) {
|
|
initialValue = HexUtility.getLongValueHexString(musicAddress, 4);
|
|
}
|
|
InputDialog inputDialog = new InputDialog(mainComposite.getShell(),
|
|
TextUtility.format(Texts.MESSAGE_I507, selectedFileType.getDescription()), Texts.MESSAGE_I508,
|
|
initialValue, new IInputValidator() {
|
|
|
|
@Override
|
|
public String isValid(String newText) {
|
|
// ERROR: This is not a valid music address. Specify
|
|
// a hexadecimal value between '0000' and 'FFFF'.
|
|
try {
|
|
int value = Integer.parseInt(newText, 16);
|
|
if (value >= 0x0000 && value <= 0xffff) {
|
|
return null;
|
|
}
|
|
} catch (NumberFormatException ignore) {
|
|
|
|
}
|
|
return TextUtility.format(Texts.MESSAGE_E509);
|
|
}
|
|
|
|
});
|
|
if (inputDialog.open() != Window.OK) {
|
|
return;
|
|
}
|
|
musicAddress = Integer.parseInt(inputDialog.getValue(), 16);
|
|
|
|
}
|
|
|
|
// Perform actual export.
|
|
byte[] binary;
|
|
try {
|
|
binary = player.getExportFileContent(selectedFileType, musicAddress);
|
|
} catch (Exception ex) {
|
|
// ERROR: Cannot export sound file as '{0}'. {1}
|
|
messageManager.sendMessage(MessageIds.FORMAT, IStatus.ERROR,
|
|
TextUtility.format(Texts.MESSAGE_E506, selectedFileType.getDescription(), ex.getMessage()));
|
|
return;
|
|
}
|
|
|
|
File file = new File(fileName).getAbsoluteFile();
|
|
try {
|
|
FileUtility.writeBytes(file, binary);
|
|
} catch (CoreException ex) {
|
|
messageManager.sendMessage(MessageIds.FORMAT, ex);
|
|
return;
|
|
}
|
|
// INFO: Sound file exported as file '{0}' of type '{1}'.
|
|
messageManager.sendMessage(MessageIds.FORMAT, IStatus.INFO, Texts.MESSAGE_I505, file.getPath(),
|
|
selectedFileType.getDescription());
|
|
|
|
}
|
|
}
|