OSDN Git Service

リファクタリング(MIDIエディタの内部クラスを外出し)
authorAkiyoshi Kamide <kamide@yk.rim.or.jp>
Fri, 21 Apr 2017 15:52:11 +0000 (00:52 +0900)
committerAkiyoshi Kamide <kamide@yk.rim.or.jp>
Fri, 21 Apr 2017 15:52:11 +0000 (00:52 +0900)
src/camidion/chordhelper/ChordHelperApplet.java
src/camidion/chordhelper/midieditor/MidiEventTable.java
src/camidion/chordhelper/midieditor/MidiSequenceEditorDialog.java
src/camidion/chordhelper/midieditor/PlaylistTable.java
src/camidion/chordhelper/midieditor/SequenceTrackListTable.java [new file with mode: 0644]

index b4fe592..652fc55 100644 (file)
@@ -50,6 +50,7 @@ import camidion.chordhelper.mididevice.SequencerTimeView;
 import camidion.chordhelper.mididevice.VirtualMidiDevice;
 import camidion.chordhelper.midieditor.Base64Dialog;
 import camidion.chordhelper.midieditor.KeySignatureLabel;
+import camidion.chordhelper.midieditor.MidiEventDialog;
 import camidion.chordhelper.midieditor.MidiSequenceEditorDialog;
 import camidion.chordhelper.midieditor.NewSequenceDialog;
 import camidion.chordhelper.midieditor.PlaylistTableModel;
@@ -135,7 +136,7 @@ public class ChordHelperApplet extends JApplet {
         * @return 追加先のインデックス値(0から始まる)。追加できなかったときは -1
         */
        public int addToPlaylistBase64(String base64EncodedText, String filename) {
-               Base64Dialog d = midiEditor.sequenceListTable.base64Dialog;
+               Base64Dialog d = midiEditor.playlistTable.base64Dialog;
                d.setBase64Data(base64EncodedText, filename);
                return d.addToPlaylist();
        }
@@ -170,7 +171,7 @@ public class ChordHelperApplet extends JApplet {
        public String getMidiDataBase64() throws IOException {
                SequenceTrackListTableModel s = sequencerModel.getSequenceTrackListTableModel();
                if( s == null ) return null;
-               Base64Dialog d = midiEditor.sequenceListTable.base64Dialog;
+               Base64Dialog d = midiEditor.playlistTable.base64Dialog;
                d.setMIDIData(s.getMIDIdata());
                return d.getBase64Data();
        }
@@ -265,7 +266,7 @@ public class ChordHelperApplet extends JApplet {
         */
        public static class VersionInfo {
                public static final String NAME = "MIDI Chord Helper";
-               public static final String VERSION = "Ver.20170419.1";
+               public static final String VERSION = "Ver.20170421.1";
                public static final String COPYRIGHT = "Copyright (C) 2004-2017";
                public static final String AUTHER = "@きよし - Akiyoshi Kamide";
                public static final String URL = "http://www.yk.rim.or.jp/~kamide/music/chordhelper/";
@@ -360,21 +361,24 @@ public class ChordHelperApplet extends JApplet {
                        ));
                        keyboardCenterPanel.keyboard.setPreferredSize(new Dimension(571, 80));
                }};
-               // MIDIã\83\87ã\83\90ã\82¤ã\82¹ã\81¨MIDIã\82¨ã\83\87ã\82£ã\82¿ã\81®ã\82»ã\83\83ã\83\88ã\82¢ã\83\83ã\83\97
+               // MIDIã\83\87ã\83\90ã\82¤ã\82¹ã\83\84ã\83ªã\83¼ã\81®æ§\8bç¯\89
                VirtualMidiDevice guiMidiDevice = keyboardPanel.keyboardCenterPanel.keyboard.midiDevice;
                deviceTreeModel = new MidiDeviceTreeModel(guiMidiDevice);
-               sequencerModel = deviceTreeModel.getSequencerModel();
-               playlistModel = new PlaylistTableModel(sequencerModel);
+               //
+               // MIDIデバイスツリーを操作するダイアログの構築
                MidiDeviceDialog midiDeviceDialog = new MidiDeviceDialog(deviceTreeModel);
                midiDeviceDialog.setIconImage(iconImage);
-               midiEditor = new MidiSequenceEditorDialog(playlistModel, guiMidiDevice, midiDeviceDialog.getOpenAction());
-               midiEditor.setIconImage(iconImage);
                //
-               // メイン画面へのMIDIファイルのドラッグ&ドロップ受付開始
-               setTransferHandler(midiEditor.transferHandler);
+               // MIDIイベントダイアログの構築
+               MidiEventDialog eventDialog = new MidiEventDialog();
+               keyboardPanel.setEventDialog(eventDialog);
                //
-               // MIDIエディタのイベントダイアログを、ピアノ鍵盤のイベント送出ダイアログと共用
-               keyboardPanel.setEventDialog(midiEditor.eventListTable.eventDialog);
+               // MIDIエディタダイアログの構築・MIDIファイルのドロップ受付開始
+               sequencerModel = deviceTreeModel.getSequencerModel();
+               playlistModel = new PlaylistTableModel(sequencerModel);
+               midiEditor = new MidiSequenceEditorDialog(playlistModel, eventDialog, guiMidiDevice, midiDeviceDialog.getOpenAction());
+               midiEditor.setIconImage(iconImage);
+               setTransferHandler(midiEditor.transferHandler);
                //
                // 歌詞表示/コード入力フィールド
                (lyricDisplay = new ChordTextField(sequencerModel)).addActionListener(
index 3466733..2cc14c3 100644 (file)
@@ -37,13 +37,13 @@ import camidion.chordhelper.mididevice.VirtualMidiDevice;
  */
 public class MidiEventTable extends JTable {
        /**
-        * 操作音を鳴らすMIDI出力デバイス
+        * MIDIイベント入力ダイアログ(イベント入力とイベント送出で共用)
         */
-       private VirtualMidiDevice outputMidiDevice;
+       public MidiEventDialog eventDialog;
        /**
-        * MIDIイベント入力ダイアログ(イベント入力とイベント送出で共用)
+        * 操作音を鳴らすMIDI出力デバイス
         */
-       public MidiEventDialog eventDialog = new MidiEventDialog();
+       private VirtualMidiDevice outputMidiDevice;
        /**
         * 新しいイベントリストテーブルを構築します。
         * <p>データモデルとして一つのトラックのイベントリストを指定できます。
@@ -52,11 +52,19 @@ public class MidiEventTable extends JTable {
         * </p>
         *
         * @param model トラック(イベントリスト)データモデル
+        * @param eventDialog MIDIイベントダイアログ
         * @param outputMidiDevice 操作音出力先MIDIデバイス
         */
-       public MidiEventTable(TrackEventListTableModel model, VirtualMidiDevice outputMidiDevice) {
+       public MidiEventTable(TrackEventListTableModel model, MidiEventDialog eventDialog, VirtualMidiDevice outputMidiDevice) {
                super(model, null, model.getSelectionModel());
                this.outputMidiDevice = outputMidiDevice;
+               this.eventDialog = eventDialog;
+               pairNoteOnOffModel = new JToggleButton.ToggleButtonModel() {
+                       {
+                               addItemListener(e->eventDialog.midiMessageForm.durationForm.setEnabled(isSelected()));
+                               setSelected(true);
+                       }
+               };
                //
                // 列モデルにセルエディタを設定
                eventCellEditor = new MidiEventCellEditor();
@@ -77,16 +85,13 @@ public class MidiEventTable extends JTable {
         */
        @Override
        public TrackEventListTableModel getModel() {
-               return (TrackEventListTableModel) super.getModel();
+               return (TrackEventListTableModel) dataModel;
        }
-       public void updateTo(SequenceTrackListTableModel sequenceModel) {
-               titleLabel.updateTrackNumber(sequenceModel.getSelectionModel().getMinSelectionIndex());
-               TrackEventListTableModel oldTrackModel = getModel();
-               TrackEventListTableModel newTrackModel = sequenceModel.getSelectedTrackModel();
-               if( oldTrackModel == newTrackModel )
-                       return;
-               if( newTrackModel == null ) {
-                       newTrackModel = getModel().getParent().getParent().emptyEventListTableModel;
+       public void setModel(TrackEventListTableModel model) {
+               TrackEventListTableModel oldModel = getModel();
+               if( oldModel == model ) return;
+               if( model == null ) {
+                       model = getModel().getParent().getParent().emptyEventListTableModel;
                        queryJumpEventAction.setEnabled(false);
                        queryAddEventAction.setEnabled(false);
 
@@ -99,10 +104,10 @@ public class MidiEventTable extends JTable {
                        queryJumpEventAction.setEnabled(true);
                        queryAddEventAction.setEnabled(true);
                }
-               oldTrackModel.getSelectionModel().removeListSelectionListener(eventSelectionListener);
-               setModel(newTrackModel);
-               setSelectionModel(newTrackModel.getSelectionModel());
-               newTrackModel.getSelectionModel().addListSelectionListener(eventSelectionListener);
+               oldModel.getSelectionModel().removeListSelectionListener(eventSelectionListener);
+               super.setModel(model);
+               setSelectionModel(model.getSelectionModel());
+               model.getSelectionModel().addListSelectionListener(eventSelectionListener);
        }
        /**
         * タイトルラベル
@@ -112,10 +117,10 @@ public class MidiEventTable extends JTable {
         * 親テーブルの選択トラックの変更に反応する
         * トラック番号つきタイトルラベル
         */
-       private class TitleLabel extends JLabel {
+       class TitleLabel extends JLabel {
                private static final String TITLE = "MIDI Events";
                private TitleLabel() { super(TITLE); }
-               private void updateTrackNumber(int index) {
+               void updateTrackNumber(int index) {
                        String text = TITLE;
                        if( index >= 0 ) text = String.format(TITLE+" - track #%d", index);
                        setText(text);
@@ -182,13 +187,7 @@ public class MidiEventTable extends JTable {
        /**
         * Pair noteON/OFF トグルボタンモデル
         */
-       JToggleButton.ToggleButtonModel
-               pairNoteOnOffModel = new JToggleButton.ToggleButtonModel() {
-                       {
-                               addItemListener(e->eventDialog.midiMessageForm.durationForm.setEnabled(isSelected()));
-                               setSelected(true);
-                       }
-               };
+       JToggleButton.ToggleButtonModel pairNoteOnOffModel;
        private class EventEditContext {
                /**
                 * 編集対象トラック
index 14009f4..59ae872 100644 (file)
@@ -6,7 +6,6 @@ import java.awt.FlowLayout;
 import java.awt.datatransfer.DataFlavor;
 import java.awt.event.ActionEvent;
 import java.io.File;
-import java.util.Arrays;
 import java.util.List;
 
 import javax.sound.midi.Sequencer;
@@ -14,39 +13,29 @@ import javax.swing.AbstractAction;
 import javax.swing.Action;
 import javax.swing.Box;
 import javax.swing.BoxLayout;
-import javax.swing.DefaultCellEditor;
 import javax.swing.Icon;
 import javax.swing.JButton;
 import javax.swing.JCheckBox;
 import javax.swing.JComboBox;
-import javax.swing.JComponent;
 import javax.swing.JDialog;
 import javax.swing.JLabel;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
 import javax.swing.JSplitPane;
-import javax.swing.JTable;
-import javax.swing.ListSelectionModel;
 import javax.swing.TransferHandler;
 import javax.swing.border.EtchedBorder;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
-import javax.swing.event.TableModelEvent;
-import javax.swing.table.TableCellEditor;
-import javax.swing.table.TableColumnModel;
 
 import camidion.chordhelper.ButtonIcon;
 import camidion.chordhelper.ChordHelperApplet;
 import camidion.chordhelper.mididevice.MidiSequencerModel;
 import camidion.chordhelper.mididevice.VirtualMidiDevice;
-import camidion.chordhelper.music.MIDISpec;
 
 /**
  * MIDIエディタ(MIDI Editor/Playlist for MIDI Chord Helper)
  *
  * @author
- *     Copyright (C) 2006-2016 Akiyoshi Kamide
+ *     Copyright (C) 2006-2017 Akiyoshi Kamide
  *     http://www.yk.rim.or.jp/~kamide/music/chordhelper/
  */
 public class MidiSequenceEditorDialog extends JDialog {
@@ -94,7 +83,7 @@ public class MidiSequenceEditorDialog extends JDialog {
         * @return プレイリストモデル
         */
        public PlaylistTableModel getPlaylistModel() {
-               return sequenceListTable.getModel();
+               return playlistTable.getModel();
        }
        /**
         * 指定されたリストに格納されたMIDIファイルを読み込んで再生します。
@@ -102,7 +91,7 @@ public class MidiSequenceEditorDialog extends JDialog {
         * @param fileList 読み込むMIDIファイルのリスト
         */
        public void play(List<File> fileList) {
-               play(sequenceListTable.add(fileList));
+               play(playlistTable.add(fileList));
        }
        /**
         * 指定されたインデックス値(先頭が0)のMIDIシーケンスから再生します。
@@ -128,169 +117,18 @@ public class MidiSequenceEditorDialog extends JDialog {
        /**
         * プレイリストビュー(シーケンスリスト)
         */
-       public PlaylistTable sequenceListTable;
-       /**
-        * MIDIトラックリストテーブルビュー(選択中のシーケンスの中身)
-        */
-       private SequenceTrackListTable trackListTable;
-       /**
-        * MIDIイベントリストテーブルビュー(選択中のトラックの中身)
-        */
-       public MidiEventTable eventListTable;
-       /**
-        * シーケンス(トラックリスト)テーブルビュー
-        */
-       public class SequenceTrackListTable extends JTable {
-               /**
-                * トラックリストテーブルビューを構築します。
-                * @param model シーケンス(トラックリスト)データモデル
-                */
-               public SequenceTrackListTable(SequenceTrackListTableModel model) {
-                       super(model, null, model.getSelectionModel());
-                       //
-                       // 録音対象のMIDIチャンネルをコンボボックスで選択できるようにする
-                       getColumnModel()
-                               .getColumn(SequenceTrackListTableModel.Column.RECORD_CHANNEL.ordinal())
-                               .setCellEditor(new DefaultCellEditor(new JComboBox<String>(){{
-                                       addItem("OFF");
-                                       for(int i=1; i <= MIDISpec.MAX_CHANNELS; i++) addItem(String.format("%d", i));
-                                       addItem("ALL");
-                               }}));
-                       setAutoCreateColumnsFromModel(false);
-                       model.getParent().sequenceListSelectionModel.addListSelectionListener(titleLabel);
-                       TableColumnModel colModel = getColumnModel();
-                       Arrays.stream(SequenceTrackListTableModel.Column.values()).forEach(c->
-                               colModel.getColumn(c.ordinal()).setPreferredWidth(c.preferredWidth)
-                       );
-               }
-               /**
-                * このテーブルビューが表示するデータを提供する
-                * シーケンス(トラックリスト)データモデルを返します。
-                * @return シーケンス(トラックリスト)データモデル
-                */
-               @Override
-               public SequenceTrackListTableModel getModel() {
-                       return (SequenceTrackListTableModel)dataModel;
-               }
-               /**
-                * タイトルラベル
-                */
-               TitleLabel titleLabel = new TitleLabel();
-               /**
-                * 親テーブルの選択シーケンスの変更に反応する
-                * 曲番号表示付きタイトルラベル
-                */
-               private class TitleLabel extends JLabel implements ListSelectionListener {
-                       private static final String TITLE = "Tracks";
-                       public TitleLabel() { setText(TITLE); }
-                       @Override
-                       public void valueChanged(ListSelectionEvent event) {
-                               if( event.getValueIsAdjusting() ) return;
-                               SequenceTrackListTableModel oldModel = getModel();
-                               SequenceTrackListTableModel newModel = oldModel.getParent().getSelectedSequenceModel();
-                               if( oldModel == newModel ) return;
-                               //
-                               // MIDIチャンネル選択中のときはキャンセルする
-                               cancelCellEditing();
-                               //
-                               String text = TITLE;
-                               ListSelectionModel sm = oldModel.getParent().sequenceListSelectionModel;
-                               if( ! sm.isSelectionEmpty() ) {
-                                       int index = sm.getMinSelectionIndex();
-                                       if( index >= 0 ) text = String.format(text+" - MIDI file #%d", index);
-                               }
-                               setText(text);
-                               if( newModel == null ) {
-                                       newModel = oldModel.getParent().emptyTrackListTableModel;
-                                       addTrackAction.setEnabled(false);
-                               }
-                               else {
-                                       addTrackAction.setEnabled(true);
-                               }
-                               oldModel.getSelectionModel().removeListSelectionListener(trackSelectionListener);
-                               setModel(newModel);
-                               setSelectionModel(newModel.getSelectionModel());
-                               newModel.getSelectionModel().addListSelectionListener(trackSelectionListener);
-                               trackSelectionListener.valueChanged(null);
-                       }
-               }
-               /**
-                * トラック選択リスナー
-                */
-               ListSelectionListener trackSelectionListener = new ListSelectionListener() {
-                       @Override
-                       public void valueChanged(ListSelectionEvent e) {
-                               if( e != null && e.getValueIsAdjusting() ) return;
-                               ListSelectionModel selModel = getModel().getSelectionModel();
-                               deleteTrackAction.setEnabled(! selModel.isSelectionEmpty());
-                               eventListTable.updateTo(getModel());
-                       }
-               };
-               /**
-                * {@inheritDoc}
-                *
-                * <p>このトラックリストテーブルのデータが変わったときに編集を解除します。
-                * 例えば、イベントが編集された場合や、
-                * シーケンサーからこのモデルが外された場合がこれに該当します。
-                * </p>
-                */
-               @Override
-               public void tableChanged(TableModelEvent e) {
-                       super.tableChanged(e);
-                       cancelCellEditing();
-               }
-               /**
-                * このトラックリストテーブルが編集モードになっていたら解除します。
-                */
-               private void cancelCellEditing() {
-                       TableCellEditor currentCellEditor = getCellEditor();
-                       if( currentCellEditor != null ) currentCellEditor.cancelCellEditing();
-               }
-               /**
-                * トラック追加アクション
-                */
-               Action addTrackAction = new AbstractAction("New") {
-                       {
-                               String tooltip = "Append new track - 新しいトラックの追加";
-                               putValue(Action.SHORT_DESCRIPTION, tooltip);
-                               setEnabled(false);
-                       }
-                       @Override
-                       public void actionPerformed(ActionEvent e) { getModel().createTrack(); }
-               };
-               /**
-                * トラック削除アクション
-                */
-               Action deleteTrackAction = new AbstractAction("Delete", deleteIcon) {
-                       public static final String CONFIRM_MESSAGE =
-                                       "Do you want to delete selected track ?\n選択したトラックを削除しますか?";
-                       {
-                               putValue(Action.SHORT_DESCRIPTION, "Delete selected track - 選択したトラックを削除");
-                               setEnabled(false);
-                       }
-                       @Override
-                       public void actionPerformed(ActionEvent event) {
-                               if( JOptionPane.showConfirmDialog(
-                                               ((JComponent)event.getSource()).getRootPane(),
-                                               CONFIRM_MESSAGE,
-                                               ChordHelperApplet.VersionInfo.NAME,
-                                               JOptionPane.YES_NO_OPTION,
-                                               JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION
-                               ) getModel().deleteSelectedTracks();
-                       }
-               };
-       }
-
+       public PlaylistTable playlistTable;
        /**
         * 新しい {@link MidiSequenceEditorDialog} を構築します。
         * @param playlistTableModel このエディタが参照するプレイリストモデル
+        * @param eventDialog MIDIイベント入力ダイアログ
         * @param outputMidiDevice イベントテーブルの操作音出力先MIDIデバイス
         * @param midiDeviceDialogOpenAction MIDIデバイスダイアログを開くアクション
         */
-       public MidiSequenceEditorDialog(PlaylistTableModel playlistTableModel, VirtualMidiDevice outputMidiDevice, Action midiDeviceDialogOpenAction) {
-               sequenceListTable = new PlaylistTable(playlistTableModel, midiDeviceDialogOpenAction);
-               trackListTable = new SequenceTrackListTable(playlistTableModel.emptyTrackListTableModel);
-               eventListTable = new MidiEventTable(playlistTableModel.emptyEventListTableModel, outputMidiDevice);
+       public MidiSequenceEditorDialog(PlaylistTableModel playlistTableModel, MidiEventDialog eventDialog, VirtualMidiDevice outputMidiDevice, Action midiDeviceDialogOpenAction) {
+               playlistTable = new PlaylistTable(playlistTableModel, midiDeviceDialogOpenAction);
+               MidiEventTable eventListTable = new MidiEventTable(playlistTableModel.emptyEventListTableModel, eventDialog, outputMidiDevice);
+               SequenceTrackListTable trackListTable = new SequenceTrackListTable(playlistTableModel.emptyTrackListTableModel, eventListTable);
                newSequenceDialog = new NewSequenceDialog(playlistTableModel, outputMidiDevice);
                setTitle("MIDI Editor/Playlist - "+ChordHelperApplet.VersionInfo.NAME);
                setBounds( 150, 200, 900, 500 );
@@ -305,15 +143,15 @@ public class MidiSequenceEditorDialog extends JDialog {
                                add(new JButton(newSequenceDialog.openAction) {
                                        { setMargin(ChordHelperApplet.ZERO_INSETS); }
                                });
-                               if( sequenceListTable.midiFileChooser != null ) {
+                               if( playlistTable.midiFileChooser != null ) {
                                        add( Box.createRigidArea(new Dimension(5, 0)) );
-                                       add(new JButton(sequenceListTable.midiFileChooser.openMidiFileAction) {
+                                       add(new JButton(playlistTable.midiFileChooser.openMidiFileAction) {
                                                { setMargin(ChordHelperApplet.ZERO_INSETS); }
                                        });
                                }
-                               if(sequenceListTable.base64EncodeAction != null) {
+                               if(playlistTable.base64EncodeAction != null) {
                                        add(Box.createRigidArea(new Dimension(5, 0)));
-                                       add(new JButton(sequenceListTable.base64EncodeAction) {
+                                       add(new JButton(playlistTable.base64EncodeAction) {
                                                { setMargin(ChordHelperApplet.ZERO_INSETS); }
                                        });
                                }
@@ -325,14 +163,14 @@ public class MidiSequenceEditorDialog extends JDialog {
                                add(new JButton(playlistTableModel.getMoveToBottomAction()) {
                                        { setMargin(ChordHelperApplet.ZERO_INSETS); }
                                });
-                               if( sequenceListTable.midiFileChooser != null ) {
+                               if( playlistTable.midiFileChooser != null ) {
                                        add(Box.createRigidArea(new Dimension(5, 0)));
-                                       add(new JButton(sequenceListTable.midiFileChooser.saveMidiFileAction) {
+                                       add(new JButton(playlistTable.midiFileChooser.saveMidiFileAction) {
                                                { setMargin(ChordHelperApplet.ZERO_INSETS); }
                                        });
                                }
                                add( Box.createRigidArea(new Dimension(5, 0)) );
-                               add(new JButton(sequenceListTable.deleteSequenceAction) {
+                               add(new JButton(playlistTable.deleteSequenceAction) {
                                        { setMargin(ChordHelperApplet.ZERO_INSETS); }
                                });
                                add( Box.createRigidArea(new Dimension(5, 0)) );
@@ -348,7 +186,7 @@ public class MidiSequenceEditorDialog extends JDialog {
                                }});
                        }};
                        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
-                       add(new JScrollPane(sequenceListTable));
+                       add(new JScrollPane(playlistTable));
                        add(Box.createRigidArea(new Dimension(0, 10)));
                        add(playlistOperationPanel);
                        add(Box.createRigidArea(new Dimension(0, 10)));
index 203540b..148ccaf 100644 (file)
@@ -55,6 +55,7 @@ public class PlaylistTable extends JTable {
        /**
         * プレイリストビューを構築します。
         * @param model プレイリストデータモデル
+        * @param midiDeviceDialogOpenAction MIDIデバイスダイアログを開くアクション
         */
        public PlaylistTable(PlaylistTableModel model, Action midiDeviceDialogOpenAction) {
                super(model, null, model.sequenceListSelectionModel);
@@ -72,11 +73,10 @@ public class PlaylistTable extends JTable {
                new PositionCellEditor();
                //
                // 文字コード選択をプルダウンにする
-               int column = PlaylistTableModel.Column.CHARSET.ordinal();
-               TableCellEditor ce = new DefaultCellEditor(new JComboBox<Charset>() {{
-                       Charset.availableCharsets().values().stream().forEach(v->addItem(v));
-               }});
-               getColumnModel().getColumn(column).setCellEditor(ce);
+               getColumnModel().getColumn(PlaylistTableModel.Column.CHARSET.ordinal())
+                       .setCellEditor(new DefaultCellEditor(new JComboBox<Charset>() {{
+                               Charset.availableCharsets().values().stream().forEach(v->addItem(v));
+                       }}));
                setAutoCreateColumnsFromModel(false);
                //
                // Base64画面を開くアクションの生成
diff --git a/src/camidion/chordhelper/midieditor/SequenceTrackListTable.java b/src/camidion/chordhelper/midieditor/SequenceTrackListTable.java
new file mode 100644 (file)
index 0000000..d093840
--- /dev/null
@@ -0,0 +1,169 @@
+package camidion.chordhelper.midieditor;
+
+import java.awt.event.ActionEvent;
+import java.util.Arrays;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.DefaultCellEditor;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JTable;
+import javax.swing.ListSelectionModel;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.event.TableModelEvent;
+import javax.swing.table.TableCellEditor;
+import javax.swing.table.TableColumnModel;
+
+import camidion.chordhelper.ChordHelperApplet;
+import camidion.chordhelper.music.MIDISpec;
+
+/**
+ * シーケンス(トラックリスト)テーブルビュー
+ */
+public class SequenceTrackListTable extends JTable {
+       /**
+        * MIDIイベントリストテーブルビュー(選択中のトラックの中身)
+        */
+       public MidiEventTable eventListTable;
+       /**
+        * トラックリストテーブルビューを構築します。
+        * @param model シーケンス(トラックリスト)データモデル
+        * @param eventListTable イベントリストテーブル
+        */
+       public SequenceTrackListTable(SequenceTrackListTableModel model, MidiEventTable eventListTable) {
+               super(model, null, model.getSelectionModel());
+               this.eventListTable = eventListTable;
+               //
+               // 録音対象のMIDIチャンネルをコンボボックスで選択できるようにする
+               getColumnModel()
+                       .getColumn(SequenceTrackListTableModel.Column.RECORD_CHANNEL.ordinal())
+                       .setCellEditor(new DefaultCellEditor(new JComboBox<String>(){{
+                               addItem("OFF");
+                               for(int i=1; i <= MIDISpec.MAX_CHANNELS; i++) addItem(String.format("%d", i));
+                               addItem("ALL");
+                       }}));
+               setAutoCreateColumnsFromModel(false);
+               model.getParent().sequenceListSelectionModel.addListSelectionListener(titleLabel);
+               TableColumnModel colModel = getColumnModel();
+               Arrays.stream(SequenceTrackListTableModel.Column.values()).forEach(c->
+                       colModel.getColumn(c.ordinal()).setPreferredWidth(c.preferredWidth)
+               );
+       }
+       /**
+        * このテーブルビューが表示するデータを提供する
+        * シーケンス(トラックリスト)データモデルを返します。
+        * @return シーケンス(トラックリスト)データモデル
+        */
+       @Override
+       public SequenceTrackListTableModel getModel() {
+               return (SequenceTrackListTableModel)dataModel;
+       }
+       /**
+        * タイトルラベル
+        */
+       TitleLabel titleLabel = new TitleLabel();
+       /**
+        * 親テーブルの選択シーケンスの変更に反応する
+        * 曲番号表示付きタイトルラベル
+        */
+       private class TitleLabel extends JLabel implements ListSelectionListener {
+               private static final String TITLE = "Tracks";
+               public TitleLabel() { setText(TITLE); }
+               @Override
+               public void valueChanged(ListSelectionEvent event) {
+                       if( event.getValueIsAdjusting() ) return;
+                       SequenceTrackListTableModel oldModel = getModel();
+                       SequenceTrackListTableModel newModel = oldModel.getParent().getSelectedSequenceModel();
+                       if( oldModel == newModel ) return;
+                       //
+                       // MIDIチャンネル選択中のときはキャンセルする
+                       cancelCellEditing();
+                       //
+                       String text = TITLE;
+                       ListSelectionModel sm = oldModel.getParent().sequenceListSelectionModel;
+                       if( ! sm.isSelectionEmpty() ) {
+                               int index = sm.getMinSelectionIndex();
+                               if( index >= 0 ) text = String.format(text+" - MIDI file #%d", index);
+                       }
+                       setText(text);
+                       if( newModel == null ) {
+                               newModel = oldModel.getParent().emptyTrackListTableModel;
+                               addTrackAction.setEnabled(false);
+                       }
+                       else {
+                               addTrackAction.setEnabled(true);
+                       }
+                       oldModel.getSelectionModel().removeListSelectionListener(trackSelectionListener);
+                       setModel(newModel);
+                       setSelectionModel(newModel.getSelectionModel());
+                       newModel.getSelectionModel().addListSelectionListener(trackSelectionListener);
+               }
+       }
+       /**
+        * {@inheritDoc}
+        *
+        * <p>このトラックリストテーブルのデータが変わったときに編集を解除します。
+        * 例えば、イベントが編集された場合や、
+        * シーケンサーからこのモデルが外された場合がこれに該当します。
+        * </p>
+        */
+       @Override
+       public void tableChanged(TableModelEvent e) {
+               super.tableChanged(e);
+               cancelCellEditing();
+       }
+       /**
+        * このトラックリストテーブルが編集モードになっていたら解除します。
+        */
+       private void cancelCellEditing() {
+               TableCellEditor currentCellEditor = getCellEditor();
+               if( currentCellEditor != null ) currentCellEditor.cancelCellEditing();
+       }
+       /**
+        * トラック追加アクション
+        */
+       Action addTrackAction = new AbstractAction("New") {
+               {
+                       String tooltip = "Append new track - 新しいトラックの追加";
+                       putValue(Action.SHORT_DESCRIPTION, tooltip);
+                       setEnabled(false);
+               }
+               @Override
+               public void actionPerformed(ActionEvent e) { getModel().createTrack(); }
+       };
+       /**
+        * トラック削除アクション
+        */
+       Action deleteTrackAction = new AbstractAction("Delete", MidiSequenceEditorDialog.deleteIcon) {
+               public static final String CONFIRM_MESSAGE =
+                               "Do you want to delete selected track ?\n選択したトラックを削除しますか?";
+               {
+                       putValue(Action.SHORT_DESCRIPTION, "Delete selected track - 選択したトラックを削除");
+                       setEnabled(false);
+               }
+               @Override
+               public void actionPerformed(ActionEvent event) {
+                       if( JOptionPane.showConfirmDialog(
+                                       ((JComponent)event.getSource()).getRootPane(),
+                                       CONFIRM_MESSAGE,
+                                       ChordHelperApplet.VersionInfo.NAME,
+                                       JOptionPane.YES_NO_OPTION,
+                                       JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION
+                       ) getModel().deleteSelectedTracks();
+               }
+       };
+       /**
+        * トラック選択リスナー
+        */
+       private ListSelectionListener trackSelectionListener = event->{
+               if( event.getValueIsAdjusting() ) return;
+               ListSelectionModel selModel = getModel().getSelectionModel();
+               deleteTrackAction.setEnabled(! selModel.isSelectionEmpty());
+               eventListTable.titleLabel.updateTrackNumber(selModel.getMinSelectionIndex());
+               eventListTable.setModel(getModel().getSelectedTrackModel());
+       };
+}
\ No newline at end of file