OSDN Git Service

リファクタリング/ツールチップ追加(MIDIEditor周辺)
authorAkiyoshi Kamide <kamide@yk.rim.or.jp>
Mon, 25 Nov 2013 17:13:04 +0000 (17:13 +0000)
committerAkiyoshi Kamide <kamide@yk.rim.or.jp>
Mon, 25 Nov 2013 17:13:04 +0000 (17:13 +0000)
git-svn-id: https://svn.sourceforge.jp/svnroot/midichordhelper/MIDIChordHelper@16 302f1594-2db2-43b1-aaa4-6307b5a2a2de

src/ChordHelperApplet.java
src/MIDIEditor.java
src/MIDIMsgForm.java
src/MIDISequencer.java
src/MidiChordHelper.java
src/NewSequenceDialog.java
src/PianoKeyboard.java

index 37ebea8..29041d8 100644 (file)
@@ -251,7 +251,7 @@ public class ChordHelperApplet extends JApplet {
         */\r
        public static class VersionInfo {\r
                public static final String      NAME = "MIDI Chord Helper";\r
-               public static final String      VERSION = "Ver.20131124.1";\r
+               public static final String      VERSION = "Ver.20131126.1";\r
                public static final String      COPYRIGHT = "Copyright (C) 2004-2013";\r
                public static final String      AUTHER = "@きよし - Akiyoshi Kamide";\r
                public static final String      URL = "http://www.yk.rim.or.jp/~kamide/music/chordhelper/";\r
@@ -440,8 +440,8 @@ public class ChordHelperApplet extends JApplet {
                );\r
                editorDialog = new MidiEditor(deviceModelList.sequencerModel);\r
                editorDialog.setIconImage(iconImage);\r
-               new DropTarget(this, DnDConstants.ACTION_COPY_OR_MOVE, editorDialog, true);\r
                deviceModelList.setMidiEditor(editorDialog);\r
+               new DropTarget(this, DnDConstants.ACTION_COPY_OR_MOVE, editorDialog, true);\r
                keyboardPanel.eventDialog = editorDialog.eventCellEditor.eventDialog;\r
                midiConnectionDialog = new MidiDeviceDialog(deviceModelList);\r
                midiConnectionDialog.setIconImage(iconImage);\r
@@ -618,10 +618,7 @@ public class ChordHelperApplet extends JApplet {
                                        add( Box.createHorizontalStrut(12) );\r
                                        add( songTitleLabel );\r
                                        add( Box.createHorizontalStrut(12) );\r
-                                       add( new JButton("Edit/Playlist/Speed", new ButtonIcon(ButtonIcon.EDIT_ICON)) {{\r
-                                               setMargin(ZERO_INSETS);\r
-                                               addActionListener(editorDialog);\r
-                                       }});\r
+                                       add( new JButton(editorDialog.openAction) {{ setMargin(ZERO_INSETS); }});\r
                                }});\r
                                add(new JPanel() {{\r
                                        setLayout(new BoxLayout(this, BoxLayout.X_AXIS));\r
index 669cb1c..f675806 100644 (file)
@@ -77,7 +77,6 @@ import javax.swing.event.TableModelEvent;
 import javax.swing.event.TableModelListener;\r
 import javax.swing.filechooser.FileNameExtensionFilter;\r
 import javax.swing.table.AbstractTableModel;\r
-import javax.swing.table.DefaultTableColumnModel;\r
 import javax.swing.table.TableCellEditor;\r
 import javax.swing.table.TableCellRenderer;\r
 import javax.swing.table.TableColumn;\r
@@ -91,7 +90,7 @@ import javax.swing.table.TableModel;
  *     Copyright (C) 2006-2013 Akiyoshi Kamide\r
  *     http://www.yk.rim.or.jp/~kamide/music/chordhelper/\r
  */\r
-class MidiEditor extends JDialog implements DropTargetListener, ActionListener {\r
+class MidiEditor extends JDialog implements DropTargetListener {\r
        public static final Insets ZERO_INSETS = new Insets(0,0,0,0);\r
        private static final Icon deleteIcon = new ButtonIcon(ButtonIcon.X_ICON);\r
        /**\r
@@ -103,36 +102,28 @@ class MidiEditor extends JDialog implements DropTargetListener, ActionListener {
                                super("MIDI Editor","Unknown vendor","MIDI sequence editor","");\r
                        }\r
                }\r
-               {\r
-                       info = new MyInfo();\r
-                       // 送信のみなので MIDI IN はサポートしない\r
-                       setMaxReceivers(0);\r
-               }\r
+               // 送信のみなので MIDI IN はサポートしない\r
+               { info = new MyInfo(); setMaxReceivers(0); }\r
        };\r
        /**\r
-        * {@inheritDoc}\r
-        * <p>すでに表示されていた場合に手前に表示する点を除き、\r
-        * スーパークラスと同じです。\r
-        * </p>\r
+        * このダイアログを開きます。すでに開かれていた場合は前面に移動します。\r
         */\r
-       @Override\r
-       public void setVisible(boolean isToVisible) {\r
-               if( isToVisible && isVisible() ) {\r
-                       toFront();\r
-                       return;\r
-               }\r
-               super.setVisible(isToVisible);\r
+       public void open() {\r
+               if( isVisible() ) toFront(); else setVisible(true);\r
        }\r
        /**\r
-        * {@inheritDoc}\r
-        * <p>このダイアログを表示するアクションを実行します。\r
-        * </p>\r
+        * このダイアログを表示するアクション\r
         */\r
-       @Override\r
-       public void actionPerformed(ActionEvent e) {\r
-               setVisible(true);\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
@@ -140,30 +131,14 @@ class MidiEditor extends JDialog implements DropTargetListener, ActionListener {
        /**\r
         * 新しいMIDIシーケンスを生成するダイアログ\r
         */\r
-       NewSequenceDialog newSequenceDialog = new NewSequenceDialog(this) {\r
-               { setChannels(virtualMidiDevice.getChannels()); }\r
-       };\r
-       /**\r
-        * 新しいMIDIシーケンスを生成するアクション\r
-        */\r
-       public Action generateNewSongAction = new AbstractAction("New") {\r
-               {\r
-                       putValue(\r
-                               Action.SHORT_DESCRIPTION,\r
-                               "Generate new song - 新しい曲を生成"\r
-                       );\r
-               }\r
-               @Override\r
-               public void actionPerformed(ActionEvent e) {\r
-                       newSequenceDialog.setVisible(true);\r
-               }\r
-       };\r
+       NewSequenceDialog newSequenceDialog = new NewSequenceDialog(this);\r
        /**\r
         * 選択されたシーケンスへジャンプするアクション\r
         */\r
-       public Action jumpSequenceAction = new AbstractAction("Jump") {\r
+       public Action loadToSequencerAction = new AbstractAction("Load to sequencer") {\r
                {\r
-                       putValue(Action.SHORT_DESCRIPTION, "Move to selected song - 選択した曲へ進む");\r
+                       String tooltip = "Load selected MIDI sequence to sequencer - 選択した曲をシーケンサへロード";\r
+                       putValue(Action.SHORT_DESCRIPTION, tooltip);\r
                }\r
                @Override\r
                public void actionPerformed(ActionEvent e) {\r
@@ -174,18 +149,25 @@ class MidiEditor extends JDialog implements DropTargetListener, ActionListener {
         * シーケンスを削除するアクション\r
         */\r
        public Action deleteSequenceAction = new AbstractAction("Delete",deleteIcon) {\r
+               {\r
+                       String tooltip = "Delete selected MIDI sequence - 選択した曲をプレイリストから削除";\r
+                       putValue(Action.SHORT_DESCRIPTION, tooltip);\r
+               }\r
                @Override\r
                public void actionPerformed(ActionEvent e) {\r
                        if( midiFileChooser != null ) {\r
                                // ファイルに保存できる場合(Javaアプレットではなく、Javaアプリとして動作している場合)\r
-                               SequenceTrackListTableModel seqModel = sequenceListTableModel.getSequenceModel(sequenceListSelectionModel);\r
+                               //\r
+                               SequenceTrackListTableModel seqModel =\r
+                                       sequenceListTableModel.getSequenceModel(sequenceListSelectionModel);\r
                                if( seqModel.isModified() ) {\r
                                        // ファイル未保存の変更がある場合\r
-                                       String confirmMessage =\r
+                                       //\r
+                                       String message =\r
                                                "Selected MIDI sequence not saved - delete it ?\n" +\r
                                                "選択したMIDIシーケンスはまだ保存されていません。削除しますか?";\r
-                                       if( ! confirm(confirmMessage) ) {\r
-                                               // ユーザに確認してNoって言われた場合\r
+                                       if( ! confirm(message) ) {\r
+                                               // 実は削除してほしくなかった場合\r
                                                return;\r
                                        }\r
                                }\r
@@ -219,6 +201,10 @@ class MidiEditor extends JDialog implements DropTargetListener, ActionListener {
                        });\r
                        if( base64Dialog.isBase64Available() ) {\r
                                base64EncodeAction = new AbstractAction("Base64 Encode") {\r
+                                       {\r
+                                               String tooltip = "Encode selected sequence to Base64 textdata - 選択した曲をBase64テキストにエンコード";\r
+                                               putValue(Action.SHORT_DESCRIPTION, tooltip);\r
+                                       }\r
                                        @Override\r
                                        public void actionPerformed(ActionEvent e) {\r
                                                SequenceTrackListTableModel mstm = sequenceListTableModel.getSequenceModel(sequenceListSelectionModel);\r
@@ -235,7 +221,7 @@ class MidiEditor extends JDialog implements DropTargetListener, ActionListener {
                        if(base64EncodeAction != null)\r
                                base64EncodeAction.setEnabled(isSelected);\r
                        deleteSequenceAction.setEnabled(isSelected);\r
-                       jumpSequenceAction.setEnabled(isSelected);\r
+                       loadToSequencerAction.setEnabled(isSelected);\r
                }\r
        };\r
        /**\r
@@ -254,6 +240,10 @@ class MidiEditor extends JDialog implements DropTargetListener, ActionListener {
                 * ファイル保存アクション\r
                 */\r
                public Action saveMidiFileAction = new AbstractAction("Save") {\r
+                       {\r
+                               String tooltip = "Save selected MIDI sequence to file - 選択したMIDIシーケンスをファイルに保存";\r
+                               putValue(Action.SHORT_DESCRIPTION, tooltip);\r
+                       }\r
                        @Override\r
                        public void actionPerformed(ActionEvent e) {\r
                                SequenceTrackListTableModel sequenceTableModel =\r
@@ -261,21 +251,25 @@ class MidiEditor extends JDialog implements DropTargetListener, ActionListener {
                                String filename = sequenceTableModel.getFilename();\r
                                File midiFile;\r
                                if( filename != null && ! filename.isEmpty() ) {\r
-                                       midiFile = new File(filename);\r
-                                       setSelectedFile(midiFile);\r
+                                       // プレイリスト上でファイル名が入っていたら、それを初期選択\r
+                                       setSelectedFile(midiFile = new File(filename));\r
                                }\r
-                               int resp = showSaveDialog(MidiEditor.this);\r
-                               if( resp != JFileChooser.APPROVE_OPTION ) {\r
+                               int response = showSaveDialog(MidiEditor.this);\r
+                               if( response != JFileChooser.APPROVE_OPTION ) {\r
+                                       // 保存ダイアログでキャンセルされた場合\r
                                        return;\r
                                }\r
-                               midiFile = getSelectedFile();\r
-                               if( midiFile.exists() && ! confirm(\r
-                                       "Overwrite " + midiFile.getName() + " ?\n"\r
-                                       + midiFile.getName()\r
-                                       + " を上書きしてよろしいですか?"\r
-                               ) ) {\r
-                                       return;\r
+                               if( (midiFile = getSelectedFile()).exists() ) {\r
+                                       // 指定されたファイルがすでにあった場合\r
+                                       String fn = midiFile.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(midiFile) ) {\r
                                        out.write(sequenceTableModel.getMIDIdata());\r
                                        sequenceTableModel.setModified(false);\r
@@ -286,12 +280,18 @@ class MidiEditor extends JDialog implements DropTargetListener, ActionListener {
                                }\r
                        }\r
                };\r
+               /**\r
+                * シーケンスの選択有無に応じて、保存ボタンのイネーブル状態を更新します。\r
+                */\r
                private void updateEnabled() {\r
                        boolean en = (sequenceListSelectionModel.getMinSelectionIndex() >= 0);\r
                        saveMidiFileAction.setEnabled(en);\r
                }\r
                {\r
+                       // ファイルフィルタの設定\r
                        setFileFilter(new FileNameExtensionFilter("MIDI sequence (*.mid)", "mid"));\r
+                       //\r
+                       // 選択状態のリスニングを開始\r
                        sequenceListSelectionModel.addListSelectionListener(this);\r
                        updateEnabled();\r
                }\r
@@ -304,11 +304,14 @@ class MidiEditor extends JDialog implements DropTargetListener, ActionListener {
                /**\r
                 * ファイルを開くアクション\r
                 */\r
-               public Action addMidiFileAction = new AbstractAction("Open") {\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 e) {\r
-                               int resp = showOpenDialog(MidiEditor.this);\r
-                               if( resp == JFileChooser.APPROVE_OPTION )\r
+                               if(showOpenDialog(MidiEditor.this) == JFileChooser.APPROVE_OPTION)\r
                                        addSequence(getSelectedFile());\r
                        }\r
                };\r
@@ -350,6 +353,10 @@ class MidiEditor extends JDialog implements DropTargetListener, ActionListener {
         * トラック追加アクション\r
         */\r
        public Action addTrackAction = new AbstractAction("New") {\r
+               {\r
+                       String tooltip = "Append new track - 新しいトラックの追加";\r
+                       putValue(Action.SHORT_DESCRIPTION, tooltip);\r
+               }\r
                @Override\r
                public void actionPerformed(ActionEvent e) {\r
                        int index = sequenceListTableModel.getSequenceModel(sequenceListSelectionModel).createTrack();\r
@@ -358,9 +365,13 @@ class MidiEditor extends JDialog implements DropTargetListener, ActionListener {
                }\r
        };\r
        /**\r
-        * MIDIトラック除去アクション\r
+        * トラック削除アクション\r
         */\r
-       public Action removeTrackAction = new AbstractAction("Delete", deleteIcon) {\r
+       public Action deleteTrackAction = new AbstractAction("Delete", deleteIcon) {\r
+               {\r
+                       String tooltip = "Delete selected track - 選択したトラックを削除";\r
+                       putValue(Action.SHORT_DESCRIPTION, tooltip);\r
+               }\r
                @Override\r
                public void actionPerformed(ActionEvent e) {\r
                        if( ! confirm("Do you want to delete selected track ?\n選択したトラックを削除しますか?"))\r
@@ -375,25 +386,50 @@ class MidiEditor extends JDialog implements DropTargetListener, ActionListener {
        private JTable trackListTableView = new JTable(\r
                new SequenceTrackListTableModel(sequenceListTableModel),\r
                null, trackSelectionModel\r
-       );\r
-       private TracksLabel trackListTitleLabel = new TracksLabel();\r
-       private class TracksLabel extends JLabel implements ListSelectionListener {\r
+       ) {{\r
+               // 録音対象のMIDIチャンネルをコンボボックスで選択できるよう、\r
+               // セルエディタを差し替える。\r
+               getColumnModel().getColumn(\r
+                       SequenceTrackListTableModel.Column.RECORD_CHANNEL.ordinal()\r
+               ).setCellEditor(\r
+                       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
+               );\r
+               // デフォルトでは、データモデルが差し替えられると列が再作成される。\r
+               // しかしこれでは、シーケンスモデルを差し替えたとたん、\r
+               // せっかく差し替えたセルエディタがデフォルトに戻ってしまう。\r
+               //\r
+               // そこで、一度列データモデルが自動作成されたら、\r
+               // 以後は自動作成しないようにする。\r
+               setAutoCreateColumnsFromModel(false);\r
+       }};\r
+       /**\r
+        * MIDIトラックリストのタイトルラベル\r
+        */\r
+       private JLabel trackListTitleLabel = new JLabel() {\r
                private static final String TITLE = "Tracks";\r
-               public TracksLabel() {\r
-                       super(TITLE);\r
-                       sequenceListSelectionModel.addListSelectionListener(this);\r
-               }\r
-               @Override\r
-               public void valueChanged(ListSelectionEvent e) {\r
-                       if( e.getValueIsAdjusting() )\r
-                               return;\r
-                       int index = sequenceListSelectionModel.getMinSelectionIndex();\r
-                       String text = TITLE;\r
-                       if( index >= 0 )\r
-                               text = String.format(text+" - MIDI file No.%d", index);\r
-                       setText(text);\r
+               {\r
+                       sequenceListSelectionModel.addListSelectionListener(\r
+                               new ListSelectionListener() {\r
+                                       @Override\r
+                                       public void valueChanged(ListSelectionEvent e) {\r
+                                               if( e.getValueIsAdjusting() )\r
+                                                       return;\r
+                                               int index = sequenceListSelectionModel.getMinSelectionIndex();\r
+                                               String text = TITLE;\r
+                                               if( index >= 0 )\r
+                                                       text = String.format(text+" - MIDI file No.%d", index);\r
+                                               setText(text);\r
+                                       }\r
+                               }\r
+                       );\r
+                       setText(TITLE);\r
                }\r
-       }\r
+       };\r
 \r
        /**\r
         * MIDIイベント選択状態\r
@@ -443,7 +479,9 @@ class MidiEditor extends JDialog implements DropTargetListener, ActionListener {
         * MIDIイベントリストテーブルビュー\r
         */\r
        private JTable trackEventListTableView = new JTable(\r
-               new TrackEventListTableModel(), null, eventSelectionModel\r
+               new TrackEventListTableModel(),\r
+               null,\r
+               eventSelectionModel\r
        );\r
        private MidiEventsLabel midiEventsLabel = new MidiEventsLabel();\r
        private class MidiEventsLabel extends JLabel implements ListSelectionListener {\r
@@ -793,55 +831,72 @@ class MidiEditor extends JDialog implements DropTargetListener, ActionListener {
                        midiFileChooser = null;\r
                }\r
                sequenceListTableView = new JTable(\r
-                       sequenceListTableModel,\r
-                       new SequenceListTableColumnModel() {\r
-                               JToggleButton playButton = new JToggleButton(\r
-                                       sequenceListTableModel.sequencerModel.startStopAction\r
-                               ){{ setMargin(ZERO_INSETS); }};\r
-                               class ButtonCellEditor extends AbstractCellEditor implements TableCellEditor {\r
+                       sequenceListTableModel, null, sequenceListSelectionModel\r
+               ) {\r
+                       private JToggleButton playButton = new JToggleButton(\r
+                               sequenceListTableModel.sequencerModel.startStopAction\r
+                       ){{\r
+                               setMargin(ZERO_INSETS);\r
+                       }};\r
+                       {\r
+                               sequenceListTableModel.addTableModelListener(new TableModelListener() {\r
+                                       /**\r
+                                        * 全シーケンスの合計時間長をヘッダータイトルに反映します。\r
+                                        * @param e テーブルモデルイベント\r
+                                        */\r
                                        @Override\r
-                                       public Object getCellEditorValue() { return ""; }\r
+                                       public void tableChanged(TableModelEvent e) {\r
+                                               int sec = sequenceListTableModel.getTotalSeconds();\r
+                                               SequenceListTableModel.Column c = SequenceListTableModel.Column.SEQ_LENGTH;\r
+                                               TableColumn tc = getColumnModel().getColumn(c.ordinal());\r
+                                               tc.setHeaderValue(String.format(c.title+" [%02d:%02d]", sec/60, sec%60));\r
+                                               //\r
+                                               // シーケンス削除時など、合計シーケンス長が変わっても\r
+                                               // 列モデルからではヘッダタイトルが再描画されないことがある。\r
+                                               // そこで、ヘッダビューから repaint() で突っついて再描画させる。\r
+                                               getTableHeader().repaint();\r
+                                       }\r
+                               });\r
+                               TableColumn tc = getColumnModel().getColumn(\r
+                                       SequenceListTableModel.Column.SEQ_PLAY.ordinal()\r
+                               );\r
+                               tc.setCellRenderer(new TableCellRenderer() {\r
                                        @Override\r
-                                       public Component getTableCellEditorComponent(\r
+                                       public Component getTableCellRendererComponent(\r
                                                JTable table, Object value, boolean isSelected,\r
-                                               int row, int column\r
+                                               boolean hasFocus, int row, int column\r
                                        ) {\r
-                                               if(row == sequenceListTableModel.getLoadedIndex())\r
+                                               if(sequenceListTableModel.sequenceList.get(row).isOnSequencer()) {\r
+                                                       // すでにロードされていたらボタンをレンダリング\r
                                                        return playButton;\r
-                                               return null;\r
-                                       }\r
-                               }\r
-                               {\r
-                                       sequenceListTableModel.addTableModelListener(this);\r
-                                       TableColumn tc = getColumn(Column.SEQ_PLAY.ordinal());\r
-                                       tc.setCellRenderer(new TableCellRenderer() {\r
-                                               @Override\r
-                                               public Component getTableCellRendererComponent(\r
-                                                       JTable table, Object value, boolean isSelected,\r
-                                                       boolean hasFocus, int row, int column\r
-                                               ) {\r
-                                                       if(row == sequenceListTableModel.getLoadedIndex())\r
-                                                               return playButton;\r
-                                                       return null;\r
                                                }\r
-                                       });\r
-                                       tc.setCellEditor(new ButtonCellEditor());\r
-                               }\r
-                       },\r
-                       sequenceListSelectionModel\r
-               ) {{\r
-                       sequenceListTableModel.addTableModelListener(\r
-                               new TableModelListener() {\r
-                                       // シーケンス削除時など、合計シーケンス長が変わっても\r
-                                       // 列モデルからではヘッダタイトルが再描画されないことがある。\r
-                                       // そこで、ヘッダビューから repaint() で突っついて再描画させる。\r
-                                       @Override\r
-                                       public void tableChanged(TableModelEvent e) {\r
-                                               getTableHeader().repaint();\r
+                                               // ロードされていなかった場合、\r
+                                               // デフォルトレンダラーでレンダリングする。こうすれば\r
+                                               // レンダラーを設定しなかった場合と全く同じ動作になる。\r
+                                               Class<?> columnClass =\r
+                                                       sequenceListTableModel.getColumnClass(column);\r
+                                               TableCellRenderer defaultRenderer =\r
+                                                       table.getDefaultRenderer(columnClass);\r
+                                               return defaultRenderer.getTableCellRendererComponent(\r
+                                                       table, value, isSelected, hasFocus, row, column\r
+                                               );\r
                                        }\r
+                               });\r
+                               tc.setCellEditor(new PlayButtonCellEditor());\r
+                               setAutoCreateColumnsFromModel(false);\r
+                       }\r
+                       class PlayButtonCellEditor extends AbstractCellEditor implements TableCellEditor {\r
+                               @Override\r
+                               public Object getCellEditorValue() { return ""; }\r
+                               @Override\r
+                               public Component getTableCellEditorComponent(\r
+                                       JTable table, Object value, boolean isSelected,\r
+                                       int row, int column\r
+                               ) {\r
+                                       return sequenceListTableModel.sequenceList.get(row).isOnSequencer() ? playButton : null;\r
                                }\r
-                       );\r
-               }};\r
+                       }\r
+               };\r
                JPanel playlistPanel = new JPanel() {{\r
                        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));\r
                        add(new JScrollPane(sequenceListTableView));\r
@@ -849,10 +904,12 @@ class MidiEditor extends JDialog implements DropTargetListener, ActionListener {
                        add(new JPanel() {{\r
                                setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));\r
                                add(Box.createRigidArea(new Dimension(10, 0)));\r
-                               add(new JButton(generateNewSongAction) {{setMargin(ZERO_INSETS);}});\r
+                               add(new JButton(newSequenceDialog.openAction) {{\r
+                                       setMargin(ZERO_INSETS);\r
+                               }});\r
                                if( midiFileChooser != null ) {\r
                                        add( Box.createRigidArea(new Dimension(5, 0)) );\r
-                                       add(new JButton(midiFileChooser.addMidiFileAction) {{\r
+                                       add(new JButton(midiFileChooser.openMidiFileAction) {{\r
                                                setMargin(ZERO_INSETS);\r
                                        }});\r
                                }\r
@@ -861,7 +918,7 @@ class MidiEditor extends JDialog implements DropTargetListener, ActionListener {
                                        setMargin(ZERO_INSETS);\r
                                }});\r
                                add(Box.createRigidArea(new Dimension(5, 0)));\r
-                               add(new JButton(jumpSequenceAction){{ setMargin(ZERO_INSETS); }});\r
+                               add(new JButton(loadToSequencerAction){{ setMargin(ZERO_INSETS); }});\r
                                add(Box.createRigidArea(new Dimension(5, 0)));\r
                                add(new JButton(sequenceListTableModel.moveToBottomAction) {{\r
                                        setMargin(ZERO_INSETS);\r
@@ -897,7 +954,7 @@ class MidiEditor extends JDialog implements DropTargetListener, ActionListener {
                        add(Box.createRigidArea(new Dimension(0, 5)));\r
                        add(new JPanel() {{\r
                                add(new JButton(addTrackAction) {{ setMargin(ZERO_INSETS); }});\r
-                               add(new JButton(removeTrackAction) {{ setMargin(ZERO_INSETS); }});\r
+                               add(new JButton(deleteTrackAction) {{ setMargin(ZERO_INSETS); }});\r
                        }});\r
                }};\r
                JPanel eventListPanel = new JPanel() {{\r
@@ -991,28 +1048,14 @@ class MidiEditor extends JDialog implements DropTargetListener, ActionListener {
         * ボタン状態の更新\r
         */\r
        public void updateButtonStatus() {\r
-               SequenceTrackListTableModel sequenceModel = sequenceListTableModel.getSequenceModel(sequenceListSelectionModel);\r
+               SequenceTrackListTableModel sequenceModel =\r
+                       sequenceListTableModel.getSequenceModel(sequenceListSelectionModel);\r
                boolean isSequenceSelected = (sequenceModel != null);\r
                if(isSequenceSelected) {\r
                        trackListTableView.setModel(sequenceModel);\r
-                       trackListTableView.getColumnModel().getColumn(\r
-                               SequenceTrackListTableModel.Column.RECORD_CHANNEL.ordinal()\r
-                       ).setCellEditor(\r
-                               new DefaultCellEditor(\r
-                                       new JComboBox<String>() {\r
-                                               {\r
-                                                       addItem("OFF");\r
-                                                       for(int i=1; i <= MIDISpec.MAX_CHANNELS; i++)\r
-                                                               addItem(String.format("%d", i));\r
-                                                       addItem("ALL");\r
-                                               }\r
-                                       }\r
-                               )\r
-                       );\r
                }\r
                else {\r
-                       SequenceTrackListTableModel m = new SequenceTrackListTableModel(sequenceListTableModel);\r
-                       trackListTableView.setModel(m);\r
+                       trackListTableView.setModel(new SequenceTrackListTableModel(sequenceListTableModel));\r
                }\r
                addTrackAction.setEnabled(isSequenceSelected);\r
                boolean isTrackSelected = (\r
@@ -1020,7 +1063,7 @@ class MidiEditor extends JDialog implements DropTargetListener, ActionListener {
                        &&\r
                        isSequenceSelected && sequenceModel.getRowCount() > 0\r
                );\r
-               removeTrackAction.setEnabled(isTrackSelected);\r
+               deleteTrackAction.setEnabled(isTrackSelected);\r
                //\r
                TableModel tm = trackEventListTableView.getModel();\r
                if( ! (tm instanceof TrackEventListTableModel) )\r
@@ -1142,7 +1185,7 @@ class MidiEditor extends JDialog implements DropTargetListener, ActionListener {
                                firstIndex = lastIndex;\r
                }\r
                if(sequenceListTableModel.sequencerModel.getSequencer().isRunning()) {\r
-                       setVisible(true);\r
+                       open();\r
                }\r
                else if( firstIndex >= 0 ) {\r
                        sequenceListTableModel.loadToSequencer(firstIndex);\r
@@ -1209,12 +1252,11 @@ class SequencerSpeedSlider extends JPanel {
        }\r
 }\r
 \r
+\r
 /**\r
- * プレイリスト(MIDIシーケンスリスト)のテーブルモデル\r
+ * プレイリスト(MIDIシーケンスリスト)のテーブルデータモデル\r
  */\r
-class SequenceListTableColumnModel extends DefaultTableColumnModel\r
-       implements TableModelListener\r
-{\r
+class SequenceListTableModel extends AbstractTableModel implements ChangeListener {\r
        /**\r
         * 列の列挙型\r
         */\r
@@ -1224,7 +1266,7 @@ class SequenceListTableColumnModel extends DefaultTableColumnModel
                /** 変更済みフラグ */\r
                MODIFIED("Modified", Boolean.class),\r
                /** 再生ボタン */\r
-               SEQ_PLAY("", String.class) {\r
+               SEQ_PLAY("Sequencer", String.class) {\r
                        @Override\r
                        public boolean isCellEditable() { return true; }\r
                },\r
@@ -1261,31 +1303,6 @@ class SequenceListTableColumnModel extends DefaultTableColumnModel
                }\r
                public boolean isCellEditable() { return false; }\r
        }\r
-       public SequenceListTableColumnModel() {\r
-               for( Column c : Column.values() ) {\r
-                       TableColumn tc = new TableColumn(c.ordinal());\r
-                       tc.setHeaderValue(c.title);\r
-                       addColumn(tc);\r
-               }\r
-       }\r
-       /**\r
-        * 全シーケンスの合計時間長をヘッダータイトルに反映します。\r
-        * @param e テーブルモデルイベント\r
-        */\r
-       @Override\r
-       public void tableChanged(TableModelEvent e) {\r
-               SequenceListTableModel model = (SequenceListTableModel)e.getSource();\r
-               int sec = model.getTotalSeconds();\r
-               Column c = Column.SEQ_LENGTH;\r
-               TableColumn tc = getColumn(c.ordinal());\r
-               tc.setHeaderValue(String.format(c.title+" [%02d:%02d]", sec/60, sec%60));\r
-       }\r
-}\r
-\r
-/**\r
- * プレイリスト(MIDIシーケンスリスト)のテーブルモデル\r
- */\r
-class SequenceListTableModel extends AbstractTableModel implements ChangeListener {\r
        /**\r
         * MIDIシーケンサモデル\r
         */\r
@@ -1339,33 +1356,30 @@ class SequenceListTableModel extends AbstractTableModel implements ChangeListene
                        return;\r
                // 秒が変わったときだけ更新(小数点以下は無視)\r
                secondPosition = sec;\r
-               fireTableCellUpdated(\r
-                       getLoadedIndex(),\r
-                       SequenceListTableColumnModel.Column.SEQ_POSITION.ordinal()\r
-               );\r
+               fireTableCellUpdated(getLoadedIndex(), Column.SEQ_POSITION.ordinal());\r
        }\r
-       private List<SequenceTrackListTableModel> sequenceList = new Vector<>();\r
+       List<SequenceTrackListTableModel> sequenceList = new Vector<>();\r
        @Override\r
        public int getRowCount() { return sequenceList.size(); }\r
        @Override\r
        public int getColumnCount() {\r
-               return SequenceListTableColumnModel.Column.values().length;\r
+               return Column.values().length;\r
        }\r
        @Override\r
        public String getColumnName(int column) {\r
-               return SequenceListTableColumnModel.Column.values()[column].title;\r
+               return Column.values()[column].title;\r
        }\r
        @Override\r
        public Class<?> getColumnClass(int column) {\r
-               return SequenceListTableColumnModel.Column.values()[column].columnClass;\r
+               return Column.values()[column].columnClass;\r
        }\r
        @Override\r
        public boolean isCellEditable(int row, int column) {\r
-               return SequenceListTableColumnModel.Column.values()[column].isCellEditable();\r
+               return Column.values()[column].isCellEditable();\r
        }\r
        @Override\r
        public Object getValueAt(int row, int column) {\r
-               switch(SequenceListTableColumnModel.Column.values()[column]) {\r
+               switch(Column.values()[column]) {\r
                case SEQ_NUMBER: return row;\r
                case MODIFIED:\r
                        return sequenceList.get(row).isModified();\r
@@ -1406,7 +1420,7 @@ class SequenceListTableModel extends AbstractTableModel implements ChangeListene
        }\r
        @Override\r
        public void setValueAt(Object val, int row, int column) {\r
-               switch(SequenceListTableColumnModel.Column.values()[column]) {\r
+               switch(Column.values()[column]) {\r
                case FILENAME:\r
                        // ファイル名の変更\r
                        String filename = (String)val;\r
@@ -1416,7 +1430,7 @@ class SequenceListTableModel extends AbstractTableModel implements ChangeListene
                case SEQ_NAME:\r
                        // シーケンス名の設定または変更\r
                        if( sequenceList.get(row).setName((String)val) )\r
-                               fireTableCellUpdated(row, SequenceListTableColumnModel.Column.MODIFIED.ordinal());\r
+                               fireTableCellUpdated(row, Column.MODIFIED.ordinal());\r
                        break;\r
                default:\r
                        break;\r
@@ -1456,7 +1470,7 @@ class SequenceListTableModel extends AbstractTableModel implements ChangeListene
                for( int i = minIndex; i <= maxIndex; i++ ) {\r
                        if( selModel.isSelectedIndex(i) ) {\r
                                sequenceList.get(i).setModified(isModified);\r
-                               fireTableCellUpdated(i, SequenceListTableColumnModel.Column.MODIFIED.ordinal());\r
+                               fireTableCellUpdated(i, Column.MODIFIED.ordinal());\r
                        }\r
                }\r
        }\r
@@ -1526,11 +1540,11 @@ class SequenceListTableModel extends AbstractTableModel implements ChangeListene
                if( listSelectionModel.isSelectionEmpty() )\r
                        return;\r
                int selectedIndex = listSelectionModel.getMinSelectionIndex();\r
-               if( selectedIndex == getLoadedIndex() ) {\r
-                       // シーケンサーにロード済みのシーケンスだった場合はアンロードする\r
-                       sequencerModel.setSequenceTableModel(null);\r
+               if( sequenceList.remove(selectedIndex).isOnSequencer() ) {\r
+                       // 削除したシーケンスが\r
+                       // シーケンサーにロード済みだった場合、アンロードする。\r
+                       sequencerModel.setSequenceTrackListTableModel(null);\r
                }\r
-               sequenceList.remove(selectedIndex);\r
                fireTableRowsDeleted(selectedIndex, selectedIndex);\r
        }\r
        /**\r
@@ -1541,17 +1555,10 @@ class SequenceListTableModel extends AbstractTableModel implements ChangeListene
                int oldIndex = getLoadedIndex();\r
                if(index == oldIndex)\r
                        return;\r
-               SequenceTrackListTableModel sequenceTableModel = sequenceList.get(index);\r
-               sequencerModel.setSequenceTableModel(sequenceTableModel);\r
-               //\r
-               // トラック内容の再表示\r
-               sequenceTableModel.fireTableDataChanged();\r
-               //\r
-               // セルの再表示(シーケンサーのボタンと現在位置)\r
-               fireTableRowsUpdated(oldIndex, index);\r
+               sequencerModel.setSequenceTrackListTableModel(sequenceList.get(index));\r
                int columnIndices[] = {\r
-                       SequenceListTableColumnModel.Column.SEQ_PLAY.ordinal(),\r
-                       SequenceListTableColumnModel.Column.SEQ_POSITION.ordinal(),\r
+                       Column.SEQ_PLAY.ordinal(),\r
+                       Column.SEQ_POSITION.ordinal(),\r
                };\r
                for( int columnIndex : columnIndices ) {\r
                        fireTableCellUpdated(oldIndex, columnIndex);\r
@@ -1578,13 +1585,13 @@ class SequenceListTableModel extends AbstractTableModel implements ChangeListene
                int index = (loadedIndex < 0 ? 0 : loadedIndex + offset);\r
                if( index < 0 || index >= sequenceList.size() )\r
                        return false;\r
-               loadToSequencer( index );\r
+               loadToSequencer(index);\r
                return true;\r
        }\r
 }\r
 \r
 /**\r
- * MIDIã\82·ã\83¼ã\82±ã\83³ã\82¹ï¼\88ã\83\88ã\83©ã\83\83ã\82¯ã\83ªã\82¹ã\83\88ï¼\89ã\82\92表ã\81\99ã\83\86ã\83¼ã\83\96ã\83«モデル\r
+ * MIDIã\82·ã\83¼ã\82±ã\83³ã\82¹ï¼\88ã\83\88ã\83©ã\83\83ã\82¯ã\83ªã\82¹ã\83\88ï¼\89ã\81®ã\83\86ã\83¼ã\83\96ã\83«ã\83\87ã\83¼ã\82¿モデル\r
  */\r
 class SequenceTrackListTableModel extends AbstractTableModel {\r
        /**\r
@@ -1592,47 +1599,43 @@ class SequenceTrackListTableModel extends AbstractTableModel {
         */\r
        public enum Column {\r
                /** トラック番号 */\r
-               TRACK_NUMBER("No.", 30, Integer.class),\r
+               TRACK_NUMBER("No.", Integer.class),\r
                /** イベント数 */\r
-               EVENTS("Events", 60, Integer.class),\r
+               EVENTS("Events", Integer.class),\r
                /** Mute */\r
-               MUTE("Mute", 40, Boolean.class),\r
+               MUTE("Mute", Boolean.class),\r
                /** Solo */\r
-               SOLO("Solo", 40, Boolean.class),\r
+               SOLO("Solo", Boolean.class),\r
                /** 録音するMIDIチャンネル */\r
-               RECORD_CHANNEL("RecCh", 60, String.class),\r
+               RECORD_CHANNEL("RecCh", String.class),\r
                /** MIDIチャンネル */\r
-               CHANNEL("Ch", 60, String.class),\r
+               CHANNEL("Ch", String.class),\r
                /** トラック名 */\r
-               TRACK_NAME("Track name", 200, String.class);\r
-               private String title;\r
-               private int widthRatio;\r
-               private Class<?> columnClass;\r
+               TRACK_NAME("Track name", String.class);\r
+               String title;\r
+               Class<?> columnClass;\r
                /**\r
                 * 列の識別子を構築します。\r
                 * @param title 列のタイトル\r
                 * @param widthRatio 幅の割合\r
                 * @param columnClass 列のクラス\r
                 */\r
-               private Column(String title, int widthRatio, Class<?> columnClass) {\r
+               private Column(String title, Class<?> columnClass) {\r
                        this.title = title;\r
-                       this.widthRatio = widthRatio;\r
                        this.columnClass = columnClass;\r
                }\r
-               /**\r
-                * 幅の割合の合計を返します。\r
-                * @return 幅の割合の合計\r
-                */\r
-               public static int totalWidthRatio() {\r
-                       int total = 0;\r
-                       for( Column c : values() ) total += c.widthRatio;\r
-                       return total;\r
-               }\r
        }\r
        /**\r
+        * 親のプレイリスト\r
+        */\r
+       SequenceListTableModel sequenceListTableModel;\r
+       /**\r
         * ラップされたMIDIシーケンス\r
         */\r
        private Sequence sequence;\r
+       /**\r
+        * ラップされたMIDIシーケンスのtickインデックス\r
+        */\r
        private SequenceTickIndex sequenceTickIndex;\r
        /**\r
         * MIDIファイル名\r
@@ -1643,10 +1646,6 @@ class SequenceTrackListTableModel extends AbstractTableModel {
         */\r
        private List<TrackEventListTableModel> trackModelList = new ArrayList<>();\r
        /**\r
-        * 親のプレイリスト\r
-        */\r
-       SequenceListTableModel sequenceListTableModel;\r
-       /**\r
         * 空の {@link SequenceTrackListTableModel} を構築します。\r
         * @param sequenceListTableModel 親のプレイリスト\r
         */\r
@@ -1673,7 +1672,9 @@ class SequenceTrackListTableModel extends AbstractTableModel {
                return sequence == null ? 0 : sequence.getTracks().length;\r
        }\r
        @Override\r
-       public int getColumnCount() { return Column.values().length; }\r
+       public int getColumnCount() {\r
+               return Column.values().length;\r
+       }\r
        /**\r
         * 列名を返します。\r
         * @return 列名\r
@@ -1762,7 +1763,7 @@ class SequenceTrackListTableModel extends AbstractTableModel {
                        if( ch == trackTableModel.getChannel() ) break;\r
                        trackTableModel.setChannel(ch);\r
                        setModified(true);\r
-                       fireTableCellUpdated(row,Column.EVENTS.ordinal());\r
+                       fireTableCellUpdated(row, Column.EVENTS.ordinal());\r
                        break;\r
                }\r
                case TRACK_NAME:\r
@@ -1774,18 +1775,6 @@ class SequenceTrackListTableModel extends AbstractTableModel {
                fireTableCellUpdated(row,column);\r
        }\r
        /**\r
-        * 列に合わせて幅を調整します。\r
-        * @param columnModel テーブル列モデル\r
-        */\r
-       public void sizeColumnWidthToFit(TableColumnModel columnModel) {\r
-               int totalWidth = columnModel.getTotalColumnWidth();\r
-               int totalWidthRatio = Column.totalWidthRatio();\r
-               for( Column c : Column.values() ) {\r
-                       int w = totalWidth * c.widthRatio / totalWidthRatio;\r
-                       columnModel.getColumn(c.ordinal()).setPreferredWidth(w);\r
-               }\r
-       }\r
-       /**\r
         * MIDIシーケンスを返します。\r
         * @return MIDIシーケンス\r
         */\r
index 83ce569..bdbe5fe 100644 (file)
@@ -20,10 +20,10 @@ import javax.sound.midi.MidiChannel;
 import javax.sound.midi.MidiMessage;\r
 import javax.sound.midi.ShortMessage;\r
 import javax.sound.midi.SysexMessage;\r
+import javax.swing.BoundedRangeModel;\r
 import javax.swing.Box;\r
 import javax.swing.BoxLayout;\r
 import javax.swing.ComboBoxModel;\r
-import javax.swing.DefaultBoundedRangeModel;\r
 import javax.swing.DefaultComboBoxModel;\r
 import javax.swing.JButton;\r
 import javax.swing.JCheckBox;\r
@@ -1430,19 +1430,13 @@ class KeySignatureLabel extends JLabel {
 }\r
 \r
 /**\r
- * ベロシティ値範囲モデル\r
- */\r
-class VelocityModel extends DefaultBoundedRangeModel {\r
-       public VelocityModel() { super( 64, 0, 0, 127 ); }\r
-}\r
-/**\r
  * ベロシティ選択ビュー\r
  */\r
 class VelocitySelecter extends JPanel implements ChangeListener {\r
        private static final String     LABEL_PREFIX = "Velocity=";\r
        public JSlider slider;\r
        public JLabel label;\r
-       public VelocitySelecter(VelocityModel model) {\r
+       public VelocitySelecter(BoundedRangeModel model) {\r
                setLayout(new BoxLayout(this, BoxLayout.X_AXIS));\r
                add(label = new JLabel(LABEL_PREFIX + model.getValue(), Label.RIGHT) {{\r
                        setToolTipText("Velocity");\r
index b745b54..6b00441 100644 (file)
@@ -201,7 +201,7 @@ class MidiSequencerModel extends MidiConnecterListModel implements BoundedRangeM
                                        // そうでない場合、次の曲へ進んで再生する。\r
                                        // 次の曲がなければ、そこで終了。\r
                                        boolean isRepeatMode = (Boolean)toggleRepeatAction.getValue(Action.SELECTED_KEY);\r
-                                       if( isRepeatMode || MidiSequencerModel.this.deviceModelList.editorDialog.sequenceListTableModel.loadNext(1) ) {\r
+                                       if( isRepeatMode || loadNext() ) {\r
                                                start();\r
                                        }\r
                                        else {\r
@@ -215,6 +215,9 @@ class MidiSequencerModel extends MidiConnecterListModel implements BoundedRangeM
         * MIDIデバイスモデルリスト\r
         */\r
        private MidiDeviceModelList deviceModelList;\r
+       private boolean loadNext() {\r
+               return deviceModelList.editorDialog.sequenceListTableModel.loadNext(1);\r
+       }\r
        /**\r
         * このシーケンサーの再生スピード調整モデル\r
         */\r
@@ -429,7 +432,7 @@ class MidiSequencerModel extends MidiConnecterListModel implements BoundedRangeM
         * @param sequenceTableModel MIDIトラックリストテーブルモデル\r
         * @return 成功したらtrue\r
         */\r
-       public boolean setSequenceTableModel(SequenceTrackListTableModel sequenceTableModel) {\r
+       public boolean setSequenceTrackListTableModel(SequenceTrackListTableModel sequenceTableModel) {\r
                //\r
                // javax.sound.midi:Sequencer.setSequence() のドキュメントにある\r
                // 「このメソッドは、Sequencer が閉じている場合でも呼び出すことができます。 」\r
@@ -438,17 +441,22 @@ class MidiSequencerModel extends MidiConnecterListModel implements BoundedRangeM
                // この現象を回避するため、あらかじめチェックしてから setSequence() を呼び出している。\r
                //\r
                if( sequenceTableModel != null || getSequencer().isOpen() ) {\r
-                       Sequence seq = null;\r
-                       if( sequenceTableModel != null ) {\r
-                               seq = sequenceTableModel.getSequence();\r
-                       }\r
+                       Sequence sequence = null;\r
+                       if( sequenceTableModel != null )\r
+                               sequence = sequenceTableModel.getSequence();\r
                        try {\r
-                               getSequencer().setSequence(seq);\r
+                               getSequencer().setSequence(sequence);\r
                        } catch ( InvalidMidiDataException e ) {\r
                                e.printStackTrace();\r
                                return false;\r
                        }\r
                }\r
+               if( this.sequenceTableModel != null ) {\r
+                       this.sequenceTableModel.fireTableDataChanged();\r
+               }\r
+               if( sequenceTableModel != null ) {\r
+                       sequenceTableModel.fireTableDataChanged();\r
+               }\r
                this.sequenceTableModel = sequenceTableModel;\r
                fireStateChanged();\r
                return true;\r
index 5b3d69d..d63991b 100644 (file)
@@ -95,7 +95,7 @@ class AppletFrame extends JFrame implements
         */\r
        @Override\r
        public void tableChanged(TableModelEvent e) {\r
-               if( e.getColumn() == SequenceListTableColumnModel.Column.FILENAME.ordinal() )\r
+               if( e.getColumn() == SequenceListTableModel.Column.FILENAME.ordinal() )\r
                        setFilenameToTitle();\r
        }\r
        @Override\r
index 3cd81f7..07a0cb3 100644 (file)
@@ -18,6 +18,8 @@ import java.util.Vector;
 \r
 import javax.sound.midi.MidiChannel;\r
 import javax.sound.midi.Sequence;\r
+import javax.swing.AbstractAction;\r
+import javax.swing.Action;\r
 import javax.swing.BoxLayout;\r
 import javax.swing.JButton;\r
 import javax.swing.JCheckBox;\r
@@ -45,16 +47,62 @@ class NewSequenceDialog extends JDialog {
        };\r
        private static final String INITIAL_CHORD_STRING =\r
                "Key: C\nC G/B | Am Em/G | F C/E | Dm7 G7 C % | F G7 | Csus4 C\n";\r
-       private JTextArea chordText;\r
-       private JTextField seqNameText;\r
-       private JComboBox<Integer> ppqComboBox;\r
-       private TimeSignatureSelecter timesigSelecter;\r
-       private TempoSelecter tempoSelecter;\r
-       private MeasureSelecter measureSelecter;\r
-       private TrackSpecPanel trackSpecPanel;\r
+       private JTextArea chordText = new JTextArea(INITIAL_CHORD_STRING, 18, 30);\r
+       private JTextField seqNameText = new JTextField();\r
+       private JComboBox<Integer> ppqComboBox = new JComboBox<Integer>(PPQList);\r
+       private TimeSignatureSelecter timesigSelecter = new TimeSignatureSelecter();\r
+       private TempoSelecter tempoSelecter = new TempoSelecter();\r
+       private MeasureSelecter measureSelecter = new MeasureSelecter();\r
+       private TrackSpecPanel trackSpecPanel = new TrackSpecPanel() {{\r
+               Music.DrumTrackSpec dts = new Music.DrumTrackSpec(9, "Percussion track");\r
+               dts.velocity = 127;\r
+               addTrackSpec(dts);\r
+               //\r
+               Music.MelodyTrackSpec mts;\r
+               mts = new Music.MelodyTrackSpec(0, "Bass track", new Music.Range(36,48));\r
+               mts.is_bass = true;\r
+               mts.velocity = 96;\r
+               addTrackSpec(mts);\r
+               mts =  new Music.MelodyTrackSpec(1, "Chord track", new Music.Range(60,72));\r
+               addTrackSpec(mts);\r
+               mts = new Music.MelodyTrackSpec(2, "Melody track", new Music.Range(60,84));\r
+               mts.random_melody = true;\r
+               mts.beat_pattern = 0xFFFF;\r
+               mts.continuous_beat_pattern = 0x820A;\r
+               addTrackSpec(mts);\r
+       }};\r
+       /**\r
+        * ダイアログを開くアクション\r
+        */\r
+       public Action openAction = new AbstractAction("New") {\r
+               {\r
+                       String tooltip = "Generate new song - 新しい曲を生成";\r
+                       putValue(Action.SHORT_DESCRIPTION, tooltip);\r
+               }\r
+               @Override\r
+               public void actionPerformed(ActionEvent e) { setVisible(true); }\r
+       };\r
        private MidiEditor midiEditor;\r
+       /**\r
+        * MIDIシーケンス生成アクション\r
+        */\r
+       public Action generateAction = new AbstractAction(\r
+               "Generate & Add to PlayList",\r
+               new ButtonIcon(ButtonIcon.EJECT_ICON)\r
+       ) {\r
+               @Override\r
+               public void actionPerformed(ActionEvent e) {\r
+                       midiEditor.addSequenceAndPlay(getMidiSequence());\r
+                       NewSequenceDialog.this.setVisible(false);\r
+               }\r
+       };\r
+       /**\r
+        * 新しいMIDIシーケンスを生成するダイアログを構築します。\r
+        * @param midiEditor シーケンス追加先エディタ\r
+        */\r
        public NewSequenceDialog(MidiEditor midiEditor) {\r
                this.midiEditor = midiEditor;\r
+               trackSpecPanel.setChannels(midiEditor.virtualMidiDevice.getChannels());\r
                setTitle("Generate new sequence - " + ChordHelperApplet.VersionInfo.NAME);\r
                add(new JTabbedPane() {{\r
                        add("Sequence", new JPanel() {{\r
@@ -62,13 +110,13 @@ class NewSequenceDialog extends JDialog {
                                add(new JPanel() {{\r
                                        setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));\r
                                        add(new JLabel("Sequence name:"));\r
-                                       add(seqNameText = new JTextField());\r
+                                       add(seqNameText);\r
                                }});\r
                                add(new JPanel() {{\r
                                        setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));\r
                                        add(new JLabel("Resolution in PPQ ="));\r
-                                       add(ppqComboBox = new JComboBox<Integer>(PPQList));\r
-                                       add(measureSelecter = new MeasureSelecter());\r
+                                       add(ppqComboBox);\r
+                                       add(measureSelecter);\r
                                }});\r
                                add(new JButton("Randomize (Tempo, Time signature, Chord progression)") {{\r
                                        setMargin(ZERO_INSETS);\r
@@ -83,10 +131,10 @@ class NewSequenceDialog extends JDialog {
                                }});\r
                                add(new JPanel() {{\r
                                        setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));\r
-                                       add(tempoSelecter = new TempoSelecter());\r
+                                       add(tempoSelecter);\r
                                        add(new JPanel() {{\r
                                                add(new JLabel("Time signature ="));\r
-                                               add(timesigSelecter = new TimeSignatureSelecter());\r
+                                               add(timesigSelecter);\r
                                        }});\r
                                }});\r
                                add(new JPanel() {{\r
@@ -138,62 +186,22 @@ class NewSequenceDialog extends JDialog {
                                                });\r
                                        }});\r
                                }});\r
-                               add(new JScrollPane(\r
-                                       chordText = new JTextArea(INITIAL_CHORD_STRING, 18, 30)\r
-                               ));\r
+                               add(new JScrollPane(chordText));\r
                                add(new JPanel() {{\r
                                        setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));\r
-                                       add(new JButton(\r
-                                               "Generate & Add to PlayList",\r
-                                               new ButtonIcon(ButtonIcon.EJECT_ICON)\r
-                                       ) {{\r
-                                               setMargin(ZERO_INSETS);\r
-                                               addActionListener(new ActionListener() {\r
-                                                       @Override\r
-                                                       public void actionPerformed(ActionEvent e) {\r
-                                                               NewSequenceDialog.this.midiEditor.addSequenceAndPlay(getMidiSequence());\r
-                                                               NewSequenceDialog.this.setVisible(false);\r
-                                                       }\r
-                                               });\r
-                                       }});\r
+                                       add(new JButton(generateAction){{setMargin(ZERO_INSETS);}});\r
                                }});\r
                        }});\r
-                       add("Track", trackSpecPanel = new TrackSpecPanel());\r
+                       add("Track", trackSpecPanel);\r
                }});\r
                setBounds( 250, 200, 600, 540 );\r
-               //\r
-               // Create track specs\r
-               //\r
-               Music.MelodyTrackSpec mts;\r
-               Music.DrumTrackSpec dts;\r
-               //\r
-               dts = new Music.DrumTrackSpec( 9, "Percussion track" );\r
-               dts.velocity = 127;\r
-               trackSpecPanel.addTrackSpec(dts);\r
-               //\r
-               mts = new Music.MelodyTrackSpec(0, "Bass track", new Music.Range(36,48));\r
-               mts.is_bass = true;\r
-               mts.velocity = 96;\r
-               trackSpecPanel.addTrackSpec(mts);\r
-               //\r
-               mts =  new Music.MelodyTrackSpec(1, "Chord track", new Music.Range(60,72));\r
-               trackSpecPanel.addTrackSpec(mts);\r
-               //\r
-               mts = new Music.MelodyTrackSpec(2, "Melody track", new Music.Range(60,84));\r
-               mts.random_melody = true;\r
-               mts.beat_pattern = 0xFFFF;\r
-               mts.continuous_beat_pattern = 0x820A;\r
-               trackSpecPanel.addTrackSpec(mts);\r
-       }\r
-       private Music.ChordProgression getChordProgression() {\r
-               return new Music.ChordProgression(chordText.getText());\r
        }\r
        /**\r
-        * 送信用のMIDIチャンネルを設定します。\r
-        * @param midiChannels MIDIチャンネル\r
+        * 新しいコード進行を生成して返します。\r
+        * @return 新しいコード進行\r
         */\r
-       public void setChannels(MidiChannel[] midiChannels) {\r
-               trackSpecPanel.setChannels(midiChannels);\r
+       private Music.ChordProgression getChordProgression() {\r
+               return new Music.ChordProgression(chordText.getText());\r
        }\r
        /**\r
         * MIDIシーケンスを生成して返します。\r
index f4484f8..8e08516 100644 (file)
@@ -25,6 +25,7 @@ import java.util.Vector;
 import javax.sound.midi.MidiChannel;\r
 import javax.swing.AbstractAction;\r
 import javax.swing.Action;\r
+import javax.swing.BoundedRangeModel;\r
 import javax.swing.Box;\r
 import javax.swing.BoxLayout;\r
 import javax.swing.DefaultBoundedRangeModel;\r
@@ -90,7 +91,7 @@ public class PianoKeyboard extends JComponent {
 \r
        DefaultBoundedRangeModel octaveRangeModel;\r
        DefaultBoundedRangeModel octaveSizeModel;\r
-       VelocityModel velocityModel = new VelocityModel();\r
+       BoundedRangeModel velocityModel = new DefaultBoundedRangeModel(64, 0, 0, 127);\r
        DefaultMidiChannelComboBoxModel\r
                midiChComboboxModel = new DefaultMidiChannelComboBoxModel();\r
 \r