import javax.swing.Box;\r
import javax.swing.BoxLayout;\r
import javax.swing.DefaultCellEditor;\r
+import javax.swing.DefaultListSelectionModel;\r
import javax.swing.Icon;\r
import javax.swing.JButton;\r
import javax.swing.JCheckBox;\r
*/\r
class MidiEditor extends JDialog implements DropTargetListener, ActionListener {\r
public static final Insets ZERO_INSETS = new Insets(0,0,0,0);\r
- /**\r
- * プレイリストのモデル\r
- */\r
- SequenceListTableModel sequenceListTableModel;\r
+ private static final Icon deleteIcon = new ButtonIcon(ButtonIcon.X_ICON);\r
/**\r
* このMIDIエディタの仮想MIDIデバイス\r
*/\r
/**\r
* 新しいMIDIシーケンスを生成するダイアログ\r
*/\r
- NewSequenceDialog newSequenceDialog = new NewSequenceDialog(this) {{\r
- setChannels(virtualMidiDevice.getChannels());\r
- }};\r
- /**\r
- * MIDIイベント入力ダイアログ\r
- */\r
- MidiEventDialog eventDialog = new MidiEventDialog();\r
- /**\r
- * MIDIシーケンス選択状態\r
- */\r
- ListSelectionModel seqSelectionModel;\r
+ NewSequenceDialog newSequenceDialog = new NewSequenceDialog(this) {\r
+ { setChannels(virtualMidiDevice.getChannels()); }\r
+ };\r
+\r
/**\r
- * MIDIトラック選択状態\r
+ * プレイリストのモデル\r
*/\r
- private ListSelectionModel trackSelectionModel;\r
+ SequenceListTableModel sequenceListTableModel;\r
/**\r
- * MIDIイベント選択状態\r
+ * プレイリストのMIDIシーケンス選択状態\r
*/\r
- private ListSelectionModel eventSelectionModel;\r
-\r
+ ListSelectionModel seqSelectionModel = new DefaultListSelectionModel() {{\r
+ setSelectionMode(ListSelectionModel.SINGLE_SELECTION);\r
+ addListSelectionListener(new ListSelectionListener() {\r
+ @Override\r
+ public void valueChanged(ListSelectionEvent e) {\r
+ if( e.getValueIsAdjusting() ) return;\r
+ sequenceSelectionChanged();\r
+ trackSelectionModel.setSelectionInterval(0,0);\r
+ }\r
+ });\r
+ }};\r
/**\r
- * MIDIシーケンスリストテーブルビュー\r
+ * 選択されたシーケンスへジャンプするアクション\r
*/\r
- private JTable sequenceListTableView;\r
+ public Action jumpSequenceAction = new AbstractAction("Jump") {\r
+ {\r
+ putValue(\r
+ Action.SHORT_DESCRIPTION,\r
+ "Move to selected song - 選択した曲へ進む"\r
+ );\r
+ }\r
+ @Override\r
+ public void actionPerformed(ActionEvent e) {\r
+ load(seqSelectionModel.getMinSelectionIndex());\r
+ }\r
+ };\r
/**\r
- * MIDIトラックリストテーブルビュー\r
+ * シーケンスを削除するアクション\r
*/\r
- private JTable trackListTableView;\r
+ public Action deleteSequenceAction = new AbstractAction("Delete",deleteIcon) {\r
+ @Override\r
+ public void actionPerformed(ActionEvent e) {\r
+ if( midiFileChooser != null ) {\r
+ // ファイルに保存できる場合(Javaアプレットではなく、Javaアプリとして動作している場合)\r
+ MidiSequenceTableModel seqModel = sequenceListTableModel.getSequenceModel(seqSelectionModel);\r
+ if( seqModel.isModified() ) {\r
+ // ファイル未保存の変更がある場合\r
+ String confirmMessage =\r
+ "Selected MIDI sequence not saved - delete it ?\n" +\r
+ "選択したMIDIシーケンスはまだ保存されていません。削除しますか?";\r
+ if( ! confirm(confirmMessage) ) {\r
+ // ユーザに確認してNoって言われた場合\r
+ return;\r
+ }\r
+ }\r
+ }\r
+ // 削除を実行\r
+ sequenceListTableModel.removeSequence(seqSelectionModel);\r
+ }\r
+ };\r
/**\r
- * MIDIイベントリストテーブルビュー\r
+ * BASE64テキスト入力ダイアログ\r
*/\r
- private JTable eventListTableView;\r
+ Base64Dialog base64Dialog = new Base64Dialog(this);\r
/**\r
- * スクロール可能なMIDIイベントテーブルビュー\r
+ * BASE64エンコードボタン(ライブラリが見えている場合のみ有効)\r
*/\r
- private JScrollPane scrollableEventTableView;\r
+ public Action base64EncodeAction;\r
/**\r
- * 全MIDIシーケンス合計時間表示ラベル\r
+ * ファイル選択ダイアログ(アプレットでは使用不可)\r
*/\r
- private class TotalTimeLabel extends JLabel implements TableModelListener {\r
- SequenceListTableModel model;\r
- public TotalTimeLabel(SequenceListTableModel model) {\r
- (this.model = model).addTableModelListener(this);\r
- update();\r
- }\r
- private void update() {\r
- int sec = model.getTotalSeconds();\r
- String str = String.format("MIDI file playlist - Total length = %02d:%02d", sec/60, sec%60);\r
- setText(str);\r
+ private class MidiFileChooser extends JFileChooser {\r
+ {\r
+ setFileFilter(\r
+ new FileNameExtensionFilter("MIDI sequence (*.mid)", "mid")\r
+ );\r
}\r
/**\r
- * プレイリスト上でシーケンスが増減した場合、\r
- * 合計時間が変わるので表示を更新します。\r
+ * ファイルを開くアクション\r
*/\r
- @Override\r
- public void tableChanged(TableModelEvent e) {\r
- switch( e.getType() ) {\r
- case TableModelEvent.INSERT:\r
- case TableModelEvent.DELETE: update(); break;\r
- default: break;\r
+ public Action addMidiFileAction = new AbstractAction("Open") {\r
+ @Override\r
+ public void actionPerformed(ActionEvent e) {\r
+ int resp = midiFileChooser.showOpenDialog(MidiEditor.this);\r
+ if( resp == JFileChooser.APPROVE_OPTION )\r
+ addSequence(midiFileChooser.getSelectedFile());\r
}\r
- }\r
- }\r
+ };\r
+ /**\r
+ * ファイル保存アクション\r
+ */\r
+ public Action saveMidiFileAction = new AbstractAction("Save") {\r
+ @Override\r
+ public void actionPerformed(ActionEvent e) {\r
+ MidiSequenceTableModel sequenceTableModel =\r
+ sequenceListTableModel.getSequenceModel(seqSelectionModel);\r
+ String filename = sequenceTableModel.getFilename();\r
+ File midiFile;\r
+ if( filename != null && ! filename.isEmpty() ) {\r
+ midiFile = new File(filename);\r
+ midiFileChooser.setSelectedFile(midiFile);\r
+ }\r
+ int resp = midiFileChooser.showSaveDialog(MidiEditor.this);\r
+ if( resp != JFileChooser.APPROVE_OPTION ) {\r
+ return;\r
+ }\r
+ midiFile = midiFileChooser.getSelectedFile();\r
+ if( midiFile.exists() && ! confirm(\r
+ "Overwrite " + midiFile.getName() + " ?\n"\r
+ + midiFile.getName()\r
+ + " を上書きしてよろしいですか?"\r
+ ) ) {\r
+ return;\r
+ }\r
+ try ( FileOutputStream out = new FileOutputStream(midiFile) ) {\r
+ out.write(sequenceTableModel.getMIDIdata());\r
+ sequenceTableModel.setModified(false);\r
+ }\r
+ catch( IOException ex ) {\r
+ showError( ex.getMessage() );\r
+ ex.printStackTrace();\r
+ }\r
+ }\r
+ };\r
+ };\r
/**\r
- * MIDIトラック数表示ラベル\r
+ * ファイル選択ダイアログ(アプレットでは使用不可)\r
*/\r
- private JLabel tracksLabel = new JLabel("Tracks");\r
+ private MidiFileChooser midiFileChooser;\r
+\r
/**\r
- * MIDIã\82¤ã\83\99ã\83³ã\83\88æ\95°è¡¨ç¤ºã\83©ã\83\99ã\83«\r
+ * MIDIã\83\88ã\83©ã\83\83ã\82¯é\81¸æ\8a\9eç\8a¶æ\85\8b\r
*/\r
- private JLabel midiEventsLabel = new JLabel("No track selected");\r
+ private ListSelectionModel trackSelectionModel = new DefaultListSelectionModel() {{\r
+ setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);\r
+ addListSelectionListener(new ListSelectionListener() {\r
+ @Override\r
+ public void valueChanged(ListSelectionEvent e) {\r
+ if( e.getValueIsAdjusting() ) return;\r
+ MidiSequenceTableModel sequenceModel = sequenceListTableModel.getSequenceModel(seqSelectionModel);\r
+ if( sequenceModel == null || isSelectionEmpty() ) {\r
+ midiEventsLabel.setText("MIDI Events (No track selected)");\r
+ eventListTableView.setModel(new MidiTrackTableModel());\r
+ }\r
+ else {\r
+ int selIndex = getMinSelectionIndex();\r
+ MidiTrackTableModel trackModel = sequenceModel.getTrackModel(selIndex);\r
+ if( trackModel == null ) {\r
+ midiEventsLabel.setText("MIDI Events (No track selected)");\r
+ eventListTableView.setModel(new MidiTrackTableModel());\r
+ }\r
+ else {\r
+ midiEventsLabel.setText(\r
+ String.format("MIDI Events (in track No.%d)", selIndex)\r
+ );\r
+ eventListTableView.setModel(trackModel);\r
+ TableColumnModel tcm = eventListTableView.getColumnModel();\r
+ trackModel.sizeColumnWidthToFit(tcm);\r
+ tcm.getColumn(MidiTrackTableModel.Column.MESSAGE.ordinal()).setCellEditor(eventCellEditor);\r
+ }\r
+ }\r
+ updateButtonStatus();\r
+ eventSelectionModel.setSelectionInterval(0,0);\r
+ }\r
+ });\r
+ }};\r
/**\r
- * BASE64テキスト入力ダイアログ\r
+ * トラック追加アクション\r
*/\r
- Base64Dialog base64Dialog = new Base64Dialog(this);\r
+ public Action addTrackAction = new AbstractAction("New") {\r
+ @Override\r
+ public void actionPerformed(ActionEvent e) {\r
+ int index = sequenceListTableModel.getSequenceModel(seqSelectionModel).createTrack();\r
+ trackSelectionModel.setSelectionInterval(index, index);\r
+ sequenceListTableModel.fireSequenceChanged(seqSelectionModel);\r
+ }\r
+ };\r
/**\r
- * BASE64エンコードボタン(ライブラリが見えている場合のみ有効)\r
+ * MIDIトラック除去アクション\r
*/\r
- private JButton base64EncodeButton;\r
-\r
+ public Action removeTrackAction = new AbstractAction("Delete", deleteIcon) {\r
+ @Override\r
+ public void actionPerformed(ActionEvent e) {\r
+ if( ! confirm("Do you want to delete selected track ?\n選択したトラックを削除しますか?"))\r
+ return;\r
+ sequenceListTableModel.getSequenceModel(seqSelectionModel).deleteTracks(trackSelectionModel);\r
+ sequenceListTableModel.fireSequenceChanged(seqSelectionModel);\r
+ }\r
+ };\r
/**\r
- * ファイル選択ダイアログ(アプレットでは使用不可)\r
+ * MIDIトラックリストテーブルビュー\r
*/\r
- private JFileChooser fileChooser;\r
+ private JTable trackListTableView;\r
+\r
/**\r
- * MIDIã\82·ã\83¼ã\82±ã\83³ã\82¹è¿½å\8a ã\83\9cã\82¿ã\83³ï¼\88ã\83\95ã\82¡ã\82¤ã\83«é\81¸æ\8a\9eã\83\80ã\82¤ã\82¢ã\83ã\82°ã\81\8cå\88©ç\94¨ã\81§ã\81\8dã\82\8bå ´å\90\88ã\81®ã\81¿æ\9c\89å\8a¹ï¼\89\r
+ * MIDIã\82¤ã\83\99ã\83³ã\83\88é\81¸æ\8a\9eç\8a¶æ\85\8b\r
*/\r
- private JButton addMidiFileButton;\r
+ private ListSelectionModel eventSelectionModel = new DefaultListSelectionModel() {{\r
+ setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);\r
+ addListSelectionListener(new ListSelectionListener() {\r
+ @Override\r
+ public void valueChanged(ListSelectionEvent e) {\r
+ if( e.getValueIsAdjusting() ) return;\r
+ if( ! isSelectionEmpty() ) {\r
+ MidiTrackTableModel trackModel = (MidiTrackTableModel)eventListTableView.getModel();\r
+ int minIndex = getMinSelectionIndex();\r
+ if( trackModel.hasTrack() ) {\r
+ MidiEvent midiEvent = trackModel.getMidiEvent(minIndex);\r
+ MidiMessage msg = midiEvent.getMessage();\r
+ if( msg instanceof ShortMessage ) {\r
+ ShortMessage sm = (ShortMessage)msg;\r
+ int cmd = sm.getCommand();\r
+ if( cmd == 0x80 || cmd == 0x90 || cmd == 0xA0 ) {\r
+ // ノート番号を持つ場合、音を鳴らす。\r
+ MidiChannel outMidiChannels[] = virtualMidiDevice.getChannels();\r
+ int ch = sm.getChannel();\r
+ int note = sm.getData1();\r
+ int vel = sm.getData2();\r
+ outMidiChannels[ch].noteOn(note, vel);\r
+ outMidiChannels[ch].noteOff(note, vel);\r
+ }\r
+ }\r
+ }\r
+ if( pairNoteCheckbox.isSelected() ) {\r
+ int maxIndex = getMaxSelectionIndex();\r
+ int partnerIndex;\r
+ for( int i=minIndex; i<=maxIndex; i++ )\r
+ if(\r
+ isSelectedIndex(i) &&\r
+ (partnerIndex = trackModel.getIndexOfPartnerFor(i)) >= 0 &&\r
+ ! isSelectedIndex(partnerIndex)\r
+ ) addSelectionInterval(partnerIndex, partnerIndex);\r
+ }\r
+ }\r
+ updateButtonStatus();\r
+ }\r
+ });\r
+ }};\r
/**\r
- * MIDIã\83\95ã\82¡ã\82¤ã\83«ä¿\9då\98ã\83\9cã\82¿ã\83³ï¼\88ã\83\95ã\82¡ã\82¤ã\83«é\81¸æ\8a\9eã\83\80ã\82¤ã\82¢ã\83ã\82°ã\81\8cå\88©ç\94¨ã\81§ã\81\8dã\82\8bå ´å\90\88ã\81®ã\81¿æ\9c\89å\8a¹ï¼\89\r
+ * MIDIã\82¤ã\83\99ã\83³ã\83\88ã\83ªã\82¹ã\83\88ã\83\86ã\83¼ã\83\96ã\83«ã\83\93ã\83¥ã\83¼\r
*/\r
- private JButton saveMidiFileButton;\r
-\r
+ private JTable eventListTableView;\r
/**\r
- * MIDIシーケンス削除ボタン\r
+ * スクロール可能なMIDIイベントテーブルビュー\r
*/\r
- private JButton deleteSequenceButton;\r
+ private JScrollPane scrollableEventTableView;\r
/**\r
- * MIDIã\82·ã\83¼ã\82±ã\83³ã\82¹ã\82¸ã\83£ã\83³ã\83\97ã\83\9cã\82¿ã\83³\r
+ * MIDIã\83\88ã\83©ã\83\83ã\82¯æ\95°è¡¨ç¤ºã\83©ã\83\99ã\83«\r
*/\r
- private JButton jumpSequenceButton = new JButton("Jump") {{\r
- setToolTipText("Move to selected song - 選択した曲へ進む");\r
- setMargin(ZERO_INSETS);\r
- addActionListener(\r
- new ActionListener() {\r
- public void actionPerformed(ActionEvent e) {\r
- load(seqSelectionModel.getMinSelectionIndex());\r
- }\r
- }\r
- );\r
- }};\r
+ private JLabel tracksLabel = new JLabel("Tracks");\r
/**\r
- * MIDIã\83\88ã\83©ã\83\83ã\82¯è¿½å\8a ã\83\9cã\82¿ã\83³\r
+ * MIDIã\82¤ã\83\99ã\83³ã\83\88æ\95°è¡¨ç¤ºã\83©ã\83\99ã\83«\r
*/\r
- private JButton addTrackButton = new JButton("New") {{\r
- setMargin(ZERO_INSETS);\r
- addActionListener(\r
- new ActionListener() {\r
- public void actionPerformed(ActionEvent e) {\r
- int index = sequenceListTableModel.getSequenceModel(seqSelectionModel).createTrack();\r
- trackSelectionModel.setSelectionInterval(index, index);\r
- sequenceListTableModel.fireSequenceChanged(seqSelectionModel);\r
- }\r
- }\r
- );\r
- }};;\r
+ private JLabel midiEventsLabel = new JLabel("No track selected");\r
/**\r
- * MIDIã\83\88ã\83©ã\83\83ã\82¯é\99¤å\8e»ã\83\9cã\82¿ã\83³\r
+ * MIDIã\82¤ã\83\99ã\83³ã\83\88å\85¥å\8a\9bã\83\80ã\82¤ã\82¢ã\83ã\82°\r
*/\r
- private JButton removeTrackButton;\r
+ MidiEventDialog eventDialog = new MidiEventDialog();\r
/**\r
* MIDIイベント除去ボタン\r
*/\r
}\r
}\r
/**\r
- * キャンセルするアクション\r
+ * ã\82¤ã\83\99ã\83³ã\83\88å\85¥å\8a\9bã\82\92ã\82ã\83£ã\83³ã\82»ã\83«ã\81\99ã\82\8bã\82¢ã\82¯ã\82·ã\83§ã\83³\r
*/\r
Action cancelAction = new AbstractAction() {\r
{ putValue(NAME,"Cancel"); }\r
}\r
\r
/**\r
- * MIDIシーケンサモデル\r
- */\r
- private MidiSequencerModel sequencerModel;\r
- /**\r
- * 曲の先頭または前の曲へ戻るアクション\r
- */\r
- public Action moveToTopAction = new AbstractAction() {\r
- {\r
- putValue( SHORT_DESCRIPTION,\r
- "Move to top or previous song - 曲の先頭または前の曲へ戻る"\r
- );\r
- putValue( LARGE_ICON_KEY, new ButtonIcon(ButtonIcon.TOP_ICON) );\r
- }\r
- public void actionPerformed(ActionEvent event) {\r
- if( sequencerModel.getSequencer().getTickPosition() <= 40 )\r
- loadNext(-1);\r
- sequencerModel.setValue(0);\r
- }\r
- };\r
- /**\r
- * 次の曲へ進むアクション\r
- */\r
- public Action moveToBottomAction = new AbstractAction() {\r
- {\r
- putValue( SHORT_DESCRIPTION, "Move to next song - 次の曲へ進む" );\r
- putValue( LARGE_ICON_KEY, new ButtonIcon(ButtonIcon.BOTTOM_ICON) );\r
- }\r
- public void actionPerformed(ActionEvent event) {\r
- if(loadNext(1)) sequencerModel.setValue(0);\r
- }\r
- };\r
-\r
- /**\r
* MIDIイベントセルエディタ\r
*/\r
private MidiEventCellEditor eventCellEditor = new MidiEventCellEditor();\r
);\r
}};\r
/**\r
- * 再生/一時停止ボタン\r
- */\r
- private JToggleButton playPauseButton;\r
- /**\r
* 新しい {@link MidiEditor} を構築します。\r
* @param deviceModelList MIDIデバイスモデルリスト\r
*/\r
public MidiEditor(MidiSequencerModel sequencerModel) {\r
- MidiSequenceTableModel emptyTrackTableModel = new MidiSequenceTableModel(\r
- sequenceListTableModel = new SequenceListTableModel(\r
- this.sequencerModel = sequencerModel\r
- )\r
- );\r
setTitle("MIDI Editor/Playlist - MIDI Chord Helper");\r
setBounds( 150, 200, 850, 500 );\r
setLayout(new FlowLayout());\r
new DropTarget(this, DnDConstants.ACTION_COPY_OR_MOVE, this, true);\r
- playPauseButton = new JToggleButton(sequencerModel.startStopAction);\r
- sequenceListTableView = new JTable(sequenceListTableModel);\r
- trackListTableView = new JTable(emptyTrackTableModel);\r
- eventListTableView = new JTable(new MidiTrackTableModel());\r
- //\r
- sequenceListTableModel.sizeColumnWidthToFit(sequenceListTableView);\r
- emptyTrackTableModel.sizeColumnWidthToFit(trackListTableView.getColumnModel());\r
- //\r
- seqSelectionModel = sequenceListTableView.getSelectionModel();\r
- seqSelectionModel.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );\r
- seqSelectionModel.addListSelectionListener(new ListSelectionListener() {\r
- @Override\r
- public void valueChanged(ListSelectionEvent e) {\r
- if( e.getValueIsAdjusting() ) return;\r
- sequenceSelectionChanged();\r
- trackSelectionModel.setSelectionInterval(0,0);\r
- }\r
- });\r
- //\r
- trackSelectionModel = trackListTableView.getSelectionModel();\r
- trackSelectionModel.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);\r
- trackSelectionModel.addListSelectionListener(new ListSelectionListener() {\r
- @Override\r
- public void valueChanged(ListSelectionEvent e) {\r
- if( e.getValueIsAdjusting() ) return;\r
- MidiSequenceTableModel sequenceModel = sequenceListTableModel.getSequenceModel(seqSelectionModel);\r
- if( sequenceModel == null || trackSelectionModel.isSelectionEmpty() ) {\r
- midiEventsLabel.setText("MIDI Events (No track selected)");\r
- eventListTableView.setModel(new MidiTrackTableModel());\r
- }\r
- else {\r
- int selIndex = trackSelectionModel.getMinSelectionIndex();\r
- MidiTrackTableModel trackModel = sequenceModel.getTrackModel(selIndex);\r
- if( trackModel == null ) {\r
- midiEventsLabel.setText("MIDI Events (No track selected)");\r
- eventListTableView.setModel(new MidiTrackTableModel());\r
- }\r
- else {\r
- midiEventsLabel.setText(\r
- String.format("MIDI Events (in track No.%d)", selIndex)\r
- );\r
- eventListTableView.setModel(trackModel);\r
- TableColumnModel tcm = eventListTableView.getColumnModel();\r
- trackModel.sizeColumnWidthToFit(tcm);\r
- tcm.getColumn(MidiTrackTableModel.Column.MESSAGE.ordinal()).setCellEditor(eventCellEditor);\r
- }\r
- }\r
- updateButtonStatus();\r
- eventSelectionModel.setSelectionInterval(0,0);\r
- }\r
- });\r
- eventSelectionModel = eventListTableView.getSelectionModel();\r
- eventSelectionModel.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);\r
- eventSelectionModel.addListSelectionListener(new ListSelectionListener() {\r
- @Override\r
- public void valueChanged(ListSelectionEvent e) {\r
- if( e.getValueIsAdjusting() ) return;\r
- if( ! eventSelectionModel.isSelectionEmpty() ) {\r
- MidiTrackTableModel trackModel = (MidiTrackTableModel)eventListTableView.getModel();\r
- int minIndex = eventSelectionModel.getMinSelectionIndex();\r
- if( trackModel.hasTrack() ) {\r
- MidiEvent midiEvent = trackModel.getMidiEvent(minIndex);\r
- MidiMessage msg = midiEvent.getMessage();\r
- if( msg instanceof ShortMessage ) {\r
- ShortMessage sm = (ShortMessage)msg;\r
- int cmd = sm.getCommand();\r
- if( cmd == 0x80 || cmd == 0x90 || cmd == 0xA0 ) {\r
- // ノート番号を持つ場合、音を鳴らす。\r
- MidiChannel outMidiChannels[] = virtualMidiDevice.getChannels();\r
- int ch = sm.getChannel();\r
- int note = sm.getData1();\r
- int vel = sm.getData2();\r
- outMidiChannels[ch].noteOn(note, vel);\r
- outMidiChannels[ch].noteOff(note, vel);\r
- }\r
- }\r
- }\r
- if( pairNoteCheckbox.isSelected() ) {\r
- int maxIndex = eventSelectionModel.getMaxSelectionIndex();\r
- int partnerIndex;\r
- for( int i=minIndex; i<=maxIndex; i++ )\r
- if(\r
- eventSelectionModel.isSelectedIndex(i) &&\r
- (partnerIndex = trackModel.getIndexOfPartnerFor(i)) >= 0 &&\r
- ! eventSelectionModel.isSelectedIndex(partnerIndex)\r
- ) eventSelectionModel.addSelectionInterval(partnerIndex, partnerIndex);\r
- }\r
- }\r
- updateButtonStatus();\r
- }\r
- });\r
+ sequenceListTableModel = new SequenceListTableModel(sequencerModel);\r
+ eventListTableView = new JTable(\r
+ new MidiTrackTableModel(), null, eventSelectionModel\r
+ );\r
try {\r
- fileChooser = new JFileChooser() {{\r
- setFileFilter(new FileNameExtensionFilter(\r
- "MIDI sequence (*.mid)", "mid"\r
- ));\r
- }};\r
+ midiFileChooser = new MidiFileChooser();\r
}\r
catch( ExceptionInInitializerError|NoClassDefFoundError|AccessControlException e ) {\r
// アプレットの場合、Webクライアントマシンのローカルファイルには\r
// アクセスできないので、ファイル選択ダイアログは使用不可。\r
- fileChooser = null;\r
- }\r
- if( fileChooser != null ) {\r
- addMidiFileButton = new JButton("Open") {{\r
- setMargin(ZERO_INSETS);\r
- addActionListener(\r
- new ActionListener() {\r
- public void actionPerformed(ActionEvent e) {\r
- int resp = fileChooser.showOpenDialog(MidiEditor.this);\r
- if( resp == JFileChooser.APPROVE_OPTION )\r
- addSequence(fileChooser.getSelectedFile());\r
- }\r
- }\r
- );\r
- }};\r
- saveMidiFileButton = new JButton("Save") {{\r
- setMargin(ZERO_INSETS);\r
- addActionListener(new ActionListener() {\r
- @Override\r
- public void actionPerformed(ActionEvent e) {\r
- MidiSequenceTableModel sequenceTableModel =\r
- sequenceListTableModel.getSequenceModel(seqSelectionModel);\r
- String filename = sequenceTableModel.getFilename();\r
- File midiFile;\r
- if( filename != null && ! filename.isEmpty() ) {\r
- midiFile = new File(filename);\r
- fileChooser.setSelectedFile(midiFile);\r
- }\r
- int resp = fileChooser.showSaveDialog(MidiEditor.this);\r
- if( resp != JFileChooser.APPROVE_OPTION ) {\r
- return;\r
- }\r
- midiFile = fileChooser.getSelectedFile();\r
- if( midiFile.exists() && ! confirm(\r
- "Overwrite " + midiFile.getName() + " ?\n"\r
- + midiFile.getName()\r
- + " を上書きしてよろしいですか?"\r
- ) ) {\r
- return;\r
- }\r
- try ( FileOutputStream out = new FileOutputStream(midiFile) ) {\r
- out.write(sequenceTableModel.getMIDIdata());\r
- sequenceTableModel.setModified(false);\r
- }\r
- catch( IOException ex ) {\r
- showError( ex.getMessage() );\r
- ex.printStackTrace();\r
- }\r
- }\r
- });\r
- }};\r
+ midiFileChooser = null;\r
}\r
- Icon deleteIcon = new ButtonIcon(ButtonIcon.X_ICON);\r
- deleteSequenceButton = new JButton("Delete", deleteIcon) {{\r
- setMargin(ZERO_INSETS);\r
- addActionListener(new ActionListener() {\r
- public void actionPerformed(ActionEvent e) {\r
- if( saveMidiFileButton != null ) {\r
- // ファイルに保存できる場合(Javaアプレットではなく、Javaアプリとして動作している場合)\r
- MidiSequenceTableModel seqModel = sequenceListTableModel.getSequenceModel(seqSelectionModel);\r
- if( seqModel.isModified() ) {\r
- // ファイル未保存の変更がある場合\r
- String confirmMessage =\r
- "Selected MIDI sequence not saved - delete it ?\n" +\r
- "選択したMIDIシーケンスは保存されていませんが、削除しますか?";\r
- if( ! confirm(confirmMessage) ) {\r
- // ユーザに確認してNoって言われた場合\r
- return;\r
- }\r
- }\r
- }\r
- // 削除を実行\r
- sequenceListTableModel.removeSequence(seqSelectionModel);\r
- }\r
- });\r
- }};\r
JPanel playlistPanel = new JPanel() {{\r
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));\r
- add(new JScrollPane(sequenceListTableView));\r
+ add(new JScrollPane(\r
+ new JTable(sequenceListTableModel, null, seqSelectionModel) {{\r
+ sequenceListTableModel.sizeColumnWidthToFit(this);\r
+ }}\r
+ ));\r
add(Box.createRigidArea(new Dimension(0, 10)));\r
add(new JPanel() {{\r
setLayout( new BoxLayout(this, BoxLayout.LINE_AXIS ));\r
- add(new TotalTimeLabel(sequenceListTableModel));\r
+ add(new JLabel() {\r
+ private void update() {\r
+ int sec = sequenceListTableModel.getTotalSeconds();\r
+ String str = String.format(\r
+ "MIDI file playlist - Total length = %02d:%02d",\r
+ sec/60, sec%60\r
+ );\r
+ setText(str);\r
+ }\r
+ {\r
+ sequenceListTableModel.addTableModelListener(\r
+ new TableModelListener() {\r
+ /**\r
+ * プレイリスト上でシーケンスが増減した場合、\r
+ * 合計時間が変わるので表示を更新します。\r
+ */\r
+ @Override\r
+ public void tableChanged(TableModelEvent e) {\r
+ switch( e.getType() ) {\r
+ case TableModelEvent.INSERT:\r
+ case TableModelEvent.DELETE: update(); break;\r
+ default: break;\r
+ }\r
+ }\r
+ }\r
+ );\r
+ update();\r
+ }\r
+ });\r
add(Box.createRigidArea(new Dimension(10, 0)));\r
add(new JButton("New") {{\r
setToolTipText("Generate new song - 新しい曲を生成");\r
}\r
);\r
}});\r
- if( addMidiFileButton != null ) {\r
+ if( midiFileChooser != null ) {\r
add( Box.createRigidArea(new Dimension(5, 0)) );\r
- add( addMidiFileButton );\r
+ add(new JButton(midiFileChooser.addMidiFileAction) {{\r
+ setMargin(ZERO_INSETS);\r
+ }});\r
}\r
+ add(Box.createRigidArea(new Dimension(5, 0)));\r
+ add(new JButton(sequenceListTableModel.moveToTopAction) {{\r
+ setMargin(ZERO_INSETS);\r
+ }});\r
+ add(Box.createRigidArea(new Dimension(5, 0)));\r
+ add(new JToggleButton(\r
+ sequenceListTableModel.sequencerModel.startStopAction\r
+ ));\r
+ add(Box.createRigidArea(new Dimension(5, 0)));\r
+ add(new JButton(sequenceListTableModel.moveToBottomAction) {{\r
+ setMargin(ZERO_INSETS);\r
+ }});\r
add( Box.createRigidArea(new Dimension(5, 0)) );\r
- add( new JButton(moveToTopAction) {{setMargin(ZERO_INSETS);}} );\r
- add( Box.createRigidArea(new Dimension(5, 0)) );\r
- add( playPauseButton );\r
- add( Box.createRigidArea(new Dimension(5, 0)) );\r
- add( new JButton(moveToBottomAction) {{setMargin(ZERO_INSETS);}} );\r
- add( Box.createRigidArea(new Dimension(5, 0)) );\r
- add( jumpSequenceButton );\r
- if( saveMidiFileButton != null ) {\r
- add( Box.createRigidArea(new Dimension(5, 0)) );\r
- add( saveMidiFileButton );\r
+ add(new JButton(jumpSequenceAction){{\r
+ setMargin(ZERO_INSETS);\r
+ }});\r
+ if( midiFileChooser != null ) {\r
+ add(Box.createRigidArea(new Dimension(5, 0)));\r
+ add(new JButton(midiFileChooser.saveMidiFileAction) {{\r
+ setMargin(ZERO_INSETS);\r
+ }});\r
}\r
if( base64Dialog.isBase64Available() ) {\r
- add( Box.createRigidArea(new Dimension(5, 0)) );\r
- add( base64EncodeButton = new JButton("Base64 Encode") {{\r
+ base64EncodeAction = new AbstractAction("Base64 Encode") {\r
+ @Override\r
+ public void actionPerformed(ActionEvent e) {\r
+ MidiSequenceTableModel mstm = sequenceListTableModel.getSequenceModel(seqSelectionModel);\r
+ base64Dialog.setMIDIData(mstm.getMIDIdata(), mstm.getFilename());\r
+ base64Dialog.setVisible(true);\r
+ }\r
+ };\r
+ add(Box.createRigidArea(new Dimension(5, 0)));\r
+ add(new JButton(base64EncodeAction) {{\r
setMargin(ZERO_INSETS);\r
- addActionListener(\r
- new ActionListener() {\r
- public void actionPerformed(ActionEvent e) {\r
- MidiSequenceTableModel mstm = sequenceListTableModel.getSequenceModel(seqSelectionModel);\r
- base64Dialog.setMIDIData(mstm.getMIDIdata(), mstm.getFilename());\r
- base64Dialog.setVisible(true);\r
- }\r
- }\r
- );\r
}});\r
}\r
add( Box.createRigidArea(new Dimension(5, 0)) );\r
- add( deleteSequenceButton );\r
+ add(new JButton(deleteSequenceAction) {{\r
+ setMargin(ZERO_INSETS);\r
+ }});\r
add( Box.createRigidArea(new Dimension(5, 0)) );\r
- add( new SequencerSpeedSlider(\r
- MidiEditor.this.sequencerModel.speedSliderModel)\r
- );\r
+ add(new SequencerSpeedSlider(\r
+ sequenceListTableModel.sequencerModel.speedSliderModel\r
+ ));\r
}});\r
add( Box.createRigidArea(new Dimension(0, 10)) );\r
}};\r
- removeTrackButton = new JButton("Delete", deleteIcon) {{\r
- setMargin(ZERO_INSETS);\r
- addActionListener(\r
- new ActionListener() {\r
- public void actionPerformed(ActionEvent e) {\r
- if( ! confirm("Do you want to delete selected track ?\n選択したトラックを削除しますか?"))\r
- return;\r
- sequenceListTableModel.getSequenceModel(seqSelectionModel).deleteTracks(trackSelectionModel);\r
- sequenceListTableModel.fireSequenceChanged(seqSelectionModel);\r
- }\r
- }\r
- );\r
- }};\r
JPanel trackListPanel = new JPanel() {{\r
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));\r
add(tracksLabel);\r
add(Box.createRigidArea(new Dimension(0, 5)));\r
- add(new JScrollPane(trackListTableView));\r
+ add(new JScrollPane(\r
+ trackListTableView = new JTable(\r
+ new MidiSequenceTableModel(sequenceListTableModel),\r
+ null,\r
+ trackSelectionModel\r
+ ) {{\r
+ ((MidiSequenceTableModel)getModel()).sizeColumnWidthToFit(getColumnModel());\r
+ }}\r
+ ));\r
add(Box.createRigidArea(new Dimension(0, 5)));\r
add(new JPanel() {{\r
- add(addTrackButton);\r
- add(removeTrackButton);\r
+ add(new JButton(addTrackAction) {{\r
+ setMargin(ZERO_INSETS);\r
+ }});\r
+ add(new JButton(removeTrackAction) {{\r
+ setMargin(ZERO_INSETS);\r
+ }});\r
}});\r
}};\r
removeEventButton = new JButton("Delete", deleteIcon) {{\r
public void sequenceSelectionChanged() {\r
MidiSequenceTableModel sequenceTableModel = sequenceListTableModel.getSequenceModel(seqSelectionModel);\r
boolean loaded = (sequenceTableModel != null);\r
- if(saveMidiFileButton != null) saveMidiFileButton.setEnabled(loaded);\r
- if(base64EncodeButton != null) base64EncodeButton.setEnabled(loaded);\r
- deleteSequenceButton.setEnabled(loaded);\r
- jumpSequenceButton.setEnabled(loaded);\r
- addTrackButton.setEnabled(loaded);\r
+ if(midiFileChooser != null) midiFileChooser.saveMidiFileAction.setEnabled(loaded);\r
+ if(base64EncodeAction != null) base64EncodeAction.setEnabled(loaded);\r
+ deleteSequenceAction.setEnabled(loaded);\r
+ jumpSequenceAction.setEnabled(loaded);\r
+ addTrackAction.setEnabled(loaded);\r
if(loaded) {\r
int selectedIndex = seqSelectionModel.getMinSelectionIndex();\r
trackListTableView.setModel(sequenceTableModel);\r
sequenceListTableModel.getSequenceModel(seqSelectionModel) != null &&\r
sequenceListTableModel.getSequenceModel(seqSelectionModel).getRowCount() > 0\r
);\r
- removeTrackButton.setEnabled(isTrackSelected);\r
+ removeTrackAction.setEnabled(isTrackSelected);\r
TableModel tm = eventListTableView.getModel();\r
if( ! (tm instanceof MidiTrackTableModel) )\r
return;\r
MidiTrackTableModel trackTableModel = (MidiTrackTableModel)tm;\r
- jumpSequenceButton.setEnabled(\r
+ jumpSequenceAction.setEnabled(\r
trackTableModel != null && trackTableModel.getRowCount() > 0\r
);\r
boolean isEventSelected = (\r
);\r
}\r
public String getMIDIdataBase64() {\r
- base64Dialog.setMIDIData(sequencerModel.getSequenceTableModel().getMIDIdata());\r
+ base64Dialog.setMIDIData(\r
+ sequenceListTableModel.sequencerModel.getSequenceTableModel().getMIDIdata()\r
+ );\r
return base64Dialog.getBase64Data();\r
}\r
/**\r
*/\r
public int addSequenceAndPlay(Sequence sequence) {\r
int lastIndex = sequenceListTableModel.addSequence(sequence,"");\r
- if( ! sequencerModel.getSequencer().isRunning() ) {\r
+ if( ! sequenceListTableModel.sequencerModel.getSequencer().isRunning() ) {\r
load(lastIndex);\r
- sequencerModel.start();\r
+ sequenceListTableModel.sequencerModel.start();\r
}\r
return lastIndex;\r
}\r
if( seq == null ) return -1;\r
return sequenceListTableModel.addSequence(seq, filename);\r
}\r
+\r
/**\r
* 指定のインデックス位置にあるMIDIシーケンスをシーケンサーにロードします。\r
* @param index MIDIシーケンスのインデックス(先頭が 0)\r
if( firstIndex == -1 )\r
firstIndex = lastIndex;\r
}\r
- if(sequencerModel.getSequencer().isRunning()) {\r
+ if(sequenceListTableModel.sequencerModel.getSequencer().isRunning()) {\r
setVisible(true);\r
}\r
else if( firstIndex >= 0 ) {\r
load(firstIndex);\r
- sequencerModel.start();\r
+ sequenceListTableModel.sequencerModel.start();\r
}\r
}\r
/**\r
}\r
}\r
/**\r
- * MIDIã\82·ã\83¼ã\82±ã\83³ã\82µã\83¼ã\83¢ã\83\87ã\83«\r
+ * MIDIシーケンサモデル\r
*/\r
- protected MidiSequencerModel sequencerModel;\r
+ MidiSequencerModel sequencerModel;\r
+ /**\r
+ * 曲の先頭または前の曲へ戻るアクション\r
+ */\r
+ public Action moveToTopAction = new AbstractAction() {\r
+ {\r
+ putValue( SHORT_DESCRIPTION,\r
+ "Move to top or previous song - 曲の先頭または前の曲へ戻る"\r
+ );\r
+ putValue( LARGE_ICON_KEY, new ButtonIcon(ButtonIcon.TOP_ICON) );\r
+ }\r
+ public void actionPerformed(ActionEvent event) {\r
+ if( sequencerModel.getSequencer().getTickPosition() <= 40 )\r
+ loadNext(-1);\r
+ sequencerModel.setValue(0);\r
+ }\r
+ };\r
+ /**\r
+ * 次の曲へ進むアクション\r
+ */\r
+ public Action moveToBottomAction = new AbstractAction() {\r
+ {\r
+ putValue( SHORT_DESCRIPTION, "Move to next song - 次の曲へ進む" );\r
+ putValue( LARGE_ICON_KEY, new ButtonIcon(ButtonIcon.BOTTOM_ICON) );\r
+ }\r
+ public void actionPerformed(ActionEvent event) {\r
+ if(loadNext(1)) sequencerModel.setValue(0);\r
+ }\r
+ };\r
/**\r
* 新しいプレイリストのテーブルモデルを構築します。\r
- * @param deviceManager MIDIデバイスマネージャ\r
+ * @param sequencerModel MIDIシーケンサーモデル\r
*/\r
public SequenceListTableModel(MidiSequencerModel sequencerModel) {\r
(this.sequencerModel = sequencerModel).addChangeListener(this);\r
}\r
+ /**\r
+ * シーケンサーの秒位置\r
+ */\r
private int secondPosition = 0;\r
/**\r
- * 再生中のシーケンサの秒位置が変わったときに表示を更新します。\r
+ * å\86\8dç\94\9fä¸ã\81®ã\82·ã\83¼ã\82±ã\83³ã\82µã\83¼ã\81®ç§\92ä½\8dç½®ã\81\8cå¤\89ã\82\8fã\81£ã\81\9fã\81¨ã\81\8dã\81«è¡¨ç¤ºã\82\92æ\9b´æ\96°ã\81\97ã\81¾ã\81\99ã\80\82\r
*/\r
@Override\r
public void stateChanged(ChangeEvent e) {\r