/* * Copyright (C) 2015-2017 たんらる */ package fourthline.mabiicco.ui.editor; import static org.junit.Assert.*; import java.awt.event.ActionEvent; import java.awt.event.InputEvent; import java.awt.event.MouseEvent; import java.lang.reflect.Field; import java.util.List; import javax.swing.JViewport; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import fourthline.UseLoadingDLS; import fourthline.mabiicco.IEditStateObserver; import fourthline.mabiicco.MabiIccoProperties; import fourthline.mabiicco.midi.IPlayNote; import fourthline.mabiicco.ui.IMMLManager; import fourthline.mabiicco.ui.MMLSeqView; import fourthline.mabiicco.ui.MMLTrackView; import fourthline.mabiicco.ui.PianoRollView; import fourthline.mmlTools.MMLEventList; import fourthline.mmlTools.MMLNoteEvent; import fourthline.mmlTools.MMLTrack; import fourthline.mmlTools.core.UndefinedTickException; public final class MMLEditorTest extends UseLoadingDLS { private static boolean activePartSwitch; @BeforeClass public static void initialize() { activePartSwitch = MabiIccoProperties.getInstance().activePartSwitch.get(); } @AfterClass public static void cleanup() { MabiIccoProperties.getInstance().activePartSwitch.set( activePartSwitch ); } private MMLEditor editor; private IMMLManager mmlManager; private PianoRollView pianoRollView; private int playingNote = -1; @Before public void initializeObj() throws Exception { this.mmlManager = new MMLSeqView(null); MMLTrackView.getInstance(0, null, mmlManager).setSelectMMLPartOfIndex(0); Field f = MMLSeqView.class.getDeclaredField("pianoRollView"); f.setAccessible(true); JViewport viewport = new JViewport(); this.pianoRollView = (PianoRollView) f.get(this.mmlManager); int height = pianoRollView.getTotalHeight(); viewport.setBounds(0, 0, 200, height); this.pianoRollView.setViewportAndParent(viewport, mmlManager); this.editor = new MMLEditor(null, new IPlayNote() { @Override public void playNote(int note, int velocity) { playingNote = note; } @Override public void playNote(int note[], int velocity) { playingNote = note[0]; } @Override public void offNote() { playingNote = -1; } }, this.pianoRollView, this.mmlManager); editor.setEditStateObserver(new IEditStateObserver() { @Override public void notifyUpdateEditState() {} }); } private EditMode getEditMode() throws Exception { Field f = MMLEditor.class.getDeclaredField("editMode"); f.setAccessible(true); return (EditMode) f.get(editor); } /** * ノートを挿入して移動する. * @throws Exception */ @Test public void test_insertMoveNote() throws Exception { List<MMLNoteEvent> noteEventList = mmlManager.getActiveMMLPart().getMMLNoteEventList(); assertEquals(0, noteEventList.size()); assertEquals(-1, playingNote); assertEquals(false, editor.hasSelectedNote()); int note1 = pianoRollView.convertY2Note(200); int note2 = pianoRollView.convertY2Note(100); long tickOffset1 = 0; long tickOffset2 = pianoRollView.convertXtoTick(100); tickOffset2 -= ( tickOffset2 % editor.getEditAlign() ); MouseEvent mouseEvent1 = new MouseEvent(pianoRollView, 0, 0, InputEvent.BUTTON1_DOWN_MASK, 0, 200, 1, false); MouseEvent mouseEvent2 = new MouseEvent(pianoRollView, 0, 0, InputEvent.BUTTON1_DOWN_MASK, 100, 100, 1, false); // マウスクリックによる挿入ノート候補選択状態. assertEquals(EditMode.SELECT, getEditMode()); editor.mousePressed(mouseEvent1); assertEquals(EditMode.INSERT, getEditMode()); assertEquals(true, editor.hasSelectedNote()); assertEquals(note1, playingNote); assertEquals(0, noteEventList.size()); // マウスリリースによる挿入確定. editor.mouseReleased(mouseEvent1); assertEquals(EditMode.SELECT, getEditMode()); assertEquals(false, editor.hasSelectedNote()); assertEquals(1, noteEventList.size()); assertEquals(note1, noteEventList.get(0).getNote()); assertEquals(tickOffset1, noteEventList.get(0).getTickOffset()); assertEquals(-1, playingNote); // 追加したノートをクリック. editor.mousePressed(mouseEvent1); assertEquals(EditMode.MOVE, getEditMode()); assertEquals(true, editor.hasSelectedNote()); assertEquals(note1, playingNote); assertEquals(tickOffset1, noteEventList.get(0).getTickOffset()); // ノート移動. editor.mouseDragged(mouseEvent2); assertEquals(EditMode.MOVE, getEditMode()); assertEquals(true, editor.hasSelectedNote()); assertEquals(note2, playingNote); assertEquals(tickOffset2, noteEventList.get(0).getTickOffset()); // マウスリリースによる挿入確定. editor.mouseReleased(mouseEvent1); assertEquals(EditMode.SELECT, getEditMode()); assertEquals(true, editor.hasSelectedNote()); assertEquals(1, noteEventList.size()); assertEquals(note2, noteEventList.get(0).getNote()); assertEquals(tickOffset2, noteEventList.get(0).getTickOffset()); assertEquals(-1, playingNote); } /** * ノートの端をつまんで tickを変更する. * @throws Exception */ @Test public void test_lengthModify() throws Exception { List<MMLNoteEvent> noteEventList = mmlManager.getActiveMMLPart().getMMLNoteEventList(); // 初期ノートをつまんで、1/4 -> 1/2 にする. int note = 80; MMLNoteEvent note1 = new MMLNoteEvent(note, 96, 0); MMLNoteEvent note2 = new MMLNoteEvent(note, 96*2, 0); noteEventList.add(new MMLNoteEvent(note, 96, 0)); int y = pianoRollView.convertNote2Y(note); int x1 = pianoRollView.convertTicktoX(95); int x2 = pianoRollView.convertTicktoX(96*2-1); MouseEvent mouseEvent1 = new MouseEvent(pianoRollView, 0, 0, InputEvent.BUTTON1_DOWN_MASK, x1, y, 1, false); MouseEvent mouseEvent2 = new MouseEvent(pianoRollView, 0, 0, InputEvent.BUTTON1_DOWN_MASK, x2, y, 1, false); // マウスクリックでノートの長さ変更開始. assertEquals(note1.toString(), noteEventList.get(0).toString()); assertEquals(EditMode.SELECT, getEditMode()); editor.mousePressed(mouseEvent1); assertEquals(EditMode.LENGTH, getEditMode()); assertEquals(true, editor.hasSelectedNote()); assertEquals(note, playingNote); assertEquals(1, noteEventList.size()); // 変更位置までドラッグ. editor.mouseDragged(mouseEvent2); assertEquals(EditMode.LENGTH, getEditMode()); assertEquals(true, editor.hasSelectedNote()); assertEquals(note, playingNote); assertEquals(1, noteEventList.size()); // 変更確定. editor.mouseReleased(mouseEvent2); assertEquals(EditMode.SELECT, getEditMode()); assertEquals(false, editor.hasSelectedNote()); assertEquals(-1, playingNote); assertEquals(1, noteEventList.size()); assertEquals(note2.toString(), noteEventList.get(0).toString()); } /** * 範囲選択. * @throws Exception */ private void check_areaSelect() throws Exception { MMLEventList eventList = mmlManager.getActiveMMLPart(); // note1iのノートだけを範囲選択してカット&ペースト, コピー&ペースト, delete. int note1i = 80; int note2i = 40; MMLNoteEvent note1 = new MMLNoteEvent(note1i, 96, 0); MMLNoteEvent note2 = new MMLNoteEvent(note2i, 96, 96); MMLNoteEvent note3 = new MMLNoteEvent(note1i, 96, 96+96); eventList.addMMLNoteEvent(note1); eventList.addMMLNoteEvent(note2); eventList.addMMLNoteEvent(note3); int y = pianoRollView.convertNote2Y(note1i); int x1 = pianoRollView.convertTicktoX(30); int x2 = pianoRollView.convertTicktoX(96+96+30); // 右クリック指定. MouseEvent mouseEvent1 = new MouseEvent(pianoRollView, 0, 0, InputEvent.BUTTON3_DOWN_MASK, x1, y-1, 1, false); MouseEvent mouseEvent2 = new MouseEvent(pianoRollView, 0, 0, InputEvent.BUTTON3_DOWN_MASK, x2, y+1, 1, false); // エリア右クリックによる選択開始. assertEquals(EditMode.SELECT, getEditMode()); editor.mousePressed(mouseEvent1); assertEquals(EditMode.AREA, getEditMode()); assertEquals(false, editor.hasSelectedNote()); // まだ選択できるノートはない. assertEquals(3, eventList.getMMLNoteEventList().size()); // ドラッグによるエリア確定. editor.mouseDragged(mouseEvent2); assertEquals(EditMode.AREA, getEditMode()); assertEquals(true, editor.hasSelectedNote()); // 選択状態になる. // マウスリリース. editor.mouseReleased(mouseEvent2); assertEquals(EditMode.SELECT, getEditMode()); assertEquals(true, editor.hasSelectedNote()); } /** * 範囲選択後Cutする. * @throws Exception */ @Test public void test_areaSelectCut() throws Exception { MMLEventList eventList = mmlManager.getActiveMMLPart(); // 範囲選択. check_areaSelect(); // カット&ペースト. assertEquals(">>g+4<<<e4>>>g+4", eventList.toMMLString()); editor.selectedCut(); assertEquals("r4<e4", eventList.toMMLString()); editor.paste(96+96); assertEquals("r4<e4>>>g+4r4g+4", eventList.toMMLString()); } /** * 範囲選択後Copyする. * @throws Exception */ @Test public void test_areaSelectCopy() throws Exception { MMLEventList eventList = mmlManager.getActiveMMLPart(); // 範囲選択. check_areaSelect(); // コピー&ペースト. assertEquals(">>g+4<<<e4>>>g+4", eventList.toMMLString()); editor.selectedCopy(); assertEquals(">>g+4<<<e4>>>g+4", eventList.toMMLString()); editor.paste(96+96+96); assertEquals(">>g+4<<<e4>>>g+4g+4r4g+4", eventList.toMMLString()); } /** * 範囲選択後Deleteする. * @throws Exception */ @Test public void test_areaSelectDelete() throws Exception { MMLEventList eventList = mmlManager.getActiveMMLPart(); // 範囲選択. check_areaSelect(); // delete. assertEquals(">>g+4<<<e4>>>g+4", eventList.toMMLString()); editor.selectedDelete(); assertEquals("r4<e4", eventList.toMMLString()); } /** * すべて選択する. 選択されたことはDeleteして消えたことで判定. * @throws UndefinedTickException */ @Test public void test_selectAll() throws UndefinedTickException { mmlManager.setMMLselectedTrack(new MMLTrack().setMML("MML@ccc,ddd,eee")); editor.selectAll(); editor.selectedDelete(); int index = mmlManager.getActiveTrackIndex(); assertEquals("MML@,ddd,eee;", mmlManager.getMMLScore().getTrack(index).getOriginalMML()); } /** * @param mml 入力MML * @param expect 期待MML * @param mode Changeするモード * @param select 選択したノートを使う * @throws Exception */ private void check_changePart(String mml, String expect, MMLEditor.ChangePartAction mode, boolean select) throws Exception { MMLTrack track = new MMLTrack().setMML(mml); mmlManager.setMMLselectedTrack(track); MMLEventList from = track.getMMLEventAtIndex(0); MMLEventList to = track.getMMLEventAtIndex(2); if (select) { // select MMLNoteEvent note = new MMLEventList("ccc").getMMLNoteEventList().get(1); int y = pianoRollView.convertNote2Y( note.getNote()); int x = pianoRollView.convertTicktoX( note.getTickOffset() ); MouseEvent e = new MouseEvent(pianoRollView, 0, 0, InputEvent.BUTTON1_DOWN_MASK, x+1, y+1, 1, false); editor.mousePressed(e); assertEquals(EditMode.MOVE, getEditMode()); editor.mouseReleased(e); assertEquals(EditMode.SELECT, getEditMode()); } editor.changePart(from, to, select, mode); mmlManager.updateActivePart(true); assertEquals(expect, track.getOriginalMML()); } /** * パートごとの交換. * @throws Exception */ @Test public void test_changePartSwap() throws Exception { String mml = "MML@ccc,ddd,eee;"; String expect = "MML@eee,ddd,ccc;"; check_changePart(mml, expect, MMLEditor.ChangePartAction.SWAP, false); } /** * パートごとの移動. * @throws Exception */ @Test public void test_changePartMove() throws Exception { String mml = "MML@ccc,ddd,eee;"; String expect = "MML@,ddd,ccc;"; check_changePart(mml, expect, MMLEditor.ChangePartAction.MOVE, false); } /** * パートごとのコピー * @throws Exception */ @Test public void test_changePartCopy() throws Exception { String mml = "MML@ccc,ddd,eee;"; String expect = "MML@ccc,ddd,ccc;"; check_changePart(mml, expect, MMLEditor.ChangePartAction.COPY, false); } /** * 選択された部分の交換. * @throws Exception */ @Test public void test_changePartSelectedSwap() throws Exception { String mml = "MML@ccc,ddd,eee;"; String expect = "MML@cec,ddd,ece;"; check_changePart(mml, expect, MMLEditor.ChangePartAction.SWAP, true); } /** * 選択された部分の移動. * @throws Exception */ @Test public void test_changePartSelectedMove() throws Exception { String mml = "MML@ccc,ddd,eee;"; String expect = "MML@crc,ddd,ece;"; check_changePart(mml, expect, MMLEditor.ChangePartAction.MOVE, true); } /** * 選択された部分のコピー. * @throws Exception */ @Test public void test_changePartSelectedCopy() throws Exception { String mml = "MML@ccc,ddd,eee;"; String expect = "MML@ccc,ddd,ece;"; check_changePart(mml, expect, MMLEditor.ChangePartAction.COPY, true); } /** * Shiftで複数選択してDelete. */ @Test public void test_shiftSelectAndDelete() { MMLTrack track = new MMLTrack().setMML("MML@ccddeeff;"); mmlManager.setMMLselectedTrack(track); // select MMLNoteEvent note1 = track.getMMLEventAtIndex(0).getMMLNoteEventList().get(2); MMLNoteEvent note2 = track.getMMLEventAtIndex(0).getMMLNoteEventList().get(5); int y1 = pianoRollView.convertNote2Y( note1.getNote()); int y2 = pianoRollView.convertNote2Y( note2.getNote()); int x1 = pianoRollView.convertTicktoX( note1.getTickOffset() ); int x2 = pianoRollView.convertTicktoX( note2.getTickOffset() ); MouseEvent e1 = new MouseEvent(pianoRollView, 0, 0, InputEvent.BUTTON1_DOWN_MASK, x1+1, y1+1, 1, false); MouseEvent e2 = new MouseEvent(pianoRollView, 0, 0, InputEvent.BUTTON1_DOWN_MASK | ActionEvent.SHIFT_MASK, x2+1, y2+1, 1, false); editor.mousePressed(e1); editor.mouseReleased(e1); editor.mousePressed(e2); editor.mouseReleased(e2); editor.selectedDelete(); assertEquals("MML@ccr1ff,,;", track.getOriginalMML()); } /** * クリック時に他のパートを選択する. */ @Test public void test_selectOtherPartMode() { MMLTrack track = new MMLTrack().setMML("MML@,ccc;"); mmlManager.setMMLselectedTrack(track); MabiIccoProperties.getInstance().activePartSwitch.set(true); // select MMLNoteEvent note1 = track.getMMLEventAtIndex(1).getMMLNoteEventList().get(2); int y1 = pianoRollView.convertNote2Y( note1.getNote()); int x1 = pianoRollView.convertTicktoX( note1.getTickOffset() ); MouseEvent e1 = new MouseEvent(pianoRollView, 0, 0, InputEvent.BUTTON1_DOWN_MASK, x1+1, y1+1, 1, false); // メロディーパート. assertTrue(track.getMMLEventAtIndex(0) == mmlManager.getActiveMMLPart()); editor.mousePressed(e1); editor.mouseReleased(e1); // 和音パート. assertTrue(track.getMMLEventAtIndex(1) == mmlManager.getActiveMMLPart()); } /** * 右クリックして, 指定された処理を実行後のMMLをテストする. * @param input * @param expect * @param selectIndex 右クリックするノートindex * @param r */ private void checkOneSelectActionButton3(String input, String expect, int selectIndex, Runnable r) { MMLTrack track = new MMLTrack().setMML(input); mmlManager.setMMLselectedTrack(track); // select MMLNoteEvent note1 = track.getMMLEventAtIndex(0).getMMLNoteEventList().get(selectIndex); int y1 = pianoRollView.convertNote2Y( note1.getNote() ); int x1 = pianoRollView.convertTicktoX( note1.getTickOffset() ); MouseEvent e1 = new MouseEvent(pianoRollView, 0, 0, InputEvent.BUTTON3_DOWN_MASK, x1+1, y1+1, 1, false); editor.mousePressed(e1); editor.mouseReleased(e1); r.run(); assertEquals(expect, track.getOriginalMML()); } @Test public void test_selectPreviousAll() { checkOneSelectActionButton3("MML@aabebaa;", "MML@r1baa,,;", 3, () -> { editor.selectPreviousAll(); editor.selectedDelete(); }); } @Test public void test_selectAfterAll() { checkOneSelectActionButton3("MML@aabebaa;", "MML@aab,,;", 3, () -> { editor.selectAfterAll(); editor.selectedDelete(); }); } }