Java代码

  1. package com.xfherun.midiforge.gui;
  2. import com.xfherun.languages.Language;
  3. import com.xfherun.midiforge.animations.LoadAnimation;
  4. import com.xfherun.midiforge.exits.Exit;
  5. import com.xfherun.midiforge.gui.dialogs.MIDIForgeTickLoopDialog;
  6. import com.xfherun.midiforge.gui.renderer.MIDIRendererPanel;
  7. import com.xfherun.midiforge.gui.ui.componentuis.MIDIForgeMenuBarUI;
  8. import com.xfherun.midiforge.gui.ui.componentuis.MIDIForgeMenuUI;
  9. import com.xfherun.midiforge.languages.SystemLanguage;
  10. import com.xfherun.midiforge.logger.Logger;
  11. import com.xfherun.midiforge.main.References;
  12. import com.xfherun.midiforge.utils.GraphicsUtilities;
  13. import com.xfherun.midiforge.utils.MathUtilities;
  14. import com.xfherun.midiforge.utils.ThreadUtilities;
  15. import com.xfherun.midiplayer.DefaultMidiRenderer;
  16. import com.xfherun.midiplayer.LoopOption;
  17. import com.xfherun.midiplayer.MidiSequence;
  18. import com.xfherun.midiplayer.PianoKeyboardRenderer;
  19. import javax.sound.midi.MidiSystem;
  20. import javax.sound.midi.MidiUnavailableException;
  21. import javax.sound.midi.Receiver;
  22. import javax.swing.*;
  23. import javax.swing.filechooser.FileNameExtensionFilter;
  24. import java.awt.*;
  25. import java.awt.datatransfer.DataFlavor;
  26. import java.awt.datatransfer.Transferable;
  27. import java.awt.datatransfer.UnsupportedFlavorException;
  28. import java.awt.event.*;
  29. import java.io.File;
  30. import java.io.IOException;
  31. import java.util.ArrayList;
  32. import java.util.LinkedHashSet;
  33. import java.util.List;
  34. /**
  35. * 主窗口
  36. * project: MidiForge
  37. *
  38. * @author xfherun 何润
  39. */
  40. public class MainWindow extends JFrame
  41. {
  42. /**
  43. * 窗口是否显示
  44. */
  45. protected volatile boolean rendering = false;
  46. /**
  47. * 默认的空参构造 -> class: MainWindow
  48. *
  49. * @author xfherun 何润
  50. */
  51. public MainWindow()
  52. {
  53. initialization();
  54. }
  55. /**
  56. * 关闭窗口
  57. *
  58. * @author xfherun 何润
  59. */
  60. public final void close()
  61. {
  62. implClose();
  63. }
  64. /**
  65. * 实现关闭
  66. *
  67. * @author xfherun 何润
  68. */
  69. protected void implClose()
  70. {
  71. Logger.LOGGER.info("Window closing...");
  72. setVisible(false);
  73. dispose();
  74. Exit.exit(true);
  75. }
  76. /**
  77. * 初始化
  78. *
  79. * @author xfherun 何润
  80. */
  81. protected void initialization()
  82. {
  83. Logger.LOGGER.info("The window starts initializing...");
  84. setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
  85. addWindowListener(new WindowAdapter()
  86. {
  87. @Override
  88. public void windowClosing(WindowEvent e)
  89. {
  90. close();
  91. }
  92. });
  93. setTitle(SystemLanguage.translate("application.window.title"));
  94. try
  95. {
  96. Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
  97. setSize(
  98. MathUtilities.round(screenSize.getWidth() * 0.667),
  99. MathUtilities.round(screenSize.getHeight() * 0.667)
  100. );
  101. }
  102. catch (Throwable e)
  103. {
  104. Logger.LOGGER.error("Unable to set window size!", e);
  105. setSize(850, 480);
  106. }
  107. setLocationRelativeTo(null);
  108. Logger.LOGGER.info("The window size is set to: " + getWidth() + " * " + getHeight());
  109. Logger.LOGGER.info("window position is set to: " + getX() + " * " + getY());
  110. Logger.LOGGER.info("Start initializing the window component...");
  111. initializationComponents();
  112. Logger.LOGGER.info("The window component is initialized!");
  113. Logger.LOGGER.info("The window is initialized!");
  114. }
  115. @Override
  116. public void paint(Graphics g)
  117. {
  118. if (!rendering)
  119. rendering = true;
  120. super.paint(g);
  121. }
  122. /**
  123. * 获取 rendering 的值
  124. *
  125. * @return rendering 的值
  126. * @author xfherun 何润
  127. */
  128. public boolean isRendering()
  129. {
  130. return rendering;
  131. }
  132. /**
  133. * MIDI渲染器面板
  134. */
  135. protected volatile MIDIRendererPanel midiRendererPanel;
  136. /**
  137. * 顶部栏
  138. */
  139. protected volatile JPanel topBar;
  140. /**
  141. * 卡片面板
  142. */
  143. private volatile JPanel cardPanel;
  144. /**
  145. * 创建播放菜单
  146. *
  147. * @return 返回集合
  148. * @author xfherun 何润
  149. */
  150. protected ArrayList<JComponent> createPlayMenus()
  151. {
  152. ArrayList<JComponent> arrayList = new ArrayList<>();
  153. JMenuItem playAndPause = new JMenuItem(SystemLanguage.translate("application.window.home.menubar.menu.play.playAndPause.text"));
  154. JMenuItem stop = new JMenuItem(SystemLanguage.translate("application.window.home.menubar.menu.play.stop.text"));
  155. JMenuItem fwd = new JMenuItem(SystemLanguage.translate("application.window.home.menubar.menu.play.tickForward.text"));
  156. JMenuItem back = new JMenuItem(SystemLanguage.translate("application.window.home.menubar.menu.play.tickBackward.text"));
  157. JCheckBoxMenuItem enableLoop = new JCheckBoxMenuItem(SystemLanguage.translate("application.window.home.menubar.menu.play.enableLoop.text"));
  158. JMenuItem volumeForward = new JMenuItem(SystemLanguage.translate("application.window.home.menubar.menu.play.volumeForward.text"));
  159. JMenuItem volumeBackward = new JMenuItem(SystemLanguage.translate("application.window.home.menubar.menu.play.volumeBackward.text"));
  160. JCheckBoxMenuItem muted = new JCheckBoxMenuItem(SystemLanguage.translate("application.window.home.menubar.menu.play.mute.text"));
  161. {
  162. playAndPause.setAccelerator(KeyStroke.getKeyStroke("SPACE"));
  163. stop.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_E, InputEvent.CTRL_MASK));
  164. fwd.setAccelerator(KeyStroke.getKeyStroke("RIGHT"));
  165. back.setAccelerator(KeyStroke.getKeyStroke("LEFT"));
  166. enableLoop.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L, InputEvent.CTRL_MASK));
  167. volumeForward.setAccelerator(KeyStroke.getKeyStroke("UP"));
  168. volumeBackward.setAccelerator(KeyStroke.getKeyStroke("DOWN"));
  169. muted.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_M, InputEvent.CTRL_MASK));
  170. }
  171. DefaultMidiRenderer renderer = midiRendererPanel.getRenderer();
  172. if (renderer == null)
  173. {
  174. playAndPause.setEnabled(false);
  175. stop.setEnabled(false);
  176. fwd.setEnabled(false);
  177. back.setEnabled(false);
  178. enableLoop.setEnabled(false);
  179. volumeForward.setEnabled(false);
  180. volumeBackward.setEnabled(false);
  181. muted.setEnabled(false);
  182. }
  183. if (renderer != null)
  184. {
  185. playAndPause.addActionListener(e ->
  186. {
  187. if (renderer.isRunning()) renderer.stop();
  188. else renderer.start();
  189. });
  190. stop.addActionListener(e ->
  191. {
  192. renderer.stop();
  193. renderer.setTickPosition(0L);
  194. });
  195. long finalTickStep = 1000000000L;
  196. fwd.addActionListener(e ->
  197. renderer.setTimePosition(renderer.getTimePosition() + finalTickStep));
  198. back.addActionListener(e ->
  199. renderer.setTimePosition(renderer.getTimePosition() - finalTickStep));
  200. muted.setSelected(renderer.isMuted());
  201. muted.addActionListener(e ->
  202. renderer.setMuted(muted.isSelected()));
  203. volumeForward.addActionListener(e ->
  204. {
  205. JSlider volumeSlider = midiRendererPanel.getVolumeSlider();
  206. volumeSlider.setValue(volumeSlider.getValue() + 10);
  207. });
  208. volumeBackward.addActionListener(e ->
  209. {
  210. JSlider volumeSlider = midiRendererPanel.getVolumeSlider();
  211. volumeSlider.setValue(volumeSlider.getValue() - 10);
  212. });
  213. enableLoop.setSelected(midiRendererPanel.isLoop());
  214. enableLoop.addActionListener(e ->
  215. {
  216. if (!enableLoop.isSelected()) midiRendererPanel.setLoop(false, 0L, -1L, 0);
  217. else
  218. {
  219. MIDIForgeTickLoopDialog midiForgeTickLoopDialog = new MIDIForgeTickLoopDialog(MainWindow.this, renderer);
  220. midiForgeTickLoopDialog.setVisible(true);
  221. int loopCount = midiForgeTickLoopDialog.getLoopCount();
  222. LoopOption loopOption = midiForgeTickLoopDialog.getLoopOption();
  223. long startPointLong = midiForgeTickLoopDialog.getStartPointLong();
  224. long endPointLong = midiForgeTickLoopDialog.getEndPointLong();
  225. if (loopOption != null)
  226. {
  227. if (LoopOption.NO_LOOP.equals(loopOption)) return;
  228. if (LoopOption.INDEFINITELY_LOOP.equals(loopOption)) loopCount = -1;
  229. midiRendererPanel.setLoop(true, startPointLong, endPointLong, loopCount);
  230. }
  231. }
  232. });
  233. }
  234. arrayList.add(playAndPause);
  235. arrayList.add(stop);
  236. arrayList.add(fwd);
  237. arrayList.add(back);
  238. arrayList.add(new JPopupMenu.Separator());
  239. arrayList.add(enableLoop);
  240. arrayList.add(new JPopupMenu.Separator());
  241. arrayList.add(volumeForward);
  242. arrayList.add(volumeBackward);
  243. arrayList.add(muted);
  244. return arrayList;
  245. }
  246. /**
  247. * 选择MIDI文件
  248. *
  249. * @param multipleChoices 是否多选
  250. * @return 返回文件数组
  251. * @author xfherun 何润
  252. */
  253. protected File[] selectedMIDIFile(boolean multipleChoices)
  254. {
  255. JFileChooser jFileChooser = new JFileChooser();
  256. jFileChooser.setDialogType(JFileChooser.OPEN_DIALOG);
  257. jFileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
  258. jFileChooser.setMultiSelectionEnabled(multipleChoices);
  259. jFileChooser.setDialogTitle(SystemLanguage.translate("application.utilities.midiFileChooser.window.title"));
  260. jFileChooser.setFileFilter(new FileNameExtensionFilter(
  261. SystemLanguage.translate("application.utilities.typeMIDI.description.text"),
  262. "mid", "midi"
  263. ));
  264. jFileChooser.setSelectedFile(new File("").getAbsoluteFile());
  265. int option = jFileChooser.showOpenDialog(MainWindow.this);
  266. if (option == JFileChooser.APPROVE_OPTION)
  267. {
  268. if (jFileChooser.isMultiSelectionEnabled())
  269. return jFileChooser.getSelectedFiles();
  270. return new File[]{jFileChooser.getSelectedFile()};
  271. }
  272. return null;
  273. }
  274. /**
  275. * 当前MIDI文件
  276. */
  277. protected volatile File currentMIDIFile;
  278. /**
  279. * 使用MIDI接收器
  280. */
  281. private static final boolean useMidiReceiver = true;
  282. /**
  283. * 获取MIDI接收器
  284. *
  285. * @return 返回MIDI接收器
  286. * @author xfherun 何润
  287. */
  288. protected Receiver getMIDIReceiver()
  289. {
  290. if (!useMidiReceiver) return null;
  291. try
  292. {
  293. return MidiSystem.getReceiver();
  294. }
  295. catch (Throwable e)
  296. {
  297. Logger.LOGGER.error("Unable to get a MIDI receiver!", e);
  298. }
  299. return null;
  300. }
  301. /**
  302. * 创建文件菜单
  303. *
  304. * @return 返回集合
  305. * @author xfherun 何润
  306. */
  307. protected ArrayList<JComponent> createFileMenus()
  308. {
  309. ArrayList<JComponent> arrayList = new ArrayList<>();
  310. JMenuItem openSong = new JMenuItem(SystemLanguage.translate("application.window.home.menubar.menu.file.openSong.text"));
  311. JMenuItem reopenSong = new JMenuItem(SystemLanguage.translate("application.window.home.menubar.menu.file.reopenSong.text", (currentMIDIFile != null ? currentMIDIFile.getName() : SystemLanguage.translate("application.window.home.menubar.menu.file.reopenSong.sub.text"))));
  312. JMenuItem closeFile = new JMenuItem(SystemLanguage.translate("application.window.home.menubar.menu.file.closeFile.text"));
  313. JMenu library = new JMenu(SystemLanguage.translate("application.window.home.menubar.menu.file.library.text"));
  314. {
  315. JMenuItem addFile = new JMenuItem(SystemLanguage.translate("application.window.home.menubar.menu.file.library.addFile.text"));
  316. JMenuItem addDirectory = new JMenuItem(SystemLanguage.translate("application.window.home.menubar.menu.file.library.addDirectory.text"));
  317. addFile.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.CTRL_MASK));
  318. addDirectory.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_D, InputEvent.CTRL_MASK));
  319. library.add(addFile);
  320. library.add(addDirectory);
  321. }
  322. openSong.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, InputEvent.CTRL_MASK));
  323. reopenSong.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.CTRL_MASK));
  324. closeFile.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_W, InputEvent.CTRL_MASK));
  325. library.setMnemonic('L');
  326. if (currentMIDIFile == null || !currentMIDIFile.exists() || !currentMIDIFile.isFile())
  327. reopenSong.setEnabled(false);
  328. openSong.addActionListener(e ->
  329. {
  330. File[] files = selectedMIDIFile(false);
  331. if (files != null)
  332. {
  333. File midiFile = files[0];
  334. if (midiFile.getName().toLowerCase().endsWith(".mid") || midiFile.getName().toLowerCase().endsWith(".midi"))
  335. {
  336. ThreadUtilities.asynchronous(that ->
  337. {
  338. Logger.LOGGER.info("Selected MIDI File: " + midiFile.getAbsolutePath());
  339. loadSong(midiFile, getMIDIReceiver());
  340. });
  341. }
  342. }
  343. });
  344. closeFile.addActionListener(e ->
  345. {
  346. if (currentMIDIFile == null) return;
  347. Logger.LOGGER.info("Start closing MIDI files... currentMIDIFile -> " + currentMIDIFile.getAbsolutePath());
  348. closeSong();
  349. });
  350. reopenSong.addActionListener(e ->
  351. {
  352. if (currentMIDIFile == null) return;
  353. File reopenMIDIFile = currentMIDIFile;
  354. if (reopenMIDIFile.exists() && reopenMIDIFile.isFile() && (reopenMIDIFile.getName().toLowerCase().endsWith(".mid") || reopenMIDIFile.getName().toLowerCase().endsWith(".midi")))
  355. {
  356. Logger.LOGGER.info("Start reopening this MIDI song: " + reopenMIDIFile.getAbsolutePath());
  357. ThreadUtilities.asynchronous(that ->
  358. {
  359. closeSong();
  360. loadSong(reopenMIDIFile, getMIDIReceiver());
  361. });
  362. }
  363. else
  364. {
  365. Logger.LOGGER.warn("Invalid MIDI files: " + reopenMIDIFile.getAbsolutePath());
  366. currentMIDIFile = null;
  367. }
  368. });
  369. arrayList.add(openSong);
  370. arrayList.add(reopenSong);
  371. arrayList.add(closeFile);
  372. arrayList.add(new JPopupMenu.Separator());
  373. arrayList.add(library);
  374. return arrayList;
  375. }
  376. /**
  377. * 创建视图菜单
  378. *
  379. * @return 返回集合
  380. * @author xfherun 何润
  381. */
  382. protected ArrayList<JComponent> createViewMenus()
  383. {
  384. DefaultMidiRenderer renderer = midiRendererPanel.getRenderer();
  385. ArrayList<JComponent> arrayList = new ArrayList<>();
  386. JCheckBoxMenuItem playbackToolbar = new JCheckBoxMenuItem(SystemLanguage.translate("application.window.home.menubar.menu.view.playbackToolbar.text"));
  387. JCheckBoxMenuItem libraryPanel = new JCheckBoxMenuItem(SystemLanguage.translate("application.window.home.menubar.menu.view.libraryPanel.text"));
  388. JCheckBoxMenuItem pianoKeyboard = new JCheckBoxMenuItem(SystemLanguage.translate("application.window.home.menubar.menu.view.pianoKeyboard.text"));
  389. JCheckBoxMenuItem noteLabels = new JCheckBoxMenuItem(SystemLanguage.translate("application.window.home.menubar.menu.view.noteLabels.text"));
  390. JMenu changedPianoKeyboardOrientation = new JMenu(SystemLanguage.translate("application.window.home.menubar.menu.view.changedPianoKeyboardOrientation.text"));
  391. JCheckBoxMenuItem alwaysOnTop = new JCheckBoxMenuItem(SystemLanguage.translate("application.window.home.menubar.menu.view.alwaysOnTop.text"));
  392. JCheckBoxMenuItem fullScreen = new JCheckBoxMenuItem(SystemLanguage.translate("application.window.home.menubar.menu.view.fullScreen.text"));
  393. playbackToolbar.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_T, InputEvent.CTRL_MASK));
  394. libraryPanel.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Y, InputEvent.CTRL_MASK));
  395. pianoKeyboard.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_K, InputEvent.CTRL_MASK));
  396. noteLabels.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, InputEvent.CTRL_MASK));
  397. changedPianoKeyboardOrientation.setMnemonic('C');
  398. playbackToolbar.setSelected(midiRendererPanel.getTopBarPanel().isVisible());
  399. playbackToolbar.addActionListener(e ->
  400. {
  401. midiRendererPanel.getTopBarPanel().setVisible(playbackToolbar.isSelected());
  402. midiRendererPanel.updateSize();
  403. GraphicsUtilities.updateComponents(midiRendererPanel, MainWindow.this);
  404. });
  405. fullScreen.setSelected(isUndecorated());
  406. fullScreen.addActionListener(e ->
  407. {
  408. if (fullScreen.isSelected())
  409. midiRendererPanel.fullScreenOn();
  410. else midiRendererPanel.fullScreenOff();
  411. });
  412. JMenuItem h = new JMenuItem(SystemLanguage.translate("application.window.home.menubar.menu.view.changedPianoKeyboardOrientation.H.text"));
  413. JMenuItem v = new JMenuItem(SystemLanguage.translate("application.window.home.menubar.menu.view.changedPianoKeyboardOrientation.V.text"));
  414. h.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_H, InputEvent.CTRL_MASK));
  415. v.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_MASK));
  416. h.setEnabled(false);
  417. v.setEnabled(false);
  418. pianoKeyboard.setEnabled(false);
  419. noteLabels.setEnabled(false);
  420. if (renderer != null)
  421. {
  422. h.setEnabled(true);
  423. v.setEnabled(true);
  424. pianoKeyboard.setEnabled(true);
  425. noteLabels.setEnabled(true);
  426. h.addActionListener(e ->
  427. {
  428. renderer.getPianoKeyboardRenderer().setOrientation(PianoKeyboardRenderer.HORIZONTAL);
  429. midiRendererPanel.updateSize();
  430. });
  431. v.addActionListener(e ->
  432. {
  433. renderer.getPianoKeyboardRenderer().setOrientation(PianoKeyboardRenderer.VERTICAL);
  434. midiRendererPanel.updateSize();
  435. });
  436. pianoKeyboard.addActionListener(e ->
  437. {
  438. });
  439. noteLabels.addActionListener(e ->
  440. {
  441. });
  442. }
  443. changedPianoKeyboardOrientation.add(h);
  444. changedPianoKeyboardOrientation.add(v);
  445. alwaysOnTop.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.CTRL_MASK));
  446. fullScreen.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.ALT_MASK));
  447. {
  448. alwaysOnTop.setSelected(isAlwaysOnTop());
  449. }
  450. {
  451. alwaysOnTop.addActionListener(e -> setAlwaysOnTop(alwaysOnTop.isSelected()));
  452. }
  453. arrayList.add(playbackToolbar);
  454. arrayList.add(libraryPanel);
  455. arrayList.add(pianoKeyboard);
  456. arrayList.add(noteLabels);
  457. arrayList.add(changedPianoKeyboardOrientation);
  458. arrayList.add(new JPopupMenu.Separator());
  459. arrayList.add(alwaysOnTop);
  460. arrayList.add(fullScreen);
  461. return arrayList;
  462. }
  463. /**
  464. * 创建选项菜单
  465. *
  466. * @return 返回集合
  467. * @author xfherun 何润
  468. */
  469. protected ArrayList<JComponent> createOptionsMenus()
  470. {
  471. ArrayList<JComponent> arrayList = new ArrayList<>();
  472. JMenuItem preferences = new JMenuItem(SystemLanguage.translate("application.window.home.menubar.menu.options.preferences.text"));
  473. preferences.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, InputEvent.CTRL_MASK));
  474. arrayList.add(preferences);
  475. return arrayList;
  476. }
  477. /**
  478. * 创建帮助菜单
  479. *
  480. * @return 返回集合
  481. * @author xfherun 何润
  482. */
  483. protected ArrayList<JComponent> createHelpMenus()
  484. {
  485. ArrayList<JComponent> arrayList = new ArrayList<>();
  486. JMenuItem online = new JMenuItem(SystemLanguage.translate("application.window.home.menubar.menu.help.online.text"));
  487. JMenuItem about = new JMenuItem(SystemLanguage.translate("application.window.home.menubar.menu.help.about.text"));
  488. online.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_I, InputEvent.CTRL_MASK));
  489. about.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_U, InputEvent.CTRL_MASK));
  490. arrayList.add(online);
  491. arrayList.add(about);
  492. return arrayList;
  493. }
  494. /**
  495. * 初始化窗口组件
  496. *
  497. * @author xfherun 何润
  498. */
  499. protected void initializationComponents()
  500. {
  501. cardPanel = new JPanel();
  502. cardPanel.setOpaque(true);
  503. cardPanel.setLayout(new CardLayout());
  504. {
  505. topBar = new JPanel();
  506. topBar.setOpaque(true);
  507. topBar.setBackground(Color.BLACK);
  508. topBar.setLayout(new BorderLayout());
  509. topBar.setMinimumSize(new Dimension(0, 50));
  510. topBar.setMaximumSize(new Dimension(Integer.MAX_VALUE, 50));
  511. topBar.setPreferredSize(new Dimension(0, 50));
  512. JLabel logoTextLabel = new JLabel();
  513. logoTextLabel.setForeground(new Color(217, 217, 217, 255));
  514. logoTextLabel.setBorder(BorderFactory.createEmptyBorder(0, 50, 0, 50));
  515. logoTextLabel.setFont(new Font(logoTextLabel.getFont().getFamily(), Font.BOLD, MathUtilities.round(topBar.getPreferredSize().getHeight() * 0.61)));
  516. logoTextLabel.setText(References.APPLICATION_NAME);
  517. topBar.add(logoTextLabel, BorderLayout.WEST);
  518. JMenuBar menuBar = new JMenuBar();
  519. JMenu file = createMenu(SystemLanguage.translate("application.window.home.menubar.menu.file.text"));
  520. JMenu play = createMenu(SystemLanguage.translate("application.window.home.menubar.menu.play.text"));
  521. JMenu view = createMenu(SystemLanguage.translate("application.window.home.menubar.menu.view.text"));
  522. JMenu options = createMenu(SystemLanguage.translate("application.window.home.menubar.menu.options.text"));
  523. JMenu help = createMenu(SystemLanguage.translate("application.window.home.menubar.menu.help.text"));
  524. file.setMnemonic('F');
  525. play.setMnemonic('P');
  526. view.setMnemonic('V');
  527. options.setMnemonic('O');
  528. help.setMnemonic('H');
  529. file.addItemListener(e ->
  530. {
  531. Logger.LOGGER.info("Start Creation Menu: File");
  532. JMenu source = (JMenu) e.getSource();
  533. source.removeAll();
  534. for (JComponent menu : createFileMenus())
  535. source.add(menu);
  536. GraphicsUtilities.updateComponents(source);
  537. });
  538. play.addItemListener(e ->
  539. {
  540. Logger.LOGGER.info("Start Creation Menu: Play");
  541. JMenu source = (JMenu) e.getSource();
  542. source.removeAll();
  543. for (JComponent menu : createPlayMenus())
  544. source.add(menu);
  545. GraphicsUtilities.updateComponents(source);
  546. });
  547. view.addItemListener(e ->
  548. {
  549. Logger.LOGGER.info("Start Creation Menu: View");
  550. JMenu source = (JMenu) e.getSource();
  551. source.removeAll();
  552. for (JComponent menu : createViewMenus())
  553. source.add(menu);
  554. GraphicsUtilities.updateComponents(source);
  555. });
  556. options.addItemListener(e ->
  557. {
  558. Logger.LOGGER.info("Start Creation Menu: Options");
  559. JMenu source = (JMenu) e.getSource();
  560. source.removeAll();
  561. for (JComponent menu : createOptionsMenus())
  562. source.add(menu);
  563. GraphicsUtilities.updateComponents(source);
  564. });
  565. help.addItemListener(e ->
  566. {
  567. Logger.LOGGER.info("Start Creation Menu: Help");
  568. JMenu source = (JMenu) e.getSource();
  569. source.removeAll();
  570. for (JComponent menu : createHelpMenus())
  571. source.add(menu);
  572. GraphicsUtilities.updateComponents(source);
  573. });
  574. menuBar.add(file);
  575. menuBar.add(play);
  576. menuBar.add(view);
  577. menuBar.add(options);
  578. menuBar.add(help);
  579. menuBar.setBorder(BorderFactory.createEmptyBorder(9, 9, 9, 50));
  580. topBar.add(menuBar, BorderLayout.EAST);
  581. getContentPane().add(topBar, BorderLayout.NORTH);
  582. }
  583. {
  584. midiRendererPanel = new MIDIRendererPanel();
  585. midiRendererPanel.addMouseListener(new MouseAdapter()
  586. {
  587. @Override
  588. public void mouseClicked(MouseEvent e)
  589. {
  590. if (e.getButton() == 3)
  591. {
  592. ArrayList<JComponent> alls = new ArrayList<>();
  593. {
  594. {
  595. JMenu file0 = new JMenu(SystemLanguage.translate("application.window.home.menubar.menu.file.text"));
  596. file0.setMnemonic('F');
  597. ArrayList<JComponent> fileMenus = createFileMenus();
  598. for (JComponent fileMenu : fileMenus) file0.add(fileMenu);
  599. alls.add(file0);
  600. }
  601. {
  602. JMenu view0 = new JMenu(SystemLanguage.translate("application.window.home.menubar.menu.view.text"));
  603. view0.setMnemonic('V');
  604. ArrayList<JComponent> fileMenus = createViewMenus();
  605. for (JComponent fileMenu : fileMenus) view0.add(fileMenu);
  606. alls.add(view0);
  607. }
  608. {
  609. alls.addAll(createOptionsMenus());
  610. }
  611. }
  612. alls.add(new JPopupMenu.Separator());
  613. alls.addAll(createPlayMenus());
  614. JPopupMenu popupMenu = new JPopupMenu();
  615. for (JComponent playMenu : alls)
  616. popupMenu.add(playMenu);
  617. popupMenu.show(midiRendererPanel, e.getX() + 1, e.getY() + 1);
  618. }
  619. }
  620. });
  621. JPanel panel = new JPanel();
  622. panel.setLayout(new BorderLayout());
  623. midiRendererPanel.setTransferHandler(new TransferHandler()
  624. {
  625. @Override
  626. public boolean canImport(TransferSupport support)
  627. {
  628. return true;
  629. }
  630. @Override
  631. public boolean importData(TransferSupport support)
  632. {
  633. LinkedHashSet<File> files = new LinkedHashSet<>();
  634. Transferable transferable = support.getTransferable();
  635. if (transferable != null && support.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
  636. {
  637. DataFlavor[] dataFlavors = support.getDataFlavors();
  638. if (dataFlavors != null && dataFlavors.length > 0)
  639. {
  640. for (DataFlavor dataFlavor : dataFlavors)
  641. {
  642. try
  643. {
  644. if (dataFlavor == null) continue;
  645. Object transferData = transferable.getTransferData(dataFlavor);
  646. if (transferData instanceof List<?> list)
  647. {
  648. for (Object o : list)
  649. {
  650. if (o instanceof File file)
  651. {
  652. String name = file.getName().toLowerCase();
  653. if (name.endsWith(".mid") || name.endsWith(".midi"))
  654. files.add(file);
  655. }
  656. }
  657. }
  658. }
  659. catch (Throwable ignored)
  660. {
  661. }
  662. }
  663. }
  664. }
  665. if (files.size() != 1) return false;
  666. for (File file : files)
  667. {
  668. ThreadUtilities.asynchronous(that ->
  669. {
  670. Logger.LOGGER.info("Selected MIDI File: " + file.getAbsolutePath());
  671. loadSong(file, getMIDIReceiver());
  672. });
  673. break;
  674. }
  675. return true;
  676. }
  677. });
  678. panel.add(midiRendererPanel, BorderLayout.CENTER);
  679. cardPanel.add("Renderer", panel);
  680. }
  681. getContentPane().add(cardPanel, BorderLayout.CENTER);
  682. }
  683. /**
  684. * 创建菜单
  685. *
  686. * @param text 文本
  687. * @return 返回菜单对象
  688. * @author xfherun 何润
  689. */
  690. protected JMenu createMenu(String text)
  691. {
  692. return new JMenu(text)
  693. {
  694. @Override
  695. public void updateUI()
  696. {
  697. setUI(new MIDIForgeMenuUI()
  698. {
  699. @Override
  700. public void installUI(JComponent c)
  701. {
  702. super.installUI(c);
  703. c.setOpaque(true);
  704. c.setBackground(new Color(0, 0, 0, 255));
  705. c.setForeground(new Color(204, 204, 204, 255));
  706. selectionBackground = new Color(0, 0, 0, 255);
  707. selectionForeground = new Color(255, 255, 255, 255);
  708. int margin = 4;
  709. int p = 2;
  710. c.setBorder(BorderFactory.createEmptyBorder(margin, margin * p, margin, margin * p));
  711. }
  712. });
  713. }
  714. };
  715. }
  716. /**
  717. * 关闭歌曲
  718. *
  719. * @author xfherun 何润
  720. */
  721. public void closeSong()
  722. {
  723. DefaultMidiRenderer renderer = midiRendererPanel.getRenderer();
  724. if (renderer != null)
  725. renderer.close();
  726. midiRendererPanel.setRenderer(null);
  727. midiRendererPanel.getDraggedProgressBar().setPercentage(0.0);
  728. midiRendererPanel.getDraggedProgressBar().setDraggable(false);
  729. setTitle(SystemLanguage.translate("application.window.title"));
  730. GraphicsUtilities.updateComponents(this);
  731. }
  732. /**
  733. * 加载歌曲
  734. *
  735. * @param file 文件
  736. * @param receiver MIDI接收器
  737. * @author xfherun 何润
  738. */
  739. public void loadSong(File file, Receiver receiver)
  740. {
  741. closeSong();
  742. MidiSequence sequence;
  743. LoadAnimation.LoadAnimationDialog loadAnimationDialog = new LoadAnimation.LoadAnimationDialog(MainWindow.this);
  744. try
  745. {
  746. sequence = MidiSequence.loadMidiSequence(currentMIDIFile = file, null);
  747. }
  748. catch (Throwable e)
  749. {
  750. try
  751. {
  752. loadAnimationDialog.setVisible(false);
  753. loadAnimationDialog.dispose();
  754. loadAnimationDialog = null;
  755. }
  756. catch (Throwable ex)
  757. {
  758. e.addSuppressed(ex);
  759. }
  760. Logger.LOGGER.error("Loading MIDI sequence error!", e);
  761. return;
  762. }
  763. midiRendererPanel.setRenderer(new DefaultMidiRenderer());
  764. DefaultMidiRenderer renderer = midiRendererPanel.getRenderer();
  765. renderer.open(sequence, receiver);
  766. try
  767. {
  768. loadAnimationDialog.setVisible(false);
  769. loadAnimationDialog.dispose();
  770. loadAnimationDialog = null;
  771. }
  772. catch (Throwable e)
  773. {
  774. Logger.LOGGER.warn("Closing the loading animation window failed!", e);
  775. }
  776. midiRendererPanel.getDraggedProgressBar().setPercentage(0.0);
  777. midiRendererPanel.getDraggedProgressBar().setDraggable(true);
  778. midiRendererPanel.updateMetronome();
  779. midiRendererPanel.updateVolume();
  780. setTitle("*" + SystemLanguage.translate("application.window.title") + " - " + currentMIDIFile.getAbsolutePath());
  781. GraphicsUtilities.updateComponents(this);
  782. }
  783. /**
  784. * 获取 midiRendererPanel 的值
  785. *
  786. * @return midiRendererPanel 的值
  787. * @author xfherun 何润
  788. */
  789. public MIDIRendererPanel getMidiRendererPanel()
  790. {
  791. return midiRendererPanel;
  792. }
  793. }
返回顶部
  • 提示