import javax.swing.event.TableModelListener;\r
import javax.swing.filechooser.FileNameExtensionFilter;\r
import javax.swing.table.AbstractTableModel;\r
+import javax.swing.table.DefaultTableColumnModel;\r
import javax.swing.table.TableCellEditor;\r
+import javax.swing.table.TableCellRenderer;\r
import javax.swing.table.TableColumn;\r
import javax.swing.table.TableColumnModel;\r
import javax.swing.table.TableModel;\r
}\r
};\r
/**\r
- * 新しいMIDIシーケンスを生成するダイアログ\r
+ * {@inheritDoc}\r
+ * <p>すでに表示されていた場合に手前に表示する点を除き、\r
+ * スーパークラスと同じです。\r
+ * </p>\r
*/\r
- NewSequenceDialog newSequenceDialog = new NewSequenceDialog(this) {\r
- { setChannels(virtualMidiDevice.getChannels()); }\r
- };\r
+ @Override\r
+ public void setVisible(boolean isToVisible) {\r
+ if( isToVisible && isVisible() ) {\r
+ toFront();\r
+ return;\r
+ }\r
+ super.setVisible(isToVisible);\r
+ }\r
+ /**\r
+ * {@inheritDoc}\r
+ * <p>このダイアログを表示するアクションを実行します。\r
+ * </p>\r
+ */\r
+ @Override\r
+ public void actionPerformed(ActionEvent e) {\r
+ setVisible(true);\r
+ }\r
\r
/**\r
- * プレイリストのモデル\r
+ * ã\83\97ã\83¬ã\82¤ã\83ªã\82¹ã\83\88ã\81®ã\83\87ã\83¼ã\82¿ã\83¢ã\83\87ã\83«\r
*/\r
SequenceListTableModel sequenceListTableModel;\r
/**\r
- * プレイリストのMIDIシーケンス選択状態\r
+ * 新しいMIDIシーケンスを生成するダイアログ\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
+ NewSequenceDialog newSequenceDialog = new NewSequenceDialog(this) {\r
+ { setChannels(virtualMidiDevice.getChannels()); }\r
+ };\r
/**\r
- * 選択されたシーケンスへジャンプするアクション\r
+ * 新しいMIDIシーケンスを生成するアクション\r
*/\r
- public Action jumpSequenceAction = new AbstractAction("Jump") {\r
+ public Action generateNewSongAction = new AbstractAction("New") {\r
{\r
putValue(\r
Action.SHORT_DESCRIPTION,\r
- "Move to selected song - 選択した曲へ進む"\r
+ "Generate new song - 新しい曲を生成"\r
);\r
}\r
@Override\r
public void actionPerformed(ActionEvent e) {\r
- load(seqSelectionModel.getMinSelectionIndex());\r
+ newSequenceDialog.setVisible(true);\r
+ }\r
+ };\r
+ /**\r
+ * 選択されたシーケンスへジャンプするアクション\r
+ */\r
+ public Action jumpSequenceAction = new AbstractAction("Jump") {\r
+ {\r
+ putValue(Action.SHORT_DESCRIPTION, "Move to selected song - 選択した曲へ進む");\r
+ }\r
+ @Override\r
+ public void actionPerformed(ActionEvent e) {\r
+ sequenceListTableModel.loadToSequencer(sequenceListSelectionModel.getMinSelectionIndex());\r
}\r
};\r
/**\r
public void actionPerformed(ActionEvent e) {\r
if( midiFileChooser != null ) {\r
// ファイルに保存できる場合(Javaアプレットではなく、Javaアプリとして動作している場合)\r
- SequenceTrackListTableModel seqModel = sequenceListTableModel.getSequenceModel(seqSelectionModel);\r
+ SequenceTrackListTableModel seqModel = sequenceListTableModel.getSequenceModel(sequenceListSelectionModel);\r
if( seqModel.isModified() ) {\r
// ファイル未保存の変更がある場合\r
String confirmMessage =\r
}\r
}\r
// 削除を実行\r
- sequenceListTableModel.removeSequence(seqSelectionModel);\r
+ sequenceListTableModel.removeSequence(sequenceListSelectionModel);\r
}\r
};\r
/**\r
/**\r
* BASE64エンコードボタン(ライブラリが見えている場合のみ有効)\r
*/\r
- public Action base64EncodeAction;\r
+ private Action base64EncodeAction;\r
+ /**\r
+ * プレイリストのMIDIシーケンス選択状態\r
+ */\r
+ ListSelectionModel sequenceListSelectionModel = new DefaultListSelectionModel() {\r
+ {\r
+ setSelectionMode(ListSelectionModel.SINGLE_SELECTION);\r
+ addListSelectionListener(new ListSelectionListener() {\r
+ @Override\r
+ public void valueChanged(ListSelectionEvent e) {\r
+ if( e.getValueIsAdjusting() )\r
+ return;\r
+ updateButtonStatus();\r
+ updateEnabled();\r
+ }\r
+ });\r
+ if( base64Dialog.isBase64Available() ) {\r
+ base64EncodeAction = new AbstractAction("Base64 Encode") {\r
+ @Override\r
+ public void actionPerformed(ActionEvent e) {\r
+ SequenceTrackListTableModel mstm = sequenceListTableModel.getSequenceModel(sequenceListSelectionModel);\r
+ base64Dialog.setMIDIData(mstm.getMIDIdata(), mstm.getFilename());\r
+ base64Dialog.setVisible(true);\r
+ }\r
+ };\r
+ }\r
+ updateEnabled();\r
+ }\r
+ private void updateEnabled() {\r
+ int selIndex = getMinSelectionIndex();\r
+ boolean isSelected = (selIndex >= 0);\r
+ if(base64EncodeAction != null)\r
+ base64EncodeAction.setEnabled(isSelected);\r
+ deleteSequenceAction.setEnabled(isSelected);\r
+ jumpSequenceAction.setEnabled(isSelected);\r
+ }\r
+ };\r
+ /**\r
+ * プレイリストビュー\r
+ */\r
+ JTable sequenceListTableView;\r
/**\r
* ファイル選択ダイアログ(アプレットでは使用不可)\r
*/\r
/**\r
* ファイル選択ダイアログ(アプレットでは使用不可)\r
*/\r
- private class MidiFileChooser extends JFileChooser {\r
- {\r
- setFileFilter(\r
- new FileNameExtensionFilter("MIDI sequence (*.mid)", "mid")\r
- );\r
- }\r
- /**\r
- * ファイルを開くアクション\r
- */\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
+ private class MidiFileChooser extends JFileChooser implements ListSelectionListener {\r
/**\r
* ファイル保存アクション\r
*/\r
@Override\r
public void actionPerformed(ActionEvent e) {\r
SequenceTrackListTableModel sequenceTableModel =\r
- sequenceListTableModel.getSequenceModel(seqSelectionModel);\r
+ sequenceListTableModel.getSequenceModel(sequenceListSelectionModel);\r
String filename = sequenceTableModel.getFilename();\r
File midiFile;\r
if( filename != null && ! filename.isEmpty() ) {\r
midiFile = new File(filename);\r
- midiFileChooser.setSelectedFile(midiFile);\r
+ setSelectedFile(midiFile);\r
}\r
- int resp = midiFileChooser.showSaveDialog(MidiEditor.this);\r
+ int resp = showSaveDialog(MidiEditor.this);\r
if( resp != JFileChooser.APPROVE_OPTION ) {\r
return;\r
}\r
- midiFile = midiFileChooser.getSelectedFile();\r
+ midiFile = getSelectedFile();\r
if( midiFile.exists() && ! confirm(\r
"Overwrite " + midiFile.getName() + " ?\n"\r
+ midiFile.getName()\r
}\r
}\r
};\r
+ private void updateEnabled() {\r
+ boolean en = (sequenceListSelectionModel.getMinSelectionIndex() >= 0);\r
+ saveMidiFileAction.setEnabled(en);\r
+ }\r
+ {\r
+ setFileFilter(new FileNameExtensionFilter("MIDI sequence (*.mid)", "mid"));\r
+ sequenceListSelectionModel.addListSelectionListener(this);\r
+ updateEnabled();\r
+ }\r
+ @Override\r
+ public void valueChanged(ListSelectionEvent e) {\r
+ if( e.getValueIsAdjusting() )\r
+ return;\r
+ updateEnabled();\r
+ }\r
+ /**\r
+ * ファイルを開くアクション\r
+ */\r
+ public Action addMidiFileAction = new AbstractAction("Open") {\r
+ @Override\r
+ public void actionPerformed(ActionEvent e) {\r
+ int resp = showOpenDialog(MidiEditor.this);\r
+ if( resp == JFileChooser.APPROVE_OPTION )\r
+ addSequence(getSelectedFile());\r
+ }\r
+ };\r
};\r
\r
/**\r
- * MIDIトラック数表示ラベル\r
- */\r
- private JLabel tracksLabel;\r
- /**\r
* MIDIトラック選択状態\r
*/\r
private ListSelectionModel trackSelectionModel = new DefaultListSelectionModel() {{\r
addListSelectionListener(new ListSelectionListener() {\r
@Override\r
public void valueChanged(ListSelectionEvent e) {\r
- if( e.getValueIsAdjusting() ) return;\r
- SequenceTrackListTableModel sequenceModel = sequenceListTableModel.getSequenceModel(seqSelectionModel);\r
+ if( e.getValueIsAdjusting() )\r
+ return;\r
+ SequenceTrackListTableModel sequenceModel = sequenceListTableModel.getSequenceModel(sequenceListSelectionModel);\r
if( sequenceModel == null || isSelectionEmpty() ) {\r
- midiEventsLabel.setText("MIDI Events (No track selected)");\r
- eventListTableView.setModel(new TrackEventListTableModel());\r
+ trackEventListTableView.setModel(new TrackEventListTableModel());\r
}\r
else {\r
int selIndex = getMinSelectionIndex();\r
TrackEventListTableModel trackModel = sequenceModel.getTrackModel(selIndex);\r
if( trackModel == null ) {\r
- midiEventsLabel.setText("MIDI Events (No track selected)");\r
- eventListTableView.setModel(new TrackEventListTableModel());\r
+ trackEventListTableView.setModel(new TrackEventListTableModel());\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
+ trackEventListTableView.setModel(trackModel);\r
+ TableColumnModel tcm = trackEventListTableView.getColumnModel();\r
trackModel.sizeColumnWidthToFit(tcm);\r
- tcm.getColumn(TrackEventListTableModel.Column.MESSAGE.ordinal()).setCellEditor(eventCellEditor);\r
+ TableColumn midiMessageColumn = tcm.getColumn(TrackEventListTableModel.Column.MESSAGE.ordinal());\r
+ midiMessageColumn.setCellEditor(eventCellEditor);\r
}\r
}\r
- setActionEnabled();\r
- eventSelectionModel.setSelectionInterval(0,0);\r
+ updateButtonStatus();\r
}\r
});\r
}};\r
public Action addTrackAction = new AbstractAction("New") {\r
@Override\r
public void actionPerformed(ActionEvent e) {\r
- int index = sequenceListTableModel.getSequenceModel(seqSelectionModel).createTrack();\r
+ int index = sequenceListTableModel.getSequenceModel(sequenceListSelectionModel).createTrack();\r
trackSelectionModel.setSelectionInterval(index, index);\r
- sequenceListTableModel.fireSequenceChanged(seqSelectionModel);\r
+ sequenceListTableModel.fireSequenceChanged(sequenceListSelectionModel);\r
}\r
};\r
/**\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
+ sequenceListTableModel.getSequenceModel(sequenceListSelectionModel).deleteTracks(trackSelectionModel);\r
+ sequenceListTableModel.fireSequenceChanged(sequenceListSelectionModel);\r
}\r
};\r
+ /**\r
+ * MIDIトラックリストテーブルビュー(選択中のシーケンスの中身)\r
+ */\r
+ private JTable trackListTableView = new JTable(\r
+ new SequenceTrackListTableModel(sequenceListTableModel),\r
+ null, trackSelectionModel\r
+ );\r
+ private TracksLabel trackListTitleLabel = new TracksLabel();\r
+ private class TracksLabel extends JLabel implements ListSelectionListener {\r
+ private static final String TITLE = "Tracks";\r
+ public TracksLabel() {\r
+ super(TITLE);\r
+ sequenceListSelectionModel.addListSelectionListener(this);\r
+ }\r
+ @Override\r
+ public void valueChanged(ListSelectionEvent e) {\r
+ if( e.getValueIsAdjusting() )\r
+ return;\r
+ int index = sequenceListSelectionModel.getMinSelectionIndex();\r
+ String text = TITLE;\r
+ if( index >= 0 )\r
+ text = String.format(text+" - MIDI file No.%d", index);\r
+ setText(text);\r
+ }\r
+ }\r
\r
/**\r
* MIDIイベント選択状態\r
public void valueChanged(ListSelectionEvent e) {\r
if( e.getValueIsAdjusting() ) return;\r
if( ! isSelectionEmpty() ) {\r
- TrackEventListTableModel trackModel = (TrackEventListTableModel)eventListTableView.getModel();\r
+ TrackEventListTableModel trackModel = (TrackEventListTableModel)trackEventListTableView.getModel();\r
int minIndex = getMinSelectionIndex();\r
if( trackModel.hasTrack() ) {\r
MidiEvent midiEvent = trackModel.getMidiEvent(minIndex);\r
) addSelectionInterval(partnerIndex, partnerIndex);\r
}\r
}\r
- setActionEnabled();\r
+ updateButtonStatus();\r
}\r
});\r
}};\r
/**\r
* MIDIイベントリストテーブルビュー\r
*/\r
- private JTable eventListTableView;\r
+ private JTable trackEventListTableView = new JTable(\r
+ new TrackEventListTableModel(), null, eventSelectionModel\r
+ );\r
+ private MidiEventsLabel midiEventsLabel = new MidiEventsLabel();\r
+ private class MidiEventsLabel extends JLabel implements ListSelectionListener {\r
+ private static final String TITLE = "MIDI Events";\r
+ public MidiEventsLabel() {\r
+ super(TITLE);\r
+ trackSelectionModel.addListSelectionListener(this);\r
+ }\r
+ @Override\r
+ public void valueChanged(ListSelectionEvent e) {\r
+ String text = TITLE;\r
+ int index = trackSelectionModel.getMinSelectionIndex();\r
+ if( index >= 0 )\r
+ text = String.format(TITLE+" - track No.%d", index);\r
+ setText(text);\r
+ }\r
+ }\r
/**\r
* スクロール可能なMIDIイベントテーブルビュー\r
*/\r
- private JScrollPane scrollableEventTableView;\r
+ private JScrollPane scrollableEventTableView = new JScrollPane(trackEventListTableView);\r
/**\r
- * MIDIイベント数表示ラベル\r
+ * 指定の MIDI tick のイベントへスクロールします。\r
+ * @param tick MIDI tick\r
*/\r
- private JLabel midiEventsLabel;\r
+ public void scrollToEventAt(long tick) {\r
+ TrackEventListTableModel trackModel = (TrackEventListTableModel)trackEventListTableView.getModel();\r
+ int index = trackModel.tickToIndex(tick);\r
+ scrollableEventTableView.getVerticalScrollBar().setValue(\r
+ index * trackEventListTableView.getRowHeight()\r
+ );\r
+ eventSelectionModel.setSelectionInterval(index, index);\r
+ }\r
/**\r
- * MIDIイベント入力ダイアログ\r
+ * MIDIイベント表のセルエディタ\r
*/\r
- MidiEventDialog eventDialog = new MidiEventDialog();\r
+ MidiEventCellEditor eventCellEditor = new MidiEventCellEditor();\r
/**\r
* Pair note on/off チェックボックス\r
*/\r
- private JCheckBox pairNoteCheckbox;\r
-\r
+ private JCheckBox pairNoteCheckbox = new JCheckBox("Pair NoteON/OFF") {\r
+ { setModel(eventCellEditor.pairNoteOnOffModel); }\r
+ };\r
/**\r
* MIDIイベント表のセルエディタ\r
*/\r
class MidiEventCellEditor extends AbstractCellEditor implements TableCellEditor {\r
/**\r
+ * MIDIイベント入力ダイアログ\r
+ */\r
+ MidiEventDialog eventDialog = new MidiEventDialog();\r
+ /**\r
* 削除対象にする変更前イベント(null可)\r
*/\r
private MidiEvent[] midiEventsToBeRemoved;\r
* Pair noteON/OFF トグルボタンモデル\r
*/\r
private JToggleButton.ToggleButtonModel pairNoteOnOffModel =\r
- new JToggleButton.ToggleButtonModel();\r
+ new JToggleButton.ToggleButtonModel() {{\r
+ addItemListener(new ItemListener() {\r
+ public void itemStateChanged(ItemEvent e) {\r
+ eventDialog.midiMessageForm.durationForm.setEnabled(isSelected());\r
+ }\r
+ });\r
+ setSelected(true);\r
+ }};\r
\r
private void setSelectedEvent() {\r
- sequenceTableModel = sequenceListTableModel.getSequenceModel(seqSelectionModel);\r
+ sequenceTableModel = sequenceListTableModel.getSequenceModel(sequenceListSelectionModel);\r
eventDialog.midiMessageForm.durationForm.setPPQ(sequenceTableModel.getSequence().getResolution());\r
tickPositionModel.setSequenceIndex(sequenceTableModel.getSequenceTickIndex());\r
selectedIndex = -1;\r
currentTick = 0;\r
selectedMidiEvent = null;\r
- midiTrackTableModel = (TrackEventListTableModel)eventListTableView.getModel();\r
+ midiTrackTableModel = (TrackEventListTableModel)trackEventListTableView.getModel();\r
if( ! eventSelectionModel.isSelectionEmpty() ) {\r
selectedIndex = eventSelectionModel.getMinSelectionIndex();\r
selectedMidiEvent = midiTrackTableModel.getMidiEvent(selectedIndex);\r
* イベント入力をキャンセルするアクション\r
*/\r
Action cancelAction = new AbstractAction() {\r
- { putValue(NAME,"Cancel"); }\r
+ {\r
+ putValue(NAME,"Cancel");\r
+ eventDialog.cancelButton.setAction(this);\r
+ }\r
public void actionPerformed(ActionEvent e) {\r
fireEditingCanceled();\r
eventDialog.setVisible(false);\r
{ putValue(NAME,"Paste"); }\r
public void actionPerformed(ActionEvent e) {\r
long tick = tickPositionModel.getTickPosition();\r
- ((TrackEventListTableModel)eventListTableView.getModel()).addMidiEvents(\r
+ ((TrackEventListTableModel)trackEventListTableView.getModel()).addMidiEvents(\r
copiedEventsToPaste, tick, copiedEventsPPQ\r
);\r
scrollToEventAt(tick);\r
- sequenceListTableModel.fireSequenceChanged(seqSelectionModel);\r
+ sequenceListTableModel.fireSequenceChanged(sequenceListSelectionModel);\r
eventDialog.setVisible(false);\r
}\r
};\r
}\r
};\r
/**\r
- * イベント編集ボタン\r
- */\r
- private JButton editEventButton = new JButton() {{\r
- setHorizontalAlignment(JButton.LEFT);\r
- }};\r
- /**\r
- * MIDIイベント表のセルエディタを構築します。\r
+ * イベント編集アクション\r
*/\r
- public MidiEventCellEditor() {\r
- eventDialog.cancelButton.setAction(cancelAction);\r
- eventDialog.midiMessageForm.setOutputMidiChannels(virtualMidiDevice.getChannels());\r
- eventDialog.tickPositionInputForm.setModel(tickPositionModel);\r
- editEventButton.addActionListener(\r
- new ActionListener() {\r
- public void actionPerformed(ActionEvent e) {\r
- setSelectedEvent();\r
- if( selectedMidiEvent == null ) return;\r
- MidiEvent partnerEvent = null;\r
- eventDialog.midiMessageForm.setMessage(selectedMidiEvent.getMessage());\r
- if( eventDialog.midiMessageForm.isNote() ) {\r
- int partnerIndex = midiTrackTableModel.getIndexOfPartnerFor(selectedIndex);\r
- if( partnerIndex < 0 ) {\r
- eventDialog.midiMessageForm.durationForm.setDuration(0);\r
- }\r
- else {\r
- partnerEvent = midiTrackTableModel.getMidiEvent(partnerIndex);\r
- long partnerTick = partnerEvent.getTick();\r
- long duration = currentTick > partnerTick ?\r
- currentTick - partnerTick : partnerTick - currentTick ;\r
- eventDialog.midiMessageForm.durationForm.setDuration((int)duration);\r
- }\r
- }\r
- MidiEvent events[];\r
- if( partnerEvent == null ) {\r
- events = new MidiEvent[1];\r
- events[0] = selectedMidiEvent;\r
- }\r
- else {\r
- events = new MidiEvent[2];\r
- events[0] = selectedMidiEvent;\r
- events[1] = partnerEvent;\r
- }\r
- midiEventsToBeRemoved = events;\r
- eventDialog.setTitle("Change MIDI event");\r
- eventDialog.okButton.setAction(addEventAction);\r
- eventDialog.openEventForm();\r
+ private Action editEventAction = new AbstractAction() {\r
+ public void actionPerformed(ActionEvent e) {\r
+ setSelectedEvent();\r
+ if( selectedMidiEvent == null )\r
+ return;\r
+ MidiEvent partnerEvent = null;\r
+ eventDialog.midiMessageForm.setMessage(selectedMidiEvent.getMessage());\r
+ if( eventDialog.midiMessageForm.isNote() ) {\r
+ int partnerIndex = midiTrackTableModel.getIndexOfPartnerFor(selectedIndex);\r
+ if( partnerIndex < 0 ) {\r
+ eventDialog.midiMessageForm.durationForm.setDuration(0);\r
}\r
- }\r
- );\r
- pairNoteOnOffModel.addItemListener(\r
- new ItemListener() {\r
- public void itemStateChanged(ItemEvent e) {\r
- eventDialog.midiMessageForm.durationForm.setEnabled(\r
- pairNoteOnOffModel.isSelected()\r
- );\r
+ else {\r
+ partnerEvent = midiTrackTableModel.getMidiEvent(partnerIndex);\r
+ long partnerTick = partnerEvent.getTick();\r
+ long duration = currentTick > partnerTick ?\r
+ currentTick - partnerTick : partnerTick - currentTick ;\r
+ eventDialog.midiMessageForm.durationForm.setDuration((int)duration);\r
}\r
}\r
- );\r
- pairNoteOnOffModel.setSelected(true);\r
+ MidiEvent events[];\r
+ if( partnerEvent == null ) {\r
+ events = new MidiEvent[1];\r
+ events[0] = selectedMidiEvent;\r
+ }\r
+ else {\r
+ events = new MidiEvent[2];\r
+ events[0] = selectedMidiEvent;\r
+ events[1] = partnerEvent;\r
+ }\r
+ midiEventsToBeRemoved = events;\r
+ eventDialog.setTitle("Change MIDI event");\r
+ eventDialog.okButton.setAction(addEventAction);\r
+ eventDialog.openEventForm();\r
+ }\r
+ };\r
+ public MidiEventCellEditor() {\r
+ eventDialog.midiMessageForm.setOutputMidiChannels(virtualMidiDevice.getChannels());\r
+ eventDialog.tickPositionInputForm.setModel(tickPositionModel);\r
}\r
+ @Override\r
public boolean isCellEditable(EventObject e) {\r
// ダブルクリックで編集\r
return e instanceof MouseEvent && ((MouseEvent)e).getClickCount() == 2;\r
}\r
- public Object getCellEditorValue() {\r
- return "";\r
- }\r
+ @Override\r
+ public Object getCellEditorValue() { return ""; }\r
+ private JButton editEventButton = new JButton(editEventAction){\r
+ {\r
+ setHorizontalAlignment(JButton.LEFT);\r
+ }\r
+ };\r
+ @Override\r
public Component getTableCellEditorComponent(\r
- JTable table, Object value, boolean isSelected,\r
- int row, int column\r
+ JTable table, Object value, boolean isSelected, int row, int column\r
) {\r
editEventButton.setText((String)value);\r
return editEventButton;\r
}\r
\r
/**\r
- * MIDIイベントセルエディタ\r
- */\r
- private MidiEventCellEditor eventCellEditor = new MidiEventCellEditor();\r
- /**\r
* ペースト用にコピーされたMIDIイベントの配列\r
*/\r
private MidiEvent copiedEventsToPaste[];\r
public void actionPerformed(ActionEvent e) {\r
if( ! confirm("Do you want to cut selected event ?\n選択したMIDIイベントを切り取りますか?"))\r
return;\r
- TrackEventListTableModel trackTableModel = (TrackEventListTableModel)eventListTableView.getModel();\r
+ TrackEventListTableModel trackTableModel = (TrackEventListTableModel)trackEventListTableView.getModel();\r
copiedEventsToPaste = trackTableModel.getMidiEvents(eventSelectionModel);\r
- copiedEventsPPQ = sequenceListTableModel.getSequenceModel(seqSelectionModel).getSequence().getResolution();\r
+ copiedEventsPPQ = sequenceListTableModel.getSequenceModel(sequenceListSelectionModel).getSequence().getResolution();\r
trackTableModel.removeMidiEvents(copiedEventsToPaste);\r
- sequenceListTableModel.fireSequenceChanged(seqSelectionModel);\r
+ sequenceListTableModel.fireSequenceChanged(sequenceListSelectionModel);\r
}\r
};\r
/**\r
public Action copyEventAction = new AbstractAction("Copy") {\r
@Override\r
public void actionPerformed(ActionEvent e) {\r
- TrackEventListTableModel trackTableModel = (TrackEventListTableModel)eventListTableView.getModel();\r
+ TrackEventListTableModel trackTableModel = (TrackEventListTableModel)trackEventListTableView.getModel();\r
copiedEventsToPaste = trackTableModel.getMidiEvents(eventSelectionModel);\r
- copiedEventsPPQ = sequenceListTableModel.getSequenceModel(seqSelectionModel).getSequence().getResolution();\r
- setActionEnabled();\r
+ copiedEventsPPQ = sequenceListTableModel.getSequenceModel(sequenceListSelectionModel).getSequence().getResolution();\r
+ updateButtonStatus();\r
}\r
};\r
/**\r
public void actionPerformed(ActionEvent e) {\r
if( ! confirm("Do you want to delete selected event ?\n選択したMIDIイベントを削除しますか?"))\r
return;\r
- ((TrackEventListTableModel)eventListTableView.getModel()).removeMidiEvents(eventSelectionModel);\r
- sequenceListTableModel.fireSequenceChanged(seqSelectionModel);\r
+ ((TrackEventListTableModel)trackEventListTableView.getModel()).removeMidiEvents(eventSelectionModel);\r
+ sequenceListTableModel.fireSequenceChanged(sequenceListSelectionModel);\r
}\r
};\r
/**\r
* @param deviceModelList MIDIデバイスモデルリスト\r
*/\r
public MidiEditor(MidiSequencerModel sequencerModel) {\r
- sequenceListTableModel = new SequenceListTableModel(sequencerModel);\r
+ sequenceListTableModel = new SequenceListTableModel(sequencerModel) ;\r
setTitle("MIDI Editor/Playlist - MIDI Chord Helper");\r
setBounds( 150, 200, 850, 500 );\r
setLayout(new FlowLayout());\r
// アクセスできないので、ファイル選択ダイアログは使用不可。\r
midiFileChooser = null;\r
}\r
+ sequenceListTableView = new JTable(\r
+ sequenceListTableModel,\r
+ new SequenceListTableColumnModel() {\r
+ JToggleButton playButton = new JToggleButton(\r
+ sequenceListTableModel.sequencerModel.startStopAction\r
+ ){{ setMargin(ZERO_INSETS); }};\r
+ class ButtonCellEditor extends AbstractCellEditor implements TableCellEditor {\r
+ @Override\r
+ public Object getCellEditorValue() { return ""; }\r
+ @Override\r
+ public Component getTableCellEditorComponent(\r
+ JTable table, Object value, boolean isSelected,\r
+ int row, int column\r
+ ) {\r
+ if(row == sequenceListTableModel.getLoadedIndex())\r
+ return playButton;\r
+ return null;\r
+ }\r
+ }\r
+ {\r
+ sequenceListTableModel.addTableModelListener(this);\r
+ TableColumn tc = getColumn(Column.SEQ_PLAY.ordinal());\r
+ tc.setCellRenderer(new TableCellRenderer() {\r
+ @Override\r
+ public Component getTableCellRendererComponent(\r
+ JTable table, Object value, boolean isSelected,\r
+ boolean hasFocus, int row, int column\r
+ ) {\r
+ if(row == sequenceListTableModel.getLoadedIndex())\r
+ return playButton;\r
+ return null;\r
+ }\r
+ });\r
+ tc.setCellEditor(new ButtonCellEditor());\r
+ }\r
+ },\r
+ sequenceListSelectionModel\r
+ ) {{\r
+ sequenceListTableModel.addTableModelListener(\r
+ new TableModelListener() {\r
+ // シーケンス削除時など、合計シーケンス長が変わっても\r
+ // 列モデルからではヘッダタイトルが再描画されないことがある。\r
+ // そこで、ヘッダビューから repaint() で突っついて再描画させる。\r
+ @Override\r
+ public void tableChanged(TableModelEvent e) {\r
+ getTableHeader().repaint();\r
+ }\r
+ }\r
+ );\r
+ }};\r
JPanel playlistPanel = new JPanel() {{\r
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));\r
- add(new JScrollPane(\r
- new JTable(sequenceListTableModel, null, seqSelectionModel) {{\r
- sequenceListTableModel.sizeColumnWidthToFit(this);\r
- }}\r
- ));\r
+ add(new JScrollPane(sequenceListTableView));\r
add(Box.createRigidArea(new Dimension(0, 10)));\r
add(new JPanel() {{\r
- setLayout( new BoxLayout(this, BoxLayout.LINE_AXIS ));\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
+ setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));\r
add(Box.createRigidArea(new Dimension(10, 0)));\r
- add(new JButton("New") {{\r
- setToolTipText("Generate new song - 新しい曲を生成");\r
- setMargin(ZERO_INSETS);\r
- addActionListener(\r
- new ActionListener() {\r
- public void actionPerformed(ActionEvent e) {\r
- newSequenceDialog.setVisible(true);\r
- }\r
- }\r
- );\r
- }});\r
+ add(new JButton(generateNewSongAction) {{setMargin(ZERO_INSETS);}});\r
if( midiFileChooser != null ) {\r
add( Box.createRigidArea(new Dimension(5, 0)) );\r
add(new JButton(midiFileChooser.addMidiFileAction) {{\r
setMargin(ZERO_INSETS);\r
}});\r
add(Box.createRigidArea(new Dimension(5, 0)));\r
- add(new JToggleButton(\r
- sequenceListTableModel.sequencerModel.startStopAction\r
- ));\r
+ add(new JButton(jumpSequenceAction){{ setMargin(ZERO_INSETS); }});\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(jumpSequenceAction){{ setMargin(ZERO_INSETS); }});\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
- base64EncodeAction = new AbstractAction("Base64 Encode") {\r
- @Override\r
- public void actionPerformed(ActionEvent e) {\r
- SequenceTrackListTableModel mstm = sequenceListTableModel.getSequenceModel(seqSelectionModel);\r
- base64Dialog.setMIDIData(mstm.getMIDIdata(), mstm.getFilename());\r
- base64Dialog.setVisible(true);\r
- }\r
- };\r
+ if(base64EncodeAction != null) {\r
add(Box.createRigidArea(new Dimension(5, 0)));\r
add(new JButton(base64EncodeAction) {{\r
setMargin(ZERO_INSETS);\r
}};\r
JPanel trackListPanel = new JPanel() {{\r
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));\r
- add(tracksLabel = new JLabel("Tracks"));\r
+ add(trackListTitleLabel);\r
add(Box.createRigidArea(new Dimension(0, 5)));\r
- add(new JScrollPane(\r
- trackListTableView = new JTable(\r
- new SequenceTrackListTableModel(sequenceListTableModel),\r
- null,\r
- trackSelectionModel\r
- ) {{\r
- ((SequenceTrackListTableModel)getModel()).sizeColumnWidthToFit(getColumnModel());\r
- }}\r
- ));\r
+ add(new JScrollPane(trackListTableView));\r
add(Box.createRigidArea(new Dimension(0, 5)));\r
add(new JPanel() {{\r
add(new JButton(addTrackAction) {{ setMargin(ZERO_INSETS); }});\r
}});\r
}};\r
JPanel eventListPanel = new JPanel() {{\r
- add(midiEventsLabel = new JLabel("No track selected"));\r
- add(scrollableEventTableView = new JScrollPane(\r
- eventListTableView = new JTable(\r
- new TrackEventListTableModel(), null, eventSelectionModel\r
- )\r
- ));\r
+ add(midiEventsLabel);\r
+ add(scrollableEventTableView);\r
add(new JPanel() {{\r
- add(\r
- pairNoteCheckbox = new JCheckBox("Pair NoteON/OFF") {{\r
- setModel(eventCellEditor.pairNoteOnOffModel);\r
- }}\r
- );\r
+ add(pairNoteCheckbox);\r
add(new JButton(eventCellEditor.queryJumpEventAction) {{\r
setMargin(ZERO_INSETS);\r
}});\r
setDividerLocation(160);\r
}}\r
);\r
- sequenceSelectionChanged();\r
+ updateButtonStatus();\r
}\r
+\r
+ // Drag & drop\r
public void dragEnter(DropTargetDragEvent event) {\r
if( event.isDataFlavorSupported(DataFlavor.javaFileListFlavor) )\r
event.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);\r
event.dropComplete(false);\r
}\r
}\r
+\r
+ // Short message dialogs\r
private void showError(String message) {\r
JOptionPane.showMessageDialog(\r
this, message,\r
JOptionPane.WARNING_MESSAGE\r
) == JOptionPane.YES_OPTION ;\r
}\r
- @Override\r
- public void setVisible(boolean isToVisible) {\r
- if( isToVisible && isVisible() )\r
- toFront();\r
- else\r
- super.setVisible(isToVisible);\r
- }\r
- @Override\r
- public void actionPerformed(ActionEvent e) {\r
- setVisible(true);\r
- }\r
- /**\r
- * MIDIトラックリストテーブルビュー(選択中のシーケンスの中身)\r
- */\r
- private JTable trackListTableView;\r
+\r
/**\r
- * 選択されたシーケンスが変わったときの動作\r
+ * ボタン状態の更新\r
*/\r
- public void sequenceSelectionChanged() {\r
- SequenceTrackListTableModel sequenceModel = sequenceListTableModel.getSequenceModel(seqSelectionModel);\r
+ public void updateButtonStatus() {\r
+ SequenceTrackListTableModel sequenceModel = sequenceListTableModel.getSequenceModel(sequenceListSelectionModel);\r
boolean isSequenceSelected = (sequenceModel != null);\r
- //\r
- // ボタンイネーブル状態の更新\r
- if(midiFileChooser != null)\r
- midiFileChooser.saveMidiFileAction.setEnabled(isSequenceSelected);\r
- if(base64EncodeAction != null)\r
- base64EncodeAction.setEnabled(isSequenceSelected);\r
- deleteSequenceAction.setEnabled(isSequenceSelected);\r
- jumpSequenceAction.setEnabled(isSequenceSelected);\r
- addTrackAction.setEnabled(isSequenceSelected);\r
- //\r
- // トラックリストの対象シーケンスを切り替える\r
if(isSequenceSelected) {\r
- int selectedIndex = seqSelectionModel.getMinSelectionIndex();\r
trackListTableView.setModel(sequenceModel);\r
- TableColumnModel trackColumnModel = trackListTableView.getColumnModel();\r
- sequenceModel.sizeColumnWidthToFit(trackColumnModel);\r
- int columnIndex = SequenceTrackListTableModel.Column.RECORD_CHANNEL.ordinal();\r
- TableColumn trackColumn = trackColumnModel.getColumn(columnIndex);\r
- trackColumn.setCellEditor(sequenceModel.new RecordChannelCellEditor());\r
- trackSelectionModel.setSelectionInterval(0,0);\r
- tracksLabel.setText(String.format("Tracks (in MIDI file No.%d)", selectedIndex));\r
+ trackListTableView.getColumnModel().getColumn(\r
+ SequenceTrackListTableModel.Column.RECORD_CHANNEL.ordinal()\r
+ ).setCellEditor(\r
+ new DefaultCellEditor(\r
+ new JComboBox<String>() {\r
+ {\r
+ addItem("OFF");\r
+ for(int i=1; i <= MIDISpec.MAX_CHANNELS; i++)\r
+ addItem(String.format("%d", i));\r
+ addItem("ALL");\r
+ }\r
+ }\r
+ )\r
+ );\r
}\r
else {\r
- trackListTableView.setModel(new SequenceTrackListTableModel(sequenceListTableModel));\r
- tracksLabel.setText("Tracks (No MIDI file selected)");\r
+ SequenceTrackListTableModel m = new SequenceTrackListTableModel(sequenceListTableModel);\r
+ trackListTableView.setModel(m);\r
}\r
- setActionEnabled();\r
- }\r
- /**\r
- * ボタン状態の更新\r
- */\r
- public void setActionEnabled() {\r
+ addTrackAction.setEnabled(isSequenceSelected);\r
boolean isTrackSelected = (\r
- ! trackSelectionModel.isSelectionEmpty() &&\r
- sequenceListTableModel.getSequenceModel(seqSelectionModel) != null &&\r
- sequenceListTableModel.getSequenceModel(seqSelectionModel).getRowCount() > 0\r
+ ! trackSelectionModel.isSelectionEmpty()\r
+ &&\r
+ isSequenceSelected && sequenceModel.getRowCount() > 0\r
);\r
removeTrackAction.setEnabled(isTrackSelected);\r
- TableModel tm = eventListTableView.getModel();\r
+ //\r
+ TableModel tm = trackEventListTableView.getModel();\r
if( ! (tm instanceof TrackEventListTableModel) )\r
return;\r
- //\r
- //\r
TrackEventListTableModel trackTableModel = (TrackEventListTableModel)tm;\r
- jumpSequenceAction.setEnabled(\r
- trackTableModel != null && trackTableModel.getRowCount() > 0\r
- );\r
boolean isEventSelected = (\r
- !(\r
- eventSelectionModel.isSelectionEmpty() ||\r
- trackTableModel == null || trackTableModel.getRowCount() == 0\r
- ) && isTrackSelected\r
+ isTrackSelected &&\r
+ ! eventSelectionModel.isSelectionEmpty() &&\r
+ trackTableModel != null && trackTableModel.getRowCount() > 0\r
);\r
- //\r
- // イベント操作のイネーブル状態更新\r
copyEventAction.setEnabled(isEventSelected);\r
deleteEventAction.setEnabled(isEventSelected);\r
cutEventAction.setEnabled(isEventSelected);\r
public int addSequenceAndPlay(Sequence sequence) {\r
int lastIndex = sequenceListTableModel.addSequence(sequence,"");\r
if( ! sequenceListTableModel.sequencerModel.getSequencer().isRunning() ) {\r
- load(lastIndex);\r
+ sequenceListTableModel.loadToSequencer(lastIndex);\r
sequenceListTableModel.sequencerModel.start();\r
}\r
return lastIndex;\r
}\r
\r
/**\r
- * 指定のインデックス位置にあるMIDIシーケンスをシーケンサーにロードします。\r
- * @param index MIDIシーケンスのインデックス(先頭が 0)\r
- */\r
- public void load(int index) {\r
- sequenceListTableModel.loadToSequencer(index);\r
- sequenceSelectionChanged();\r
- }\r
- /**\r
- * 次の曲をロードします。\r
- * @param offset 何曲次へ進むかを表す数値\r
- * @return 成功したらtrue\r
- */\r
- public boolean loadNext(int offset) {\r
- boolean retval = sequenceListTableModel.loadNext(offset);\r
- sequenceSelectionChanged();\r
- return retval;\r
- }\r
- /**\r
* 複数のMIDIファイルを読み込み、再生されていなかったら再生します。\r
* すでに再生されていた場合、このエディタダイアログを表示します。\r
*\r
setVisible(true);\r
}\r
else if( firstIndex >= 0 ) {\r
- load(firstIndex);\r
+ sequenceListTableModel.loadToSequencer(firstIndex);\r
sequenceListTableModel.sequencerModel.start();\r
}\r
}\r
*/\r
public boolean isRecordable() {\r
SequenceTrackListTableModel sequenceTableModel =\r
- sequenceListTableModel.getSequenceModel(seqSelectionModel);\r
+ sequenceListTableModel.getSequenceModel(sequenceListSelectionModel);\r
return sequenceTableModel == null ? false : sequenceTableModel.isRecordable();\r
}\r
- /**\r
- * 指定の MIDI tick のイベントへスクロールします。\r
- * @param tick MIDI tick\r
- */\r
- public void scrollToEventAt(long tick) {\r
- TrackEventListTableModel trackModel = (TrackEventListTableModel)eventListTableView.getModel();\r
- int index = trackModel.tickToIndex(tick);\r
- scrollableEventTableView.getVerticalScrollBar().setValue(\r
- index * eventListTableView.getRowHeight()\r
- );\r
- eventSelectionModel.setSelectionInterval(index, index);\r
- }\r
}\r
\r
/**\r
}\r
\r
/**\r
- * プレイリスト(MIDIシーケンスリスト)のテーブルモデル\r
+ * プレイリスト(MIDIシーケンスリスト)のテーブル列モデル\r
*/\r
-class SequenceListTableModel extends AbstractTableModel implements ChangeListener {\r
+class SequenceListTableColumnModel extends DefaultTableColumnModel\r
+ implements TableModelListener\r
+{\r
/**\r
* 列の列挙型\r
*/\r
public enum Column {\r
/** MIDIシーケンスの番号 */\r
- SEQ_NUMBER("No.", 2, Integer.class),\r
+ SEQ_NUMBER("No.", Integer.class),\r
/** 変更済みフラグ */\r
- MODIFIED("Modified", 6, Boolean.class),\r
+ MODIFIED("Modified", Boolean.class),\r
+ /** 再生ボタン */\r
+ SEQ_PLAY("", String.class) {\r
+ @Override\r
+ public boolean isCellEditable() { return true; }\r
+ },\r
/** 再生中の時間位置(分:秒) */\r
- SEQ_POSITION("Position", 6, String.class),\r
+ SEQ_POSITION("Position", String.class),\r
/** シーケンスの時間長(分:秒) */\r
- SEQ_LENGTH("Length", 6, String.class),\r
+ SEQ_LENGTH("Length", String.class),\r
/** ファイル名 */\r
- FILENAME("Filename", 16, String.class),\r
+ FILENAME("Filename", String.class) {\r
+ @Override\r
+ public boolean isCellEditable() { return true; }\r
+ },\r
/** シーケンス名(最初のトラックの名前) */\r
- SEQ_NAME("Sequence name", 40, String.class),\r
+ SEQ_NAME("Sequence name", String.class) {\r
+ @Override\r
+ public boolean isCellEditable() { return true; }\r
+ },\r
/** タイミング解像度 */\r
- RESOLUTION("Resolution", 6, Integer.class),\r
+ RESOLUTION("Resolution", Integer.class),\r
/** トラック数 */\r
- TRACKS("Tracks", 6, Integer.class),\r
+ TRACKS("Tracks", Integer.class),\r
/** タイミング分割形式 */\r
- DIVISION_TYPE("DivType", 6, String.class);\r
- private String title;\r
- private int widthRatio;\r
- private Class<?> columnClass;\r
+ DIVISION_TYPE("DivType", String.class);\r
+ String title;\r
+ Class<?> columnClass;\r
/**\r
* 列の識別子を構築します。\r
* @param title 列のタイトル\r
- * @param widthRatio 幅の割合\r
* @param columnClass 列のクラス\r
*/\r
- private Column(String title, int widthRatio, Class<?> columnClass) {\r
+ private Column(String title, Class<?> columnClass) {\r
this.title = title;\r
- this.widthRatio = widthRatio;\r
this.columnClass = columnClass;\r
}\r
- /**\r
- * 幅の割合の合計を返します。\r
- * @return 幅の割合の合計\r
- */\r
- public static int totalWidthRatio() {\r
- int total = 0;\r
- for( Column c : values() ) total += c.widthRatio;\r
- return total;\r
+ public boolean isCellEditable() { return false; }\r
+ }\r
+ public SequenceListTableColumnModel() {\r
+ for( Column c : Column.values() ) {\r
+ TableColumn tc = new TableColumn(c.ordinal());\r
+ tc.setHeaderValue(c.title);\r
+ addColumn(tc);\r
}\r
}\r
/**\r
+ * 全シーケンスの合計時間長をヘッダータイトルに反映します。\r
+ * @param e テーブルモデルイベント\r
+ */\r
+ @Override\r
+ public void tableChanged(TableModelEvent e) {\r
+ SequenceListTableModel model = (SequenceListTableModel)e.getSource();\r
+ int sec = model.getTotalSeconds();\r
+ Column c = Column.SEQ_LENGTH;\r
+ TableColumn tc = getColumn(c.ordinal());\r
+ tc.setHeaderValue(String.format(c.title+" [%02d:%02d]", sec/60, sec%60));\r
+ }\r
+}\r
+\r
+/**\r
+ * プレイリスト(MIDIシーケンスリスト)のテーブルモデル\r
+ */\r
+class SequenceListTableModel extends AbstractTableModel implements ChangeListener {\r
+ /**\r
* MIDIシーケンサモデル\r
*/\r
MidiSequencerModel sequencerModel;\r
*/\r
public Action moveToTopAction = new AbstractAction() {\r
{\r
- putValue( SHORT_DESCRIPTION,\r
+ putValue(SHORT_DESCRIPTION,\r
"Move to top or previous song - 曲の先頭または前の曲へ戻る"\r
);\r
- putValue( LARGE_ICON_KEY, new ButtonIcon(ButtonIcon.TOP_ICON) );\r
+ putValue(LARGE_ICON_KEY, new ButtonIcon(ButtonIcon.TOP_ICON));\r
}\r
public void actionPerformed(ActionEvent event) {\r
if( sequencerModel.getSequencer().getTickPosition() <= 40 )\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
+ 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
@Override\r
public void stateChanged(ChangeEvent e) {\r
int sec = sequencerModel.getValue() / 1000;\r
- if( secondPosition == sec )\r
+ if(secondPosition == sec)\r
return;\r
+ // 秒が変わったときだけ更新(小数点以下は無視)\r
secondPosition = sec;\r
- fireTableCellUpdated(getLoadedIndex(), Column.SEQ_POSITION.ordinal());\r
+ fireTableCellUpdated(\r
+ getLoadedIndex(),\r
+ SequenceListTableColumnModel.Column.SEQ_POSITION.ordinal()\r
+ );\r
}\r
- private List<SequenceTrackListTableModel> sequenceList = new ArrayList<>();\r
+ private List<SequenceTrackListTableModel> sequenceList = new Vector<>();\r
@Override\r
- public int getRowCount() {\r
- return sequenceList.size();\r
- }\r
+ public int getRowCount() { return sequenceList.size(); }\r
@Override\r
public int getColumnCount() {\r
- return Column.values().length;\r
+ return SequenceListTableColumnModel.Column.values().length;\r
}\r
@Override\r
public String getColumnName(int column) {\r
- return Column.values()[column].title;\r
+ return SequenceListTableColumnModel.Column.values()[column].title;\r
}\r
@Override\r
public Class<?> getColumnClass(int column) {\r
- return Column.values()[column].columnClass;\r
+ return SequenceListTableColumnModel.Column.values()[column].columnClass;\r
+ }\r
+ @Override\r
+ public boolean isCellEditable(int row, int column) {\r
+ return SequenceListTableColumnModel.Column.values()[column].isCellEditable();\r
}\r
@Override\r
public Object getValueAt(int row, int column) {\r
- switch(Column.values()[column]) {\r
+ switch(SequenceListTableColumnModel.Column.values()[column]) {\r
case SEQ_NUMBER: return row;\r
- case MODIFIED: return sequenceList.get(row).isModified();\r
+ case MODIFIED:\r
+ return sequenceList.get(row).isModified();\r
case DIVISION_TYPE: {\r
float divType = sequenceList.get(row).getSequence().getDivisionType();\r
if( divType == Sequence.PPQ ) return "PPQ";\r
case TRACKS:\r
return sequenceList.get(row).getSequence().getTracks().length;\r
case SEQ_POSITION: {\r
- Sequence loadedSequence = sequencerModel.getSequencer().getSequence();\r
- if( loadedSequence != null && loadedSequence == sequenceList.get(row).getSequence() )\r
+ if( getLoadedIndex() == row )\r
return String.format("%02d:%02d", secondPosition/60, secondPosition%60);\r
else\r
return "";\r
}\r
}\r
@Override\r
- public boolean isCellEditable( int row, int column ) {\r
- Column c = Column.values()[column];\r
- return c == Column.FILENAME || c == Column.SEQ_NAME ;\r
- }\r
- @Override\r
public void setValueAt(Object val, int row, int column) {\r
- switch(Column.values()[column]) {\r
+ switch(SequenceListTableColumnModel.Column.values()[column]) {\r
case FILENAME:\r
// ファイル名の変更\r
String filename = (String)val;\r
case SEQ_NAME:\r
// シーケンス名の設定または変更\r
if( sequenceList.get(row).setName((String)val) )\r
- fireTableCellUpdated(row, Column.MODIFIED.ordinal());\r
+ fireTableCellUpdated(row, SequenceListTableColumnModel.Column.MODIFIED.ordinal());\r
break;\r
default:\r
break;\r
}\r
}\r
/**\r
- * 列に合わせて幅を調整します。\r
- * @param tableView テーブルビュー\r
- */\r
- public void sizeColumnWidthToFit(JTable tableView) {\r
- TableColumnModel columnModel = tableView.getColumnModel();\r
- int totalWidth = columnModel.getTotalColumnWidth();\r
- int totalWidthRatio = Column.totalWidthRatio();\r
- for( Column c : Column.values() ) {\r
- int w = totalWidth * c.widthRatio / totalWidthRatio;\r
- columnModel.getColumn(c.ordinal()).setPreferredWidth(w);\r
- }\r
- }\r
- /**\r
* このプレイリストに読み込まれた全シーケンスの合計時間長を返します。\r
* @return 全シーケンスの合計時間長 [秒]\r
*/\r
for( int i = minIndex; i <= maxIndex; i++ ) {\r
if( selModel.isSelectedIndex(i) ) {\r
sequenceList.get(i).setModified(isModified);\r
- fireTableCellUpdated(i, Column.MODIFIED.ordinal());\r
+ fireTableCellUpdated(i, SequenceListTableColumnModel.Column.MODIFIED.ordinal());\r
}\r
}\r
}\r
*/\r
public void fireSequenceChanged(SequenceTrackListTableModel sequenceTableModel) {\r
int index = sequenceList.indexOf(sequenceTableModel);\r
- if( index < 0 ) return;\r
- fireSequenceChanged(index,index);\r
+ if( index < 0 )\r
+ return;\r
+ sequenceTableModel.setModified(true);\r
+ fireTableRowsUpdated(index, index);\r
}\r
/**\r
* 指定された選択範囲のシーケンスが変更されたことを通知します。\r
* @param selectionModel 選択状態\r
*/\r
public void fireSequenceChanged(ListSelectionModel selectionModel) {\r
- if( ! selectionModel.isSelectionEmpty() ) fireSequenceChanged(\r
- selectionModel.getMinSelectionIndex(),\r
- selectionModel.getMaxSelectionIndex()\r
- );\r
- }\r
- /**\r
- * 指定された範囲のシーケンスが変更されたことを通知します。\r
- * @param minIndex 範囲の最小インデックス\r
- * @param maxIndex 範囲の最大インデックス\r
- */\r
- public void fireSequenceChanged(int minIndex, int maxIndex) {\r
+ if( selectionModel.isSelectionEmpty() )\r
+ return;\r
+ int minIndex = selectionModel.getMinSelectionIndex();\r
+ int maxIndex = selectionModel.getMaxSelectionIndex();\r
for( int index = minIndex; index <= maxIndex; index++ ) {\r
- SequenceTrackListTableModel model = sequenceList.get(index);\r
- model.setModified(true);\r
- if( sequencerModel.getSequencer().getSequence() == model.getSequence() ) {\r
- // シーケンサーに対して、同じシーケンスを再度セットする。\r
- // (これをやらないと更新が反映されないため)\r
- sequencerModel.setSequenceTableModel(model);\r
- }\r
+ sequenceList.get(index).setModified(true);\r
}\r
fireTableRowsUpdated(minIndex, maxIndex);\r
}\r
if( listSelectionModel.isSelectionEmpty() )\r
return;\r
int selectedIndex = listSelectionModel.getMinSelectionIndex();\r
- if(sequenceList.get(selectedIndex) == sequencerModel.getSequenceTableModel())\r
+ if( selectedIndex == getLoadedIndex() ) {\r
+ // シーケンサーにロード済みのシーケンスだった場合はアンロードする\r
sequencerModel.setSequenceTableModel(null);\r
+ }\r
sequenceList.remove(selectedIndex);\r
fireTableRowsDeleted(selectedIndex, selectedIndex);\r
}\r
SequenceTrackListTableModel sequenceTableModel = sequenceList.get(index);\r
sequencerModel.setSequenceTableModel(sequenceTableModel);\r
//\r
- // 表示更新のための変更通知\r
+ // トラック内容の再表示\r
sequenceTableModel.fireTableDataChanged();\r
- int columnIndex = Column.SEQ_POSITION.ordinal();\r
- fireTableCellUpdated(oldIndex, columnIndex);\r
- fireTableCellUpdated(index, columnIndex);\r
+ //\r
+ // セルの再表示(シーケンサーのボタンと現在位置)\r
+ fireTableRowsUpdated(oldIndex, index);\r
+ int columnIndices[] = {\r
+ SequenceListTableColumnModel.Column.SEQ_PLAY.ordinal(),\r
+ SequenceListTableColumnModel.Column.SEQ_POSITION.ordinal(),\r
+ };\r
+ for( int columnIndex : columnIndices ) {\r
+ fireTableCellUpdated(oldIndex, columnIndex);\r
+ }\r
+ for( int columnIndex : columnIndices ) {\r
+ fireTableCellUpdated(index, columnIndex);\r
+ }\r
}\r
/**\r
* 現在シーケンサにロードされているシーケンスのインデックスを返します。\r
*/\r
private List<TrackEventListTableModel> trackModelList = new ArrayList<>();\r
/**\r
- * 記録するMIDIチャンネル\r
- */\r
- class RecordChannelCellEditor extends DefaultCellEditor {\r
- public RecordChannelCellEditor() {\r
- super(\r
- new JComboBox<String>() {\r
- {\r
- addItem("OFF");\r
- for( int i=1; i <= MIDISpec.MAX_CHANNELS; i++ )\r
- addItem( String.format("%d", i) );\r
- addItem("ALL");\r
- }\r
- }\r
- );\r
- }\r
- }\r
- /**\r
* 親のプレイリスト\r
*/\r
- private SequenceListTableModel sequenceListTableModel;\r
+ SequenceListTableModel sequenceListTableModel;\r
/**\r
* 空の {@link SequenceTrackListTableModel} を構築します。\r
* @param sequenceListTableModel 親のプレイリスト\r
int row = indexOf(track);\r
if( row < 0 ) return;\r
fireTableRowsUpdated(row, row);\r
- fireSequenceChanged();\r
- }\r
- /**\r
- * このシーケンスが変更されたことを通知します。\r
- */\r
- public void fireSequenceChanged() {\r
sequenceListTableModel.fireSequenceChanged(this);\r
}\r
/**\r
fireTableDataChanged();\r
if( MIDISpec.isEOT(msg) ) {\r
// EOTの場所が変わると曲の長さが変わるので、親モデルへ通知する。\r
- parent.fireSequenceChanged();\r
+ parent.sequenceListTableModel.fireSequenceChanged(parent);\r
}\r
}\r
/**\r
if(name.equals(toString()) || ! MIDISpec.setNameOf(track, name))\r
return false;\r
parent.setModified(true);\r
- parent.fireSequenceChanged();\r
+ parent.sequenceListTableModel.fireSequenceChanged(parent);\r
fireTableDataChanged();\r
return true;\r
}\r