OSDN Git Service

MIDIEditor クラスの大文字小文字違いがWindows7で同一扱いされたためか、コミットが不完全になったため、クラス名をMidiSequenceEditorに変更
authorAkiyoshi Kamide <kamide@yk.rim.or.jp>
Sun, 13 Apr 2014 12:25:29 +0000 (12:25 +0000)
committerAkiyoshi Kamide <kamide@yk.rim.or.jp>
Sun, 13 Apr 2014 12:25:29 +0000 (12:25 +0000)
git-svn-id: https://svn.sourceforge.jp/svnroot/midichordhelper/MIDIChordHelper@37 302f1594-2db2-43b1-aaa4-6307b5a2a2de

src/camidion/chordhelper/mididevice/MidiDeviceModelList.java
src/camidion/chordhelper/midieditor/Base64Dialog.java
src/camidion/chordhelper/midieditor/MIDIEditor.java [deleted file]
src/camidion/chordhelper/midieditor/MidiSequenceEditor.java [moved from src/camidion/chordhelper/midieditor/MidiEditor.java with 96% similarity]
src/camidion/chordhelper/midieditor/NewSequenceDialog.java

index d5e7cda..8d01451 100644 (file)
@@ -10,7 +10,7 @@ import javax.sound.midi.Sequencer;
 import javax.sound.midi.Synthesizer;\r
 \r
 import camidion.chordhelper.ChordHelperApplet;\r
-import camidion.chordhelper.midieditor.MidiEditor;\r
+import camidion.chordhelper.midieditor.MidiSequenceEditor;\r
 \r
 /**\r
  * MIDIデバイスモデルリスト\r
@@ -19,7 +19,7 @@ public class MidiDeviceModelList extends Vector<MidiConnecterListModel> {
        /**\r
         * MIDIエディタ\r
         */\r
-       public MidiEditor editorDialog;\r
+       public MidiSequenceEditor editorDialog;\r
        /**\r
         * MIDIエディタモデル\r
         */\r
@@ -53,7 +53,7 @@ public class MidiDeviceModelList extends Vector<MidiConnecterListModel> {
                        );\r
                        e.printStackTrace();\r
                }\r
-               editorDialog = new MidiEditor(sequencerModel);\r
+               editorDialog = new MidiSequenceEditor(sequencerModel);\r
                editorDialogModel = addMidiDevice(editorDialog.getVirtualMidiDevice());\r
                for( MidiDevice.Info info : devInfos ) {\r
                        MidiDevice device;\r
index 97f3c36..7710866 100644 (file)
@@ -27,7 +27,7 @@ import camidion.chordhelper.ChordHelperApplet;
  */\r
 public class Base64Dialog extends JDialog {\r
        private Base64TextArea base64TextArea = new Base64TextArea(8,56);\r
-       private MidiEditor midiEditor;\r
+       private MidiSequenceEditor midiEditor;\r
        /**\r
         * Base64デコードアクション\r
         */\r
@@ -102,7 +102,7 @@ public class Base64Dialog extends JDialog {
         * Base64テキスト入力ダイアログを構築します。\r
         * @param midiEditor 親画面となるMIDIエディタ\r
         */\r
-       public Base64Dialog(MidiEditor midiEditor) {\r
+       public Base64Dialog(MidiSequenceEditor midiEditor) {\r
                this.midiEditor = midiEditor;\r
                setTitle("Base64-encoded MIDI sequence - " + ChordHelperApplet.VersionInfo.NAME);\r
                try {\r
diff --git a/src/camidion/chordhelper/midieditor/MIDIEditor.java b/src/camidion/chordhelper/midieditor/MIDIEditor.java
deleted file mode 100644 (file)
index f5a9367..0000000
+++ /dev/null
@@ -1,1356 +0,0 @@
-package camidion.chordhelper.midieditor;\r
-\r
-import java.awt.Component;\r
-import java.awt.Container;\r
-import java.awt.Dimension;\r
-import java.awt.FlowLayout;\r
-import java.awt.Insets;\r
-import java.awt.datatransfer.DataFlavor;\r
-import java.awt.datatransfer.Transferable;\r
-import java.awt.dnd.DnDConstants;\r
-import java.awt.dnd.DropTarget;\r
-import java.awt.dnd.DropTargetDragEvent;\r
-import java.awt.dnd.DropTargetDropEvent;\r
-import java.awt.dnd.DropTargetEvent;\r
-import java.awt.dnd.DropTargetListener;\r
-import java.awt.event.ActionEvent;\r
-import java.awt.event.ComponentAdapter;\r
-import java.awt.event.ComponentEvent;\r
-import java.awt.event.ComponentListener;\r
-import java.awt.event.ItemEvent;\r
-import java.awt.event.ItemListener;\r
-import java.awt.event.MouseEvent;\r
-import java.io.File;\r
-import java.io.FileOutputStream;\r
-import java.io.IOException;\r
-import java.nio.charset.Charset;\r
-import java.security.AccessControlException;\r
-import java.util.EventObject;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.Set;\r
-\r
-import javax.sound.midi.InvalidMidiDataException;\r
-import javax.sound.midi.MidiChannel;\r
-import javax.sound.midi.MidiEvent;\r
-import javax.sound.midi.MidiMessage;\r
-import javax.sound.midi.Sequencer;\r
-import javax.sound.midi.ShortMessage;\r
-import javax.swing.AbstractAction;\r
-import javax.swing.AbstractCellEditor;\r
-import javax.swing.Action;\r
-import javax.swing.Box;\r
-import javax.swing.BoxLayout;\r
-import javax.swing.DefaultCellEditor;\r
-import javax.swing.Icon;\r
-import javax.swing.JButton;\r
-import javax.swing.JCheckBox;\r
-import javax.swing.JComboBox;\r
-import javax.swing.JDialog;\r
-import javax.swing.JFileChooser;\r
-import javax.swing.JLabel;\r
-import javax.swing.JOptionPane;\r
-import javax.swing.JPanel;\r
-import javax.swing.JScrollPane;\r
-import javax.swing.JSplitPane;\r
-import javax.swing.JTable;\r
-import javax.swing.JToggleButton;\r
-import javax.swing.ListSelectionModel;\r
-import javax.swing.event.ListSelectionEvent;\r
-import javax.swing.event.ListSelectionListener;\r
-import javax.swing.event.TableModelEvent;\r
-import javax.swing.filechooser.FileFilter;\r
-import javax.swing.filechooser.FileNameExtensionFilter;\r
-import javax.swing.table.JTableHeader;\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
-import camidion.chordhelper.ButtonIcon;\r
-import camidion.chordhelper.ChordHelperApplet;\r
-import camidion.chordhelper.mididevice.AbstractVirtualMidiDevice;\r
-import camidion.chordhelper.mididevice.MidiSequencerModel;\r
-import camidion.chordhelper.mididevice.VirtualMidiDevice;\r
-import camidion.chordhelper.music.MIDISpec;\r
-\r
-/**\r
- * MIDIエディタ(MIDI Editor/Playlist for MIDI Chord Helper)\r
- *\r
- * @author\r
- *     Copyright (C) 2006-2014 Akiyoshi Kamide\r
- *     http://www.yk.rim.or.jp/~kamide/music/chordhelper/\r
- */\r
-public class MIDIEditor extends JDialog implements DropTargetListener {\r
-       private static VirtualMidiDevice virtualMidiDevice = new AbstractVirtualMidiDevice() {\r
-               {\r
-                       info = new MyInfo();\r
-                       setMaxReceivers(0); // 送信専用とする(MIDI IN はサポートしない)\r
-               }\r
-               /**\r
-                * MIDIデバイス情報\r
-                */\r
-               protected MyInfo info;\r
-               @Override\r
-               public Info getDeviceInfo() {\r
-                       return info;\r
-               }\r
-               class MyInfo extends Info {\r
-                       protected MyInfo() {\r
-                               super("MIDI Editor","Unknown vendor","MIDI sequence editor","");\r
-                       }\r
-               }\r
-       };\r
-       /**\r
-        * このMIDIエディタの仮想MIDIデバイスを返します。\r
-        */\r
-       public VirtualMidiDevice getVirtualMidiDevice() {\r
-               return virtualMidiDevice;\r
-       }\r
-       /**\r
-        * このダイアログを表示するアクション\r
-        */\r
-       public Action openAction = new AbstractAction(\r
-               "Edit/Playlist/Speed", new ButtonIcon(ButtonIcon.EDIT_ICON)\r
-       ) {\r
-               {\r
-                       String tooltip = "MIDIシーケンスの編集/プレイリスト/再生速度調整";\r
-                       putValue(Action.SHORT_DESCRIPTION, tooltip);\r
-               }\r
-               @Override\r
-               public void actionPerformed(ActionEvent e) { open(); }\r
-       };\r
-       /**\r
-        * このダイアログを開きます。すでに開かれていた場合は前面に移動します。\r
-        */\r
-       public void open() {\r
-               if( isVisible() ) toFront(); else setVisible(true);\r
-       }\r
-       /**\r
-        * エラーメッセージダイアログを表示します。\r
-        * @param message エラーメッセージ\r
-        */\r
-       public void showError(String message) {\r
-               JOptionPane.showMessageDialog(\r
-                       this, message,\r
-                       ChordHelperApplet.VersionInfo.NAME,\r
-                       JOptionPane.ERROR_MESSAGE\r
-               );\r
-       }\r
-       /**\r
-        * 警告メッセージダイアログを表示します。\r
-        * @param message 警告メッセージ\r
-        */\r
-       public void showWarning(String message) {\r
-               JOptionPane.showMessageDialog(\r
-                       this, message,\r
-                       ChordHelperApplet.VersionInfo.NAME,\r
-                       JOptionPane.WARNING_MESSAGE\r
-               );\r
-       }\r
-       /**\r
-        * 確認ダイアログを表示します。\r
-        * @param message 確認メッセージ\r
-        * @return 確認OKのときtrue\r
-        */\r
-       boolean confirm(String message) {\r
-               return JOptionPane.showConfirmDialog(\r
-                       this, message,\r
-                       ChordHelperApplet.VersionInfo.NAME,\r
-                       JOptionPane.YES_NO_OPTION,\r
-                       JOptionPane.WARNING_MESSAGE\r
-               ) == JOptionPane.YES_OPTION ;\r
-       }\r
-       @Override\r
-       public void dragEnter(DropTargetDragEvent event) {\r
-               if( event.isDataFlavorSupported(DataFlavor.javaFileListFlavor) ) {\r
-                       event.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);\r
-               }\r
-       }\r
-       @Override\r
-       public void dragExit(DropTargetEvent event) {}\r
-       @Override\r
-       public void dragOver(DropTargetDragEvent event) {}\r
-       @Override\r
-       public void dropActionChanged(DropTargetDragEvent event) {}\r
-       @Override\r
-       @SuppressWarnings("unchecked")\r
-       public void drop(DropTargetDropEvent event) {\r
-               event.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);\r
-               try {\r
-                       int action = event.getDropAction();\r
-                       if ( (action & DnDConstants.ACTION_COPY_OR_MOVE) != 0 ) {\r
-                               Transferable t = event.getTransferable();\r
-                               Object data = t.getTransferData(DataFlavor.javaFileListFlavor);\r
-                               loadAndPlay((List<File>)data);\r
-                               event.dropComplete(true);\r
-                               return;\r
-                       }\r
-                       event.dropComplete(false);\r
-               }\r
-               catch (Exception ex) {\r
-                       ex.printStackTrace();\r
-                       event.dropComplete(false);\r
-               }\r
-       }\r
-       /**\r
-        * 複数のMIDIファイルを読み込み、再生されていなかったら再生します。\r
-        * すでに再生されていた場合、このエディタダイアログを表示します。\r
-        *\r
-        * @param fileList 読み込むMIDIファイルのリスト\r
-        */\r
-       public void loadAndPlay(List<File> fileList) {\r
-               int firstIndex = -1;\r
-               SequenceListTableModel playlist = sequenceListTable.getModel();\r
-               try {\r
-                       firstIndex = playlist.addSequences(fileList);\r
-               } catch(IOException|InvalidMidiDataException e) {\r
-                       showWarning(e.getMessage());\r
-               } catch(AccessControlException e) {\r
-                       showError(e.getMessage());\r
-                       e.printStackTrace();\r
-               }\r
-               if(playlist.sequencerModel.getSequencer().isRunning()) {\r
-                       open();\r
-               }\r
-               else if( firstIndex >= 0 ) {\r
-                       playlist.loadToSequencer(firstIndex);\r
-                       playlist.sequencerModel.start();\r
-               }\r
-       }\r
-       private static final Insets ZERO_INSETS = new Insets(0,0,0,0);\r
-       private static final Icon deleteIcon = new ButtonIcon(ButtonIcon.X_ICON);\r
-       /**\r
-        * 新しいMIDIシーケンスを生成するダイアログ\r
-        */\r
-       public NewSequenceDialog newSequenceDialog = new NewSequenceDialog(this);\r
-       /**\r
-        * BASE64テキスト入力ダイアログ\r
-        */\r
-       public Base64Dialog base64Dialog = new Base64Dialog(this);\r
-       /**\r
-        * プレイリストビュー(シーケンスリスト)\r
-        */\r
-       public SequenceListTable sequenceListTable;\r
-       /**\r
-        * MIDIトラックリストテーブルビュー(選択中のシーケンスの中身)\r
-        */\r
-       private TrackListTable trackListTable;\r
-       /**\r
-        * MIDIイベントリストテーブルビュー(選択中のトラックの中身)\r
-        */\r
-       private EventListTable eventListTable;\r
-       /**\r
-        * MIDIイベント入力ダイアログ(イベント入力とイベント送出で共用)\r
-        */\r
-       public MidiEventDialog  eventDialog = new MidiEventDialog();\r
-       /**\r
-        * プレイリストビュー(シーケンスリスト)\r
-        */\r
-       public class SequenceListTable extends JTable {\r
-               /**\r
-                * ファイル選択ダイアログ(アプレットでは使用不可)\r
-                */\r
-               private MidiFileChooser midiFileChooser;\r
-               /**\r
-                * BASE64エンコードアクション(ライブラリが見えている場合のみ有効)\r
-                */\r
-               private Action base64EncodeAction;\r
-               /**\r
-                * プレイリストビューを構築します。\r
-                * @param model プレイリストデータモデル\r
-                */\r
-               public SequenceListTable(SequenceListTableModel model) {\r
-                       super(model, null, model.sequenceListSelectionModel);\r
-                       try {\r
-                               midiFileChooser = new MidiFileChooser();\r
-                       }\r
-                       catch( ExceptionInInitializerError|NoClassDefFoundError|AccessControlException e ) {\r
-                               // アプレットの場合、Webクライアントマシンのローカルファイルには\r
-                               // アクセスできないので、ファイル選択ダイアログは使用不可。\r
-                               midiFileChooser = null;\r
-                       }\r
-                       // 再生ボタンを埋め込む\r
-                       new PlayButtonCellEditor();\r
-                       new PositionCellEditor();\r
-                       //\r
-                       // 文字コード選択をプルダウンにする\r
-                       int column = SequenceListTableModel.Column.CHARSET.ordinal();\r
-                       TableCellEditor ce = new DefaultCellEditor(new JComboBox<Charset>() {{\r
-                               Set<Map.Entry<String,Charset>> entrySet = Charset.availableCharsets().entrySet();\r
-                               for( Map.Entry<String,Charset> entry : entrySet ) addItem(entry.getValue());\r
-                       }});\r
-                       getColumnModel().getColumn(column).setCellEditor(ce);\r
-                       setAutoCreateColumnsFromModel(false);\r
-                       //\r
-                       // Base64エンコードアクションの生成\r
-                       if( base64Dialog.isBase64Available() ) {\r
-                               base64EncodeAction = new AbstractAction("Base64") {\r
-                                       {\r
-                                               String tooltip = "Base64 text conversion - Base64テキスト変換";\r
-                                               putValue(Action.SHORT_DESCRIPTION, tooltip);\r
-                                       }\r
-                                       @Override\r
-                                       public void actionPerformed(ActionEvent e) {\r
-                                               SequenceTrackListTableModel mstm = getModel().getSelectedSequenceModel();\r
-                                               byte[] data = null;\r
-                                               String filename = null;\r
-                                               if( mstm != null ) {\r
-                                                       data = mstm.getMIDIdata();\r
-                                                       filename = mstm.getFilename();\r
-                                               }\r
-                                               base64Dialog.setMIDIData(data, filename);\r
-                                               base64Dialog.setVisible(true);\r
-                                       }\r
-                               };\r
-                       }\r
-                       TableColumnModel colModel = getColumnModel();\r
-                       for( SequenceListTableModel.Column c : SequenceListTableModel.Column.values() ) {\r
-                               TableColumn tc = colModel.getColumn(c.ordinal());\r
-                               tc.setPreferredWidth(c.preferredWidth);\r
-                               if( c == SequenceListTableModel.Column.LENGTH ) {\r
-                                       lengthColumn = tc;\r
-                               }\r
-                       }\r
-               }\r
-               private TableColumn lengthColumn;\r
-               @Override\r
-               public void tableChanged(TableModelEvent event) {\r
-                       super.tableChanged(event);\r
-                       //\r
-                       // タイトルに合計シーケンス長を表示\r
-                       if( lengthColumn != null ) {\r
-                               int sec = getModel().getTotalSeconds();\r
-                               String title = SequenceListTableModel.Column.LENGTH.title;\r
-                               title = String.format(title+" [%02d:%02d]", sec/60, sec%60);\r
-                               lengthColumn.setHeaderValue(title);\r
-                       }\r
-                       //\r
-                       // シーケンス削除時など、合計シーケンス長が変わっても\r
-                       // 列モデルからではヘッダタイトルが再描画されないことがある。\r
-                       // そこで、ヘッダビューから repaint() で突っついて再描画させる。\r
-                       JTableHeader th = getTableHeader();\r
-                       if( th != null ) {\r
-                               th.repaint();\r
-                       }\r
-               }\r
-               /**\r
-                * 時間位置表示セルエディタ(ダブルクリック専用)\r
-                */\r
-               private class PositionCellEditor extends AbstractCellEditor\r
-                       implements TableCellEditor\r
-               {\r
-                       public PositionCellEditor() {\r
-                               int column = SequenceListTableModel.Column.POSITION.ordinal();\r
-                               TableColumn tc = getColumnModel().getColumn(column);\r
-                               tc.setCellEditor(this);\r
-                       }\r
-                       /**\r
-                        * セルをダブルクリックしたときだけ編集モードに入るようにします。\r
-                        * @param e イベント(マウスイベント)\r
-                        * @return 編集可能になったらtrue\r
-                        */\r
-                       @Override\r
-                       public boolean isCellEditable(EventObject e) {\r
-                               // マウスイベント以外のイベントでは編集不可\r
-                               if( ! (e instanceof MouseEvent) ) return false;\r
-                               return ((MouseEvent)e).getClickCount() == 2;\r
-                       }\r
-                       @Override\r
-                       public Object getCellEditorValue() { return null; }\r
-                       /**\r
-                        * 編集モード時のコンポーネントを返すタイミングで\r
-                        * そのシーケンスをシーケンサーにロードしたあと、\r
-                        * すぐに編集モードを解除します。\r
-                        * @return 常にnull\r
-                        */\r
-                       @Override\r
-                       public Component getTableCellEditorComponent(\r
-                               JTable table, Object value, boolean isSelected,\r
-                               int row, int column\r
-                       ) {\r
-                               getModel().loadToSequencer(row);\r
-                               fireEditingStopped();\r
-                               return null;\r
-                       }\r
-               }\r
-               /**\r
-                * プレイボタンを埋め込んだセルエディタ\r
-                */\r
-               private class PlayButtonCellEditor extends AbstractCellEditor\r
-                       implements TableCellEditor, TableCellRenderer\r
-               {\r
-                       private JToggleButton playButton = new JToggleButton(\r
-                               getModel().sequencerModel.startStopAction\r
-                       );\r
-                       public PlayButtonCellEditor() {\r
-                               playButton.setMargin(ZERO_INSETS);\r
-                               int column = SequenceListTableModel.Column.PLAY.ordinal();\r
-                               TableColumn tc = getColumnModel().getColumn(column);\r
-                               tc.setCellRenderer(this);\r
-                               tc.setCellEditor(this);\r
-                       }\r
-                       /**\r
-                        * {@inheritDoc}\r
-                        *\r
-                        * <p>この実装では、クリックしたセルのシーケンスが\r
-                        * シーケンサーにロードされている場合に\r
-                        * trueを返してプレイボタンを押せるようにします。\r
-                        * そうでない場合はプレイボタンのないセルなので、\r
-                        * ダブルクリックされたときだけtrueを返します。\r
-                        * </p>\r
-                        */\r
-                       @Override\r
-                       public boolean isCellEditable(EventObject e) {\r
-                               if( ! (e instanceof MouseEvent) ) {\r
-                                       // マウスイベント以外はデフォルトメソッドにお任せ\r
-                                       return super.isCellEditable(e);\r
-                               }\r
-                               fireEditingStopped();\r
-                               MouseEvent me = (MouseEvent)e;\r
-                               // クリックされたセルの行を特定\r
-                               int row = rowAtPoint(me.getPoint());\r
-                               if( row < 0 )\r
-                                       return false;\r
-                               SequenceListTableModel model = getModel();\r
-                               if( row >= model.getRowCount() )\r
-                                       return false;\r
-                               if( model.sequenceList.get(row).isOnSequencer() ) {\r
-                                       // プレイボタン表示中のセルはシングルクリックでもOK\r
-                                       return true;\r
-                               }\r
-                               // プレイボタンのないセルはダブルクリックのみを受け付ける\r
-                               return me.getClickCount() == 2;\r
-                       }\r
-                       @Override\r
-                       public Object getCellEditorValue() { return null; }\r
-                       /**\r
-                        * {@inheritDoc}\r
-                        *\r
-                        * <p>この実装では、行の表すシーケンスが\r
-                        * シーケンサーにロードされている場合にプレイボタンを返します。\r
-                        * そうでない場合は、\r
-                        * そのシーケンスをシーケンサーにロードしてnullを返します。\r
-                        * </p>\r
-                        */\r
-                       @Override\r
-                       public Component getTableCellEditorComponent(\r
-                               JTable table, Object value, boolean isSelected, int row, int column\r
-                       ) {\r
-                               fireEditingStopped();\r
-                               SequenceListTableModel model = getModel();\r
-                               if( model.sequenceList.get(row).isOnSequencer() ) {\r
-                                       return playButton;\r
-                               }\r
-                               model.loadToSequencer(row);\r
-                               return null;\r
-                       }\r
-                       @Override\r
-                       public Component getTableCellRendererComponent(\r
-                               JTable table, Object value, boolean isSelected,\r
-                               boolean hasFocus, int row, int column\r
-                       ) {\r
-                               SequenceListTableModel model = getModel();\r
-                               if(model.sequenceList.get(row).isOnSequencer()) return playButton;\r
-                               Class<?> cc = model.getColumnClass(column);\r
-                               TableCellRenderer defaultRenderer = table.getDefaultRenderer(cc);\r
-                               return defaultRenderer.getTableCellRendererComponent(\r
-                                       table, value, isSelected, hasFocus, row, column\r
-                               );\r
-                       }\r
-               }\r
-               /**\r
-                * このプレイリスト(シーケンスリスト)が表示するデータを提供する\r
-                * プレイリストモデルを返します。\r
-                * @return プレイリストモデル\r
-                */\r
-               @Override\r
-               public SequenceListTableModel getModel() {\r
-                       return (SequenceListTableModel) super.getModel();\r
-               }\r
-               /**\r
-                * シーケンスを削除するアクション\r
-                */\r
-               Action deleteSequenceAction = getModel().new SelectedSequenceAction(\r
-                       "Delete", MIDIEditor.deleteIcon,\r
-                       "Delete selected MIDI sequence - 選択した曲をプレイリストから削除"\r
-               ) {\r
-                       @Override\r
-                       public void actionPerformed(ActionEvent e) {\r
-                               SequenceListTableModel model = getModel();\r
-                               if( midiFileChooser != null ) {\r
-                                       // ファイルに保存できる場合(Javaアプレットではなく、Javaアプリとして動作している場合)\r
-                                       //\r
-                                       SequenceTrackListTableModel seqModel = model.getSelectedSequenceModel();\r
-                                       if( seqModel.isModified() ) {\r
-                                               // ファイル未保存の変更がある場合\r
-                                               //\r
-                                               String message =\r
-                                                       "Selected MIDI sequence not saved - delete it ?\n" +\r
-                                                       "選択したMIDIシーケンスはまだ保存されていません。削除しますか?";\r
-                                               if( ! confirm(message) ) {\r
-                                                       // 実は削除してほしくなかった場合\r
-                                                       return;\r
-                                               }\r
-                                       }\r
-                               }\r
-                               // 削除を実行\r
-                               model.removeSelectedSequence();\r
-                       }\r
-               };\r
-               /**\r
-                * ファイル選択ダイアログ(アプレットでは使用不可)\r
-                */\r
-               private class MidiFileChooser extends JFileChooser {\r
-                       {\r
-                               String description = "MIDI sequence (*.mid)";\r
-                               String extension = "mid";\r
-                               FileFilter filter = new FileNameExtensionFilter(description, extension);\r
-                               setFileFilter(filter);\r
-                       }\r
-                       /**\r
-                        * ファイル保存アクション\r
-                        */\r
-                       public Action saveMidiFileAction = getModel().new SelectedSequenceAction(\r
-                               "Save",\r
-                               "Save selected MIDI sequence to file - 選択したMIDIシーケンスをファイルに保存"\r
-                       ) {\r
-                               @Override\r
-                               public void actionPerformed(ActionEvent e) {\r
-                                       SequenceListTableModel model = getModel();\r
-                                       SequenceTrackListTableModel sequenceModel = model.getSelectedSequenceModel();\r
-                                       String filename = sequenceModel.getFilename();\r
-                                       File selectedFile;\r
-                                       if( filename != null && ! filename.isEmpty() ) {\r
-                                               // プレイリスト上でファイル名が入っていたら、それを初期選択\r
-                                               setSelectedFile(selectedFile = new File(filename));\r
-                                       }\r
-                                       int saveOption = showSaveDialog(MIDIEditor.this);\r
-                                       if( saveOption != JFileChooser.APPROVE_OPTION ) {\r
-                                               // 保存ダイアログでキャンセルされた場合\r
-                                               return;\r
-                                       }\r
-                                       if( (selectedFile = getSelectedFile()).exists() ) {\r
-                                               // 指定されたファイルがすでにあった場合\r
-                                               String fn = selectedFile.getName();\r
-                                               String message = "Overwrite " + fn + " ?\n";\r
-                                               message += fn + " を上書きしてよろしいですか?";\r
-                                               if( ! confirm(message) ) {\r
-                                                       // 上書きしてほしくなかった場合\r
-                                                       return;\r
-                                               }\r
-                                       }\r
-                                       // 保存を実行\r
-                                       try ( FileOutputStream out = new FileOutputStream(selectedFile) ) {\r
-                                               out.write(sequenceModel.getMIDIdata());\r
-                                               sequenceModel.setModified(false);\r
-                                       }\r
-                                       catch( IOException ex ) {\r
-                                               showError( ex.getMessage() );\r
-                                               ex.printStackTrace();\r
-                                       }\r
-                               }\r
-                       };\r
-                       /**\r
-                        * ファイルを開くアクション\r
-                        */\r
-                       public Action openMidiFileAction = new AbstractAction("Open") {\r
-                               {\r
-                                       String tooltip = "Open MIDI file - MIDIファイルを開く";\r
-                                       putValue(Action.SHORT_DESCRIPTION, tooltip);\r
-                               }\r
-                               @Override\r
-                               public void actionPerformed(ActionEvent event) {\r
-                                       int openOption = showOpenDialog(MIDIEditor.this);\r
-                                       if(openOption == JFileChooser.APPROVE_OPTION) {\r
-                                               try  {\r
-                                                       getModel().addSequence(getSelectedFile());\r
-                                               } catch( IOException|InvalidMidiDataException e ) {\r
-                                                       showWarning(e.getMessage());\r
-                                               } catch( AccessControlException e ) {\r
-                                                       showError(e.getMessage());\r
-                                                       e.printStackTrace();\r
-                                               }\r
-                                       }\r
-                               }\r
-                       };\r
-               };\r
-       }\r
-\r
-       /**\r
-        * シーケンス(トラックリスト)テーブルビュー\r
-        */\r
-       public class TrackListTable extends JTable {\r
-               /**\r
-                * トラックリストテーブルビューを構築します。\r
-                * @param model シーケンス(トラックリスト)データモデル\r
-                */\r
-               public TrackListTable(SequenceTrackListTableModel model) {\r
-                       super(model, null, model.trackListSelectionModel);\r
-                       //\r
-                       // 録音対象のMIDIチャンネルをコンボボックスで選択できるようにする\r
-                       int colIndex = SequenceTrackListTableModel.Column.RECORD_CHANNEL.ordinal();\r
-                       TableColumn tc = getColumnModel().getColumn(colIndex);\r
-                       tc.setCellEditor(new DefaultCellEditor(new JComboBox<String>(){{\r
-                               addItem("OFF");\r
-                               for(int i=1; i <= MIDISpec.MAX_CHANNELS; i++)\r
-                                       addItem(String.format("%d", i));\r
-                               addItem("ALL");\r
-                       }}));\r
-                       setAutoCreateColumnsFromModel(false);\r
-                       //\r
-                       trackSelectionListener = new TrackSelectionListener();\r
-                       titleLabel = new TitleLabel();\r
-                       model.sequenceListTableModel.sequenceListSelectionModel.addListSelectionListener(titleLabel);\r
-                       TableColumnModel colModel = getColumnModel();\r
-                       for( SequenceTrackListTableModel.Column c : SequenceTrackListTableModel.Column.values() )\r
-                               colModel.getColumn(c.ordinal()).setPreferredWidth(c.preferredWidth);\r
-               }\r
-               /**\r
-                * このテーブルビューが表示するデータを提供する\r
-                * シーケンス(トラックリスト)データモデルを返します。\r
-                * @return シーケンス(トラックリスト)データモデル\r
-                */\r
-               @Override\r
-               public SequenceTrackListTableModel getModel() {\r
-                       return (SequenceTrackListTableModel) super.getModel();\r
-               }\r
-               /**\r
-                * タイトルラベル\r
-                */\r
-               TitleLabel titleLabel;\r
-               /**\r
-                * 親テーブルの選択シーケンスの変更に反応する\r
-                * 曲番号表示付きタイトルラベル\r
-                */\r
-               private class TitleLabel extends JLabel implements ListSelectionListener {\r
-                       private static final String TITLE = "Tracks";\r
-                       public TitleLabel() { setText(TITLE); }\r
-                       @Override\r
-                       public void valueChanged(ListSelectionEvent event) {\r
-                               if( event.getValueIsAdjusting() )\r
-                                       return;\r
-                               SequenceTrackListTableModel oldModel = getModel();\r
-                               SequenceTrackListTableModel newModel = oldModel.sequenceListTableModel.getSelectedSequenceModel();\r
-                               if( oldModel == newModel )\r
-                                       return;\r
-                               //\r
-                               // MIDIチャンネル選択中のときはキャンセルする\r
-                               cancelCellEditing();\r
-                               //\r
-                               int index = oldModel.sequenceListTableModel.sequenceListSelectionModel.getMinSelectionIndex();\r
-                               String text = TITLE;\r
-                               if( index >= 0 ) {\r
-                                       text = String.format(text+" - MIDI file No.%d", index);\r
-                               }\r
-                               setText(text);\r
-                               if( newModel == null ) {\r
-                                       newModel = oldModel.sequenceListTableModel.emptyTrackListTableModel;\r
-                                       addTrackAction.setEnabled(false);\r
-                               }\r
-                               else {\r
-                                       addTrackAction.setEnabled(true);\r
-                               }\r
-                               oldModel.trackListSelectionModel.removeListSelectionListener(trackSelectionListener);\r
-                               setModel(newModel);\r
-                               setSelectionModel(newModel.trackListSelectionModel);\r
-                               newModel.trackListSelectionModel.addListSelectionListener(trackSelectionListener);\r
-                               trackSelectionListener.valueChanged(null);\r
-                       }\r
-               }\r
-               /**\r
-                * トラック選択リスナー\r
-                */\r
-               TrackSelectionListener trackSelectionListener;\r
-               /**\r
-                * 選択トラックの変更に反応するリスナー\r
-                */\r
-               private class TrackSelectionListener implements ListSelectionListener {\r
-                       @Override\r
-                       public void valueChanged(ListSelectionEvent e) {\r
-                               if( e != null && e.getValueIsAdjusting() )\r
-                                       return;\r
-                               ListSelectionModel tlsm = getModel().trackListSelectionModel;\r
-                               deleteTrackAction.setEnabled(! tlsm.isSelectionEmpty());\r
-                               eventListTable.titleLabel.update(tlsm, getModel());\r
-                       }\r
-               }\r
-               /**\r
-                * {@inheritDoc}\r
-                *\r
-                * <p>このトラックリストテーブルのデータが変わったときに編集を解除します。\r
-                * 例えば、イベントが編集された場合や、\r
-                * シーケンサーからこのモデルが外された場合がこれに該当します。\r
-                * </p>\r
-                */\r
-               @Override\r
-               public void tableChanged(TableModelEvent e) {\r
-                       super.tableChanged(e);\r
-                       cancelCellEditing();\r
-               }\r
-               /**\r
-                * このトラックリストテーブルが編集モードになっていたら解除します。\r
-                */\r
-               private void cancelCellEditing() {\r
-                       TableCellEditor currentCellEditor = getCellEditor();\r
-                       if( currentCellEditor != null )\r
-                               currentCellEditor.cancelCellEditing();\r
-               }\r
-               /**\r
-                * トラック追加アクション\r
-                */\r
-               Action addTrackAction = new AbstractAction("New") {\r
-                       {\r
-                               String tooltip = "Append new track - 新しいトラックの追加";\r
-                               putValue(Action.SHORT_DESCRIPTION, tooltip);\r
-                               setEnabled(false);\r
-                       }\r
-                       @Override\r
-                       public void actionPerformed(ActionEvent e) {\r
-                               getModel().createTrack();\r
-                       }\r
-               };\r
-               /**\r
-                * トラック削除アクション\r
-                */\r
-               Action deleteTrackAction = new AbstractAction("Delete", deleteIcon) {\r
-                       {\r
-                               String tooltip = "Delete selected track - 選択したトラックを削除";\r
-                               putValue(Action.SHORT_DESCRIPTION, tooltip);\r
-                               setEnabled(false);\r
-                       }\r
-                       @Override\r
-                       public void actionPerformed(ActionEvent e) {\r
-                               String message = "Do you want to delete selected track ?\n"\r
-                                       + "選択したトラックを削除しますか?";\r
-                               if( confirm(message) ) getModel().deleteSelectedTracks();\r
-                       }\r
-               };\r
-       }\r
-\r
-       /**\r
-        * MIDIイベントリストテーブルビュー(選択中のトラックの中身)\r
-        */\r
-       public class EventListTable extends JTable {\r
-               /**\r
-                * 新しいイベントリストテーブルを構築します。\r
-                * <p>データモデルとして一つのトラックのイベントリストを指定できます。\r
-                * トラックを切り替えたいときは {@link #setModel(TableModel)}\r
-                * でデータモデルを異なるトラックのものに切り替えます。\r
-                * </p>\r
-                *\r
-                * @param model トラック(イベントリスト)データモデル\r
-                */\r
-               public EventListTable(TrackEventListTableModel model) {\r
-                       super(model, null, model.eventSelectionModel);\r
-                       //\r
-                       // 列モデルにセルエディタを設定\r
-                       eventCellEditor = new MidiEventCellEditor();\r
-                       setAutoCreateColumnsFromModel(false);\r
-                       //\r
-                       eventSelectionListener = new EventSelectionListener();\r
-                       titleLabel = new TitleLabel();\r
-                       //\r
-                       TableColumnModel colModel = getColumnModel();\r
-                       for( TrackEventListTableModel.Column c : TrackEventListTableModel.Column.values() )\r
-                               colModel.getColumn(c.ordinal()).setPreferredWidth(c.preferredWidth);\r
-               }\r
-               /**\r
-                * このテーブルビューが表示するデータを提供する\r
-                * トラック(イベントリスト)データモデルを返します。\r
-                * @return トラック(イベントリスト)データモデル\r
-                */\r
-               @Override\r
-               public TrackEventListTableModel getModel() {\r
-                       return (TrackEventListTableModel) super.getModel();\r
-               }\r
-               /**\r
-                * タイトルラベル\r
-                */\r
-               TitleLabel titleLabel;\r
-               /**\r
-                * 親テーブルの選択トラックの変更に反応する\r
-                * トラック番号つきタイトルラベル\r
-                */\r
-               private class TitleLabel extends JLabel {\r
-                       private static final String TITLE = "MIDI Events";\r
-                       public TitleLabel() { super(TITLE); }\r
-                       public void update(ListSelectionModel tlsm, SequenceTrackListTableModel sequenceModel) {\r
-                               String text = TITLE;\r
-                               TrackEventListTableModel oldTrackModel = getModel();\r
-                               int index = tlsm.getMinSelectionIndex();\r
-                               if( index >= 0 ) {\r
-                                       text = String.format(TITLE+" - track No.%d", index);\r
-                               }\r
-                               setText(text);\r
-                               TrackEventListTableModel newTrackModel = sequenceModel.getSelectedTrackModel();\r
-                               if( oldTrackModel == newTrackModel )\r
-                                       return;\r
-                               if( newTrackModel == null ) {\r
-                                       newTrackModel = getModel().sequenceTrackListTableModel.sequenceListTableModel.emptyEventListTableModel;\r
-                                       queryJumpEventAction.setEnabled(false);\r
-                                       queryAddEventAction.setEnabled(false);\r
-\r
-                                       queryPasteEventAction.setEnabled(false);\r
-                                       copyEventAction.setEnabled(false);\r
-                                       deleteEventAction.setEnabled(false);\r
-                                       cutEventAction.setEnabled(false);\r
-                               }\r
-                               else {\r
-                                       queryJumpEventAction.setEnabled(true);\r
-                                       queryAddEventAction.setEnabled(true);\r
-                               }\r
-                               oldTrackModel.eventSelectionModel.removeListSelectionListener(eventSelectionListener);\r
-                               setModel(newTrackModel);\r
-                               setSelectionModel(newTrackModel.eventSelectionModel);\r
-                               newTrackModel.eventSelectionModel.addListSelectionListener(eventSelectionListener);\r
-                       }\r
-               }\r
-               /**\r
-                * イベント選択リスナー\r
-                */\r
-               private EventSelectionListener eventSelectionListener;\r
-               /**\r
-                * 選択イベントの変更に反応するリスナー\r
-                */\r
-               private class EventSelectionListener implements ListSelectionListener {\r
-                       public EventSelectionListener() {\r
-                               getModel().eventSelectionModel.addListSelectionListener(this);\r
-                       }\r
-                       @Override\r
-                       public void valueChanged(ListSelectionEvent e) {\r
-                               if( e.getValueIsAdjusting() )\r
-                                       return;\r
-                               if( getSelectionModel().isSelectionEmpty() ) {\r
-                                       queryPasteEventAction.setEnabled(false);\r
-                                       copyEventAction.setEnabled(false);\r
-                                       deleteEventAction.setEnabled(false);\r
-                                       cutEventAction.setEnabled(false);\r
-                               }\r
-                               else {\r
-                                       copyEventAction.setEnabled(true);\r
-                                       deleteEventAction.setEnabled(true);\r
-                                       cutEventAction.setEnabled(true);\r
-                                       TrackEventListTableModel trackModel = getModel();\r
-                                       int minIndex = getSelectionModel().getMinSelectionIndex();\r
-                                       MidiEvent midiEvent = trackModel.getMidiEvent(minIndex);\r
-                                       if( midiEvent != null ) {\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( pairNoteOnOffModel.isSelected() ) {\r
-                                               int maxIndex = getSelectionModel().getMaxSelectionIndex();\r
-                                               int partnerIndex;\r
-                                               for( int i=minIndex; i<=maxIndex; i++ ) {\r
-                                                       if( ! getSelectionModel().isSelectedIndex(i) ) continue;\r
-                                                       partnerIndex = trackModel.getIndexOfPartnerFor(i);\r
-                                                       if( partnerIndex >= 0 && ! getSelectionModel().isSelectedIndex(partnerIndex) )\r
-                                                               getSelectionModel().addSelectionInterval(partnerIndex, partnerIndex);\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-               /**\r
-                * Pair noteON/OFF トグルボタンモデル\r
-                */\r
-               private JToggleButton.ToggleButtonModel\r
-                       pairNoteOnOffModel = new JToggleButton.ToggleButtonModel() {\r
-                               {\r
-                                       addItemListener(\r
-                                               new ItemListener() {\r
-                                                       public void itemStateChanged(ItemEvent e) {\r
-                                                               eventDialog.midiMessageForm.durationForm.setEnabled(isSelected());\r
-                                                       }\r
-                                               }\r
-                                       );\r
-                                       setSelected(true);\r
-                               }\r
-                       };\r
-               private class EventEditContext {\r
-                       /**\r
-                        * 編集対象トラック\r
-                        */\r
-                       private TrackEventListTableModel trackModel;\r
-                       /**\r
-                        * tick位置入力モデル\r
-                        */\r
-                       private TickPositionModel tickPositionModel = new TickPositionModel();\r
-                       /**\r
-                        * 選択されたイベント\r
-                        */\r
-                       private MidiEvent selectedMidiEvent = null;\r
-                       /**\r
-                        * 選択されたイベントの場所\r
-                        */\r
-                       private int selectedIndex = -1;\r
-                       /**\r
-                        * 選択されたイベントのtick位置\r
-                        */\r
-                       private long currentTick = 0;\r
-                       /**\r
-                        * 上書きして削除対象にする変更前イベント(null可)\r
-                        */\r
-                       private MidiEvent[] midiEventsToBeOverwritten;\r
-                       /**\r
-                        * 選択したイベントを入力ダイアログなどに反映します。\r
-                        * @param model 対象データモデル\r
-                        */\r
-                       private void setSelectedEvent(TrackEventListTableModel trackModel) {\r
-                               this.trackModel = trackModel;\r
-                               SequenceTrackListTableModel sequenceTableModel = trackModel.sequenceTrackListTableModel;\r
-                               int ppq = sequenceTableModel.getSequence().getResolution();\r
-                               eventDialog.midiMessageForm.durationForm.setPPQ(ppq);\r
-                               tickPositionModel.setSequenceIndex(sequenceTableModel.getSequenceTickIndex());\r
-\r
-                               selectedIndex = trackModel.eventSelectionModel.getMinSelectionIndex();\r
-                               selectedMidiEvent = selectedIndex < 0 ? null : trackModel.getMidiEvent(selectedIndex);\r
-                               currentTick = selectedMidiEvent == null ? 0 : selectedMidiEvent.getTick();\r
-                               tickPositionModel.setTickPosition(currentTick);\r
-                       }\r
-                       public void setupForEdit(TrackEventListTableModel trackModel) {\r
-                               MidiEvent partnerEvent = null;\r
-                               eventDialog.midiMessageForm.setMessage(\r
-                                       selectedMidiEvent.getMessage(),\r
-                                       trackModel.sequenceTrackListTableModel.charset\r
-                               );\r
-                               if( eventDialog.midiMessageForm.isNote() ) {\r
-                                       int partnerIndex = trackModel.getIndexOfPartnerFor(selectedIndex);\r
-                                       if( partnerIndex < 0 ) {\r
-                                               eventDialog.midiMessageForm.durationForm.setDuration(0);\r
-                                       }\r
-                                       else {\r
-                                               partnerEvent = trackModel.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
-                               if(partnerEvent == null)\r
-                                       midiEventsToBeOverwritten = new MidiEvent[] {selectedMidiEvent};\r
-                               else\r
-                                       midiEventsToBeOverwritten = new MidiEvent[] {selectedMidiEvent, partnerEvent};\r
-                       }\r
-                       private Action jumpEventAction = new AbstractAction() {\r
-                               { putValue(NAME,"Jump"); }\r
-                               public void actionPerformed(ActionEvent e) {\r
-                                       long tick = tickPositionModel.getTickPosition();\r
-                                       scrollToEventAt(tick);\r
-                                       eventDialog.setVisible(false);\r
-                                       trackModel = null;\r
-                               }\r
-                       };\r
-                       private Action pasteEventAction = new AbstractAction() {\r
-                               { putValue(NAME,"Paste"); }\r
-                               public void actionPerformed(ActionEvent e) {\r
-                                       long tick = tickPositionModel.getTickPosition();\r
-                                       clipBoard.paste(trackModel, tick);\r
-                                       scrollToEventAt(tick);\r
-                                       // ペーストで曲の長さが変わったことをプレイリストに通知\r
-                                       SequenceTrackListTableModel seqModel = trackModel.sequenceTrackListTableModel;\r
-                                       seqModel.sequenceListTableModel.fireSequenceModified(seqModel);\r
-                                       eventDialog.setVisible(false);\r
-                                       trackModel = null;\r
-                               }\r
-                       };\r
-                       private boolean applyEvent() {\r
-                               long tick = tickPositionModel.getTickPosition();\r
-                               MidiMessageForm form = eventDialog.midiMessageForm;\r
-                               SequenceTrackListTableModel seqModel = trackModel.sequenceTrackListTableModel;\r
-                               MidiEvent newMidiEvent = new MidiEvent(form.getMessage(seqModel.charset), tick);\r
-                               if( midiEventsToBeOverwritten != null ) {\r
-                                       // 上書き消去するための選択済イベントがあった場合\r
-                                       trackModel.removeMidiEvents(midiEventsToBeOverwritten);\r
-                               }\r
-                               if( ! trackModel.addMidiEvent(newMidiEvent) ) {\r
-                                       System.out.println("addMidiEvent failure");\r
-                                       return false;\r
-                               }\r
-                               if(pairNoteOnOffModel.isSelected() && form.isNote()) {\r
-                                       ShortMessage sm = form.createPartnerMessage();\r
-                                       if(sm == null)\r
-                                               scrollToEventAt( tick );\r
-                                       else {\r
-                                               int duration = form.durationForm.getDuration();\r
-                                               if( form.isNote(false) ) {\r
-                                                       duration = -duration;\r
-                                               }\r
-                                               long partnerTick = tick + (long)duration;\r
-                                               if( partnerTick < 0L ) partnerTick = 0L;\r
-                                               MidiEvent partner = new MidiEvent((MidiMessage)sm, partnerTick);\r
-                                               if( ! trackModel.addMidiEvent(partner) ) {\r
-                                                       System.out.println("addMidiEvent failure (note on/off partner message)");\r
-                                               }\r
-                                               scrollToEventAt(partnerTick > tick ? partnerTick : tick);\r
-                                       }\r
-                               }\r
-                               seqModel.sequenceListTableModel.fireSequenceModified(seqModel);\r
-                               eventDialog.setVisible(false);\r
-                               return true;\r
-                       }\r
-               }\r
-               private EventEditContext editContext = new EventEditContext();\r
-               /**\r
-                * 指定のTick位置へジャンプするアクション\r
-                */\r
-               Action queryJumpEventAction = new AbstractAction() {\r
-                       {\r
-                               putValue(NAME,"Jump to ...");\r
-                               setEnabled(false);\r
-                       }\r
-                       public void actionPerformed(ActionEvent e) {\r
-                               editContext.setSelectedEvent(getModel());\r
-                               eventDialog.openTickForm("Jump selection to", editContext.jumpEventAction);\r
-                       }\r
-               };\r
-               /**\r
-                * 新しいイベントの追加を行うアクション\r
-                */\r
-               Action queryAddEventAction = new AbstractAction() {\r
-                       {\r
-                               putValue(NAME,"New");\r
-                               setEnabled(false);\r
-                       }\r
-                       public void actionPerformed(ActionEvent e) {\r
-                               TrackEventListTableModel model = getModel();\r
-                               editContext.setSelectedEvent(model);\r
-                               editContext.midiEventsToBeOverwritten = null;\r
-                               eventDialog.openEventForm(\r
-                                       "New MIDI event",\r
-                                       eventCellEditor.applyEventAction,\r
-                                       model.getChannel()\r
-                               );\r
-                       }\r
-               };\r
-               /**\r
-                * MIDIイベントのコピー&ペーストを行うためのクリップボード\r
-                */\r
-               private class LocalClipBoard {\r
-                       private MidiEvent copiedEventsToPaste[];\r
-                       private int copiedEventsPPQ = 0;\r
-                       public void copy(TrackEventListTableModel model, boolean withRemove) {\r
-                               copiedEventsToPaste = model.getSelectedMidiEvents();\r
-                               copiedEventsPPQ = model.sequenceTrackListTableModel.getSequence().getResolution();\r
-                               if( withRemove ) model.removeMidiEvents(copiedEventsToPaste);\r
-                               boolean en = (copiedEventsToPaste != null && copiedEventsToPaste.length > 0);\r
-                               queryPasteEventAction.setEnabled(en);\r
-                       }\r
-                       public void cut(TrackEventListTableModel model) {copy(model,true);}\r
-                       public void copy(TrackEventListTableModel model){copy(model,false);}\r
-                       public void paste(TrackEventListTableModel model, long tick) {\r
-                               model.addMidiEvents(copiedEventsToPaste, tick, copiedEventsPPQ);\r
-                       }\r
-               }\r
-               private LocalClipBoard clipBoard = new LocalClipBoard();\r
-               /**\r
-                * 指定のTick位置へ貼り付けるアクション\r
-                */\r
-               Action queryPasteEventAction = new AbstractAction() {\r
-                       {\r
-                               putValue(NAME,"Paste to ...");\r
-                               setEnabled(false);\r
-                       }\r
-                       public void actionPerformed(ActionEvent e) {\r
-                               editContext.setSelectedEvent(getModel());\r
-                               eventDialog.openTickForm("Paste to", editContext.pasteEventAction);\r
-                       }\r
-               };\r
-               /**\r
-                * イベントカットアクション\r
-                */\r
-               public Action cutEventAction = new AbstractAction("Cut") {\r
-                       {\r
-                               setEnabled(false);\r
-                       }\r
-                       @Override\r
-                       public void actionPerformed(ActionEvent e) {\r
-                               TrackEventListTableModel model = getModel();\r
-                               if( ! confirm("Do you want to cut selected event ?\n選択したMIDIイベントを切り取りますか?"))\r
-                                       return;\r
-                               clipBoard.cut(model);\r
-                       }\r
-               };\r
-               /**\r
-                * イベントコピーアクション\r
-                */\r
-               public Action copyEventAction = new AbstractAction("Copy") {\r
-                       {\r
-                               setEnabled(false);\r
-                       }\r
-                       @Override\r
-                       public void actionPerformed(ActionEvent e) {\r
-                               clipBoard.copy(getModel());\r
-                       }\r
-               };\r
-               /**\r
-                * イベント削除アクション\r
-                */\r
-               public Action deleteEventAction = new AbstractAction("Delete", deleteIcon) {\r
-                       {\r
-                               setEnabled(false);\r
-                       }\r
-                       @Override\r
-                       public void actionPerformed(ActionEvent e) {\r
-                               TrackEventListTableModel model = getModel();\r
-                               if( ! confirm("Do you want to delete selected event ?\n選択したMIDIイベントを削除しますか?"))\r
-                                       return;\r
-                               model.removeSelectedMidiEvents();\r
-                       }\r
-               };\r
-               /**\r
-                * MIDIイベント表のセルエディタ\r
-                */\r
-               private MidiEventCellEditor eventCellEditor;\r
-               /**\r
-                * MIDIイベント表のセルエディタ\r
-                */\r
-               class MidiEventCellEditor extends AbstractCellEditor implements TableCellEditor {\r
-                       /**\r
-                        * MIDIイベントセルエディタを構築します。\r
-                        */\r
-                       public MidiEventCellEditor() {\r
-                               eventDialog.midiMessageForm.setOutputMidiChannels(virtualMidiDevice.getChannels());\r
-                               eventDialog.tickPositionInputForm.setModel(editContext.tickPositionModel);\r
-                               int index = TrackEventListTableModel.Column.MESSAGE.ordinal();\r
-                               getColumnModel().getColumn(index).setCellEditor(this);\r
-                       }\r
-                       /**\r
-                        * セルをダブルクリックしないと編集できないようにします。\r
-                        * @param e イベント(マウスイベント)\r
-                        * @return 編集可能になったらtrue\r
-                        */\r
-                       @Override\r
-                       public boolean isCellEditable(EventObject e) {\r
-                               if( ! (e instanceof MouseEvent) )\r
-                                       return super.isCellEditable(e);\r
-                               return ((MouseEvent)e).getClickCount() == 2;\r
-                       }\r
-                       @Override\r
-                       public Object getCellEditorValue() { return null; }\r
-                       /**\r
-                        * MIDIメッセージダイアログが閉じたときにセル編集を中止するリスナー\r
-                        */\r
-                       private ComponentListener dialogComponentListener = new ComponentAdapter() {\r
-                               @Override\r
-                               public void componentHidden(ComponentEvent e) {\r
-                                       fireEditingCanceled();\r
-                                       // 用が済んだら当リスナーを除去\r
-                                       eventDialog.removeComponentListener(this);\r
-                               }\r
-                       };\r
-                       /**\r
-                        * 既存イベントを編集するアクション\r
-                        */\r
-                       private Action editEventAction = new AbstractAction() {\r
-                               public void actionPerformed(ActionEvent e) {\r
-                                       TrackEventListTableModel model = getModel();\r
-                                       editContext.setSelectedEvent(model);\r
-                                       if( editContext.selectedMidiEvent == null )\r
-                                               return;\r
-                                       editContext.setupForEdit(model);\r
-                                       eventDialog.addComponentListener(dialogComponentListener);\r
-                                       eventDialog.openEventForm("Change MIDI event", applyEventAction);\r
-                               }\r
-                       };\r
-                       /**\r
-                        * イベント編集ボタン\r
-                        */\r
-                       private JButton editEventButton = new JButton(editEventAction){{\r
-                               setHorizontalAlignment(JButton.LEFT);\r
-                       }};\r
-                       @Override\r
-                       public Component getTableCellEditorComponent(\r
-                               JTable table, Object value, boolean isSelected, int row, int column\r
-                       ) {\r
-                               editEventButton.setText(value.toString());\r
-                               return editEventButton;\r
-                       }\r
-                       /**\r
-                        * 入力したイベントを反映するアクション\r
-                        */\r
-                       private Action applyEventAction = new AbstractAction() {\r
-                               {\r
-                                       putValue(NAME,"OK");\r
-                               }\r
-                               public void actionPerformed(ActionEvent e) {\r
-                                       if( editContext.applyEvent() ) fireEditingStopped();\r
-                               }\r
-                       };\r
-               }\r
-               /**\r
-                * スクロール可能なMIDIイベントテーブルビュー\r
-                */\r
-               private JScrollPane scrollPane = new JScrollPane(this);\r
-               /**\r
-                * 指定の MIDI tick のイベントへスクロールします。\r
-                * @param tick MIDI tick\r
-                */\r
-               public void scrollToEventAt(long tick) {\r
-                       int index = getModel().tickToIndex(tick);\r
-                       scrollPane.getVerticalScrollBar().setValue(index * getRowHeight());\r
-                       getSelectionModel().setSelectionInterval(index, index);\r
-               }\r
-       }\r
-\r
-       /**\r
-        * 新しい {@link MIDIEditor} を構築します。\r
-        * @param deviceModelList MIDIデバイスモデルリスト\r
-        */\r
-       public MIDIEditor(MidiSequencerModel sequencerModel) {\r
-               // テーブルモデルとテーブルビューの生成\r
-               sequenceListTable = new SequenceListTable(\r
-                       new SequenceListTableModel(sequencerModel)\r
-               );\r
-               trackListTable = new TrackListTable(\r
-                       new SequenceTrackListTableModel(\r
-                               sequenceListTable.getModel(), null, null\r
-                       )\r
-               );\r
-               eventListTable = new EventListTable(\r
-                       new TrackEventListTableModel(trackListTable.getModel(), null)\r
-               );\r
-               // レイアウト\r
-               setTitle("MIDI Editor/Playlist - MIDI Chord Helper");\r
-               setBounds( 150, 200, 900, 500 );\r
-               setLayout(new FlowLayout());\r
-               new DropTarget(this, DnDConstants.ACTION_COPY_OR_MOVE, this, true);\r
-               JPanel playlistPanel = new JPanel() {{\r
-                       JPanel playlistOperationPanel = new JPanel() {{\r
-                               setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));\r
-                               add(Box.createRigidArea(new Dimension(10, 0)));\r
-                               add(new JButton(newSequenceDialog.openAction) {{\r
-                                       setMargin(ZERO_INSETS);\r
-                               }});\r
-                               if( sequenceListTable.midiFileChooser != null ) {\r
-                                       add( Box.createRigidArea(new Dimension(5, 0)) );\r
-                                       add(new JButton(\r
-                                               sequenceListTable.midiFileChooser.openMidiFileAction\r
-                                       ) {{\r
-                                               setMargin(ZERO_INSETS);\r
-                                       }});\r
-                               }\r
-                               if(sequenceListTable.base64EncodeAction != null) {\r
-                                       add(Box.createRigidArea(new Dimension(5, 0)));\r
-                                       add(new JButton(sequenceListTable.base64EncodeAction) {{\r
-                                               setMargin(ZERO_INSETS);\r
-                                       }});\r
-                               }\r
-                               add(Box.createRigidArea(new Dimension(5, 0)));\r
-                               SequenceListTableModel sequenceListTableModel = sequenceListTable.getModel();\r
-                               add(new JButton(sequenceListTableModel.moveToTopAction) {{\r
-                                       setMargin(ZERO_INSETS);\r
-                               }});\r
-                               add(Box.createRigidArea(new Dimension(5, 0)));\r
-                               add(new JButton(sequenceListTableModel.moveToBottomAction) {{\r
-                                       setMargin(ZERO_INSETS);\r
-                               }});\r
-                               if( sequenceListTable.midiFileChooser != null ) {\r
-                                       add(Box.createRigidArea(new Dimension(5, 0)));\r
-                                       add(new JButton(\r
-                                               sequenceListTable.midiFileChooser.saveMidiFileAction\r
-                                       ) {{\r
-                                               setMargin(ZERO_INSETS);\r
-                                       }});\r
-                               }\r
-                               add( Box.createRigidArea(new Dimension(5, 0)) );\r
-                               add(new JButton(sequenceListTable.deleteSequenceAction) {{\r
-                                       setMargin(ZERO_INSETS);\r
-                               }});\r
-                               add( Box.createRigidArea(new Dimension(5, 0)) );\r
-                               add(new SequencerSpeedSlider(\r
-                                       sequenceListTableModel.sequencerModel.speedSliderModel\r
-                               ));\r
-                               add( Box.createRigidArea(new Dimension(5, 0)) );\r
-                               add(new JPanel() {{\r
-                                       add(new JLabel("SyncMode:"));\r
-                                       add(new JLabel("Master"));\r
-                                       add(new JComboBox<Sequencer.SyncMode>(\r
-                                               sequenceListTable.getModel().sequencerModel.masterSyncModeModel\r
-                                       ));\r
-                                       add(new JLabel("Slave"));\r
-                                       add(new JComboBox<Sequencer.SyncMode>(\r
-                                               sequenceListTable.getModel().sequencerModel.slaveSyncModeModel\r
-                                       ));\r
-                               }});\r
-                       }};\r
-                       setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));\r
-                       add(new JScrollPane(sequenceListTable));\r
-                       add(Box.createRigidArea(new Dimension(0, 10)));\r
-                       add(playlistOperationPanel);\r
-                       add(Box.createRigidArea(new Dimension(0, 10)));\r
-               }};\r
-               JPanel trackListPanel = new JPanel() {{\r
-                       JPanel trackListOperationPanel = new JPanel() {{\r
-                               add(new JButton(trackListTable.addTrackAction) {{\r
-                                       setMargin(ZERO_INSETS);\r
-                               }});\r
-                               add(new JButton(trackListTable.deleteTrackAction) {{\r
-                                       setMargin(ZERO_INSETS);\r
-                               }});\r
-                       }};\r
-                       setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));\r
-                       add(trackListTable.titleLabel);\r
-                       add(Box.createRigidArea(new Dimension(0, 5)));\r
-                       add(new JScrollPane(trackListTable));\r
-                       add(Box.createRigidArea(new Dimension(0, 5)));\r
-                       add(trackListOperationPanel);\r
-               }};\r
-               JPanel eventListPanel = new JPanel() {{\r
-                       JPanel eventListOperationPanel = new JPanel() {{\r
-                               add(new JCheckBox("Pair NoteON/OFF") {{\r
-                                       setModel(eventListTable.pairNoteOnOffModel);\r
-                                       setToolTipText("NoteON/OFFをペアで同時選択する");\r
-                               }});\r
-                               add(new JButton(eventListTable.queryJumpEventAction) {{\r
-                                       setMargin(ZERO_INSETS);\r
-                               }});\r
-                               add(new JButton(eventListTable.queryAddEventAction) {{\r
-                                       setMargin(ZERO_INSETS);\r
-                               }});\r
-                               add(new JButton(eventListTable.copyEventAction) {{\r
-                                       setMargin(ZERO_INSETS);\r
-                               }});\r
-                               add(new JButton(eventListTable.cutEventAction) {{\r
-                                       setMargin(ZERO_INSETS);\r
-                               }});\r
-                               add(new JButton(eventListTable.queryPasteEventAction) {{\r
-                                       setMargin(ZERO_INSETS);\r
-                               }});\r
-                               add(new JButton(eventListTable.deleteEventAction) {{\r
-                                       setMargin(ZERO_INSETS);\r
-                               }});\r
-                       }};\r
-                       setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));\r
-                       add(eventListTable.titleLabel);\r
-                       add(eventListTable.scrollPane);\r
-                       add(eventListOperationPanel);\r
-               }};\r
-               Container cp = getContentPane();\r
-               cp.setLayout(new BoxLayout(cp, BoxLayout.Y_AXIS));\r
-               cp.add(Box.createVerticalStrut(2));\r
-               cp.add(\r
-                       new JSplitPane(JSplitPane.VERTICAL_SPLIT, playlistPanel,\r
-                               new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, trackListPanel, eventListPanel) {{\r
-                                       setDividerLocation(300);\r
-                               }}\r
-                       ) {{\r
-                               setDividerLocation(160);\r
-                       }}\r
-               );\r
-       }\r
-\r
-}\r
@@ -82,7 +82,7 @@ import camidion.chordhelper.music.MIDISpec;
  *     Copyright (C) 2006-2014 Akiyoshi Kamide\r
  *     http://www.yk.rim.or.jp/~kamide/music/chordhelper/\r
  */\r
-public class MidiEditor extends JDialog implements DropTargetListener {\r
+public class MidiSequenceEditor extends JDialog implements DropTargetListener {\r
        private static VirtualMidiDevice virtualMidiDevice = new AbstractVirtualMidiDevice() {\r
                {\r
                        info = new MyInfo();\r
@@ -473,7 +473,7 @@ public class MidiEditor extends JDialog implements DropTargetListener {
                 * シーケンスを削除するアクション\r
                 */\r
                Action deleteSequenceAction = getModel().new SelectedSequenceAction(\r
-                       "Delete", MidiEditor.deleteIcon,\r
+                       "Delete", MidiSequenceEditor.deleteIcon,\r
                        "Delete selected MIDI sequence - 選択した曲をプレイリストから削除"\r
                ) {\r
                        @Override\r
@@ -526,7 +526,7 @@ public class MidiEditor extends JDialog implements DropTargetListener {
                                                // プレイリスト上でファイル名が入っていたら、それを初期選択\r
                                                setSelectedFile(selectedFile = new File(filename));\r
                                        }\r
-                                       int saveOption = showSaveDialog(MidiEditor.this);\r
+                                       int saveOption = showSaveDialog(MidiSequenceEditor.this);\r
                                        if( saveOption != JFileChooser.APPROVE_OPTION ) {\r
                                                // 保存ダイアログでキャンセルされた場合\r
                                                return;\r
@@ -562,7 +562,7 @@ public class MidiEditor extends JDialog implements DropTargetListener {
                                }\r
                                @Override\r
                                public void actionPerformed(ActionEvent event) {\r
-                                       int openOption = showOpenDialog(MidiEditor.this);\r
+                                       int openOption = showOpenDialog(MidiSequenceEditor.this);\r
                                        if(openOption == JFileChooser.APPROVE_OPTION) {\r
                                                try  {\r
                                                        getModel().addSequence(getSelectedFile());\r
@@ -1207,10 +1207,10 @@ public class MidiEditor extends JDialog implements DropTargetListener {
        }\r
 \r
        /**\r
-        * 新しい {@link MidiEditor} を構築します。\r
+        * 新しい {@link MidiSequenceEditor} を構築します。\r
         * @param deviceModelList MIDIデバイスモデルリスト\r
         */\r
-       public MidiEditor(MidiSequencerModel sequencerModel) {\r
+       public MidiSequenceEditor(MidiSequencerModel sequencerModel) {\r
                // テーブルモデルとテーブルビューの生成\r
                sequenceListTable = new SequenceListTable(\r
                        new PlaylistTableModel(sequencerModel)\r
index 91a119c..2d8dc59 100644 (file)
@@ -93,7 +93,7 @@ public class NewSequenceDialog extends JDialog {
                @Override\r
                public void actionPerformed(ActionEvent e) { setVisible(true); }\r
        };\r
-       private MidiEditor midiEditor;\r
+       private MidiSequenceEditor midiEditor;\r
        /**\r
         * MIDIシーケンス生成アクション\r
         */\r
@@ -111,7 +111,7 @@ public class NewSequenceDialog extends JDialog {
         * 新しいMIDIシーケンスを生成するダイアログを構築します。\r
         * @param midiEditor シーケンス追加先エディタ\r
         */\r
-       public NewSequenceDialog(MidiEditor midiEditor) {\r
+       public NewSequenceDialog(MidiSequenceEditor midiEditor) {\r
                this.midiEditor = midiEditor;\r
                trackSpecPanel.setChannels(midiEditor.getVirtualMidiDevice().getChannels());\r
                setTitle("Generate new sequence - " + ChordHelperApplet.VersionInfo.NAME);\r