GUI.java
1    import javax.imageio.ImageIO;
2    import javax.swing.*;
3    import java.awt.*;
4    import java.awt.event.*;
5    import java.io.File;
6    
7    public class GUI{
8    
9        private ImageIcon whole, half, quarter, eighth, sixteenth, thirtysecond;
10       private Melody melody, calcMelody;
11       private MusicPlayer musicPlayer;
12       private JFrame frame, rhythmInput, chordsInput, oneChordInput;
13       private JPanel frameBorderPanel, userInputPanel, extraInputPanel, keyChoicePanel, rhythmDisplayPanel, rhythmFramePanel, chordsDisplayPanel, chordsFramePanel, oneChordPanel, oneChordContentPanel, keyNotesCheckBoxPanel, extraNotesCheckBoxPanel, lengthAndMelodyPanel, lengthParametersLabelsPanel, lengthParametersComboBoxesPanel;
14       private RhythmPanel rhythmInputPanel, rhythmDisplayRhythmPanel;
15       private ChordsPanel chordsInputPanel, chordsDisplayChordsPanel;
16       private MelodyPanel melodyDisplayMelodyPanel;
17       private JComboBox tonicCB, scaleCB, timeSigCB, numberMeasuresCB, smallestSubdivCB, chordRootNoteCB, arpeggiateCB;
18       private MutableComboBoxModel subdivModel, chordRootNoteModel;
19       private ComboBoxColorRenderer comboBoxColorRenderer;
20       private JButton enterRhythmB, saveRhythmB, deleteRhythm, enterChordsB, saveChordsB, saveOneChordB, deleteChordsB, createMelodyB, playMelodyB;
21       private JLabel keyL, melodyL, timeSigL, numberMeasuresL, smallestSubdivL, rootNoteL, keyNotesL, extraNotesL;
22       private JCheckBox keyNoteCheckBox2, keyNoteCheckBox3, keyNoteCheckBox4, keyNoteCheckBox5, keyNoteCheckBox6, keyNoteCheckBox7, keyNoteCheckBox8, extraNoteCheckBox1, extraNoteCheckBox2, extraNoteCheckBox3, extraNoteCheckBox4, extraNoteCheckBox5;
23       private JCheckBox[] keyNotesCheckBoxesArray, extraNotesCheckBoxesArray;
24       private boolean rhythmEntered, chordsEntered, editChord, deleteChord;
25       private boolean[] rhythm, bufferRhythm;
26       private Chord[] chords, bufferChords;
27       private Chord bufferOneChord;
28       private int length, chordBeginningIndex, chordEndingIndex;
29       
30       public GUI(){
31   
32   
33           // Initialising
34   
35           try{
36               whole = new ImageIcon(ImageIO.read(new File("res/edits/whole_transparent.png")).getScaledInstance(16, 32, Image.SCALE_SMOOTH));
37               half = new ImageIcon(ImageIO.read(new File("res/edits/half_transparent.png")).getScaledInstance(16, 32, Image.SCALE_SMOOTH));
38               quarter = new ImageIcon(ImageIO.read(new File("res/edits/quarter_transparent.png")).getScaledInstance(16, 32, Image.SCALE_SMOOTH));
39               eighth = new ImageIcon(ImageIO.read(new File("res/edits/eighth_transparent.png")).getScaledInstance(16, 32, Image.SCALE_SMOOTH));
40               sixteenth = new ImageIcon(ImageIO.read(new File("res/edits/sixteenth_transparent.png")).getScaledInstance(16, 32, Image.SCALE_SMOOTH));
41               thirtysecond = new ImageIcon(ImageIO.read(new File("res/edits/thirtysecond_transparent.png")).getScaledInstance(16, 32, Image.SCALE_SMOOTH));
42           } catch(Exception e){
43               System.out.println("Oooops, something went wrong!");
44           }
45   
46           musicPlayer = new MusicPlayer();
47           frame = new JFrame("MelodyMaker");
48           rhythmInput = new JFrame("Enter your rhythm");
49           chordsInput = new JFrame("Enter your chords");
50           oneChordInput = new JFrame("Build your chord");
51           frameBorderPanel = new JPanel();
52           frameBorderPanel.setLayout(new BorderLayout());
53           rhythmInputPanel = new RhythmPanel();
54           rhythmDisplayRhythmPanel = new RhythmPanel(); // (TODO: use only this panel for rhythmInput and get rid of rhythmInputFrame & bufferRhythm)
55           rhythmDisplayRhythmPanel.setErase(true);
56           userInputPanel = new JPanel();
57           userInputPanel.setLayout(new GridLayout(1,2));
58           extraInputPanel = new JPanel();
59           extraInputPanel.setLayout(new GridLayout(7,1));
60           keyChoicePanel = new JPanel();
61           keyChoicePanel.setLayout(new GridLayout(1,2));
62           rhythmDisplayPanel = new JPanel();
63           rhythmDisplayPanel.setLayout(new BorderLayout());
64           rhythmFramePanel = new JPanel();
65           rhythmFramePanel.setPreferredSize(new Dimension(Main.OTHER_FRAME_WIDTH, Main.OTHER_FRAME_HEIGHT));
66           rhythmFramePanel.setLayout(new BorderLayout());
67           chordsDisplayPanel = new JPanel();
68           chordsDisplayPanel.setLayout(new BorderLayout());
69           chordsFramePanel = new JPanel();
70           chordsFramePanel.setPreferredSize(new Dimension(Main.OTHER_FRAME_WIDTH, Main.OTHER_FRAME_HEIGHT));
71           chordsFramePanel.setLayout(new BorderLayout());
72           oneChordPanel = new JPanel();
73           oneChordPanel.setPreferredSize(new Dimension(Main.CHORD_FRAME_WIDTH, Main.CHORD_FRAME_HEIGHT));
74           oneChordPanel.setLayout(new BorderLayout());
75           oneChordContentPanel = new JPanel();
76           oneChordContentPanel.setLayout(new GridLayout(2,3));
77           keyNotesCheckBoxPanel = new JPanel();
78           keyNotesCheckBoxPanel.setLayout(new GridLayout(7,1));
79           extraNotesCheckBoxPanel = new JPanel();
80           extraNotesCheckBoxPanel.setLayout(new GridLayout(5,1));
81           lengthAndMelodyPanel = new JPanel();
82           lengthAndMelodyPanel.setLayout(new GridLayout(7,1));
83           lengthParametersLabelsPanel = new JPanel();
84           lengthParametersLabelsPanel.setLayout(new GridLayout(1,3));
85           lengthParametersComboBoxesPanel = new JPanel();
86           lengthParametersComboBoxesPanel.setLayout(new GridLayout(1,3));
87           melodyDisplayMelodyPanel = new MelodyPanel();
88           tonicCB = new JComboBox(new String[]{"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"});
89           tonicCB.setSelectedIndex(0);
90           tonicCB.setMaximumRowCount(12);
91           scaleCB = new JComboBox(new String[]{"Ionian (Major)", "Dorian", "Phrygian", "Lydian", "Mixolydian", "Aeolian (Minor)", "Locrian", "Harmonic Minor", "Melodic Minor"});
92           scaleCB.setMaximumRowCount(9);
93           scaleCB.setSelectedIndex(0);
94           timeSigCB = new JComboBox(new String[]{"4/4", "3/4", "6/4", "2/4", "5/4", "7/4", "7/8", "15/16"});
95           timeSigCB.setSelectedIndex(0);
96           numberMeasuresCB = new JComboBox(new String[]{"1", "2", "3", "4"});
97           numberMeasuresCB.setSelectedIndex(0);
98           subdivModel = new DefaultComboBoxModel();
99           subdivModel.addElement(whole);
100          subdivModel.addElement(half);
101          subdivModel.addElement(quarter);
102          subdivModel.addElement(eighth);
103          subdivModel.addElement(sixteenth);
104          subdivModel.addElement(thirtysecond);
105          smallestSubdivCB = new JComboBox(subdivModel);
106          smallestSubdivCB.setSelectedIndex(4);
107          arpeggiateCB = new JComboBox(new String[]{"No minor 2nd intervals", "Arpeggiate"});
108          enterRhythmB = new JButton("Enter rhythm");
109          saveRhythmB = new JButton("Save rhythm");
110          deleteRhythm = new JButton("Delete rhythm");
111          deleteRhythm.setVisible(false);
112          enterChordsB = new JButton("Enter chords"); // TODO: Add chord only creation function
113          saveChordsB = new JButton("Save chords");
114          saveOneChordB = new JButton("Save chord");
115          deleteChordsB = new JButton("Delete chords");
116          deleteChordsB.setVisible(false);
117          createMelodyB = new JButton("Create melody");
118          playMelodyB = new JButton("Play melody");
119          keyL = new JLabel("Key: ");
120          melodyL = new JLabel("Melody: ");
121          timeSigL = new JLabel("Time Signature: ");
122          numberMeasuresL = new JLabel("Number of measures: ");
123          smallestSubdivL = new JLabel("Smallest Subdivision: ");
124          rootNoteL = new JLabel("Root note");
125          keyNotesL = new JLabel("Key notes");
126          extraNotesL = new JLabel("Extra notes");
127          keyNoteCheckBox2 = new JCheckBox("2");
128          keyNoteCheckBox3 = new JCheckBox("3");
129          keyNoteCheckBox4 = new JCheckBox("4");
130          keyNoteCheckBox5 = new JCheckBox("5");
131          keyNoteCheckBox6 = new JCheckBox("6");
132          keyNoteCheckBox7 = new JCheckBox("7");
133          keyNoteCheckBox8 = new JCheckBox("8");
134          keyNoteCheckBox8.setVisible(false);
135          extraNoteCheckBox1 = new JCheckBox("1");
136          extraNoteCheckBox2 = new JCheckBox("2");
137          extraNoteCheckBox3 = new JCheckBox("3");
138          extraNoteCheckBox4 = new JCheckBox("4");
139          extraNoteCheckBox5 = new JCheckBox("5");
140          keyNotesCheckBoxesArray = new JCheckBox[7];
141          keyNotesCheckBoxesArray[0] = keyNoteCheckBox2;
142          keyNotesCheckBoxesArray[1] = keyNoteCheckBox3;
143          keyNotesCheckBoxesArray[2] = keyNoteCheckBox4;
144          keyNotesCheckBoxesArray[3] = keyNoteCheckBox5;
145          keyNotesCheckBoxesArray[4] = keyNoteCheckBox6;
146          keyNotesCheckBoxesArray[5] = keyNoteCheckBox7;
147          keyNotesCheckBoxesArray[6] = keyNoteCheckBox8;
148          extraNotesCheckBoxesArray = new JCheckBox[5];
149          extraNotesCheckBoxesArray[0] = extraNoteCheckBox1;
150          extraNotesCheckBoxesArray[1] = extraNoteCheckBox2;
151          extraNotesCheckBoxesArray[2] = extraNoteCheckBox3;
152          extraNotesCheckBoxesArray[3] = extraNoteCheckBox4;
153          extraNotesCheckBoxesArray[4] = extraNoteCheckBox5;
154          setRhythmEntered(false);
155          setChordsEntered(false);
156  
157          setLength((String)timeSigCB.getSelectedItem(), numberMeasuresCB.getSelectedIndex()+1, 16);
158          setCalcMelody(new Melody(getLength()));
159          setRhythm(new boolean[getLength()]);
160          setChords(new Chord[getLength()]);
161  
162          chordRootNoteModel = new DefaultComboBoxModel();
163          addChordRootNoteModelElements();
164          chordRootNoteCB = new JComboBox(chordRootNoteModel);
165          comboBoxColorRenderer = new ComboBoxColorRenderer(chordRootNoteCB.getRenderer(), getCalcMelody());
166          chordRootNoteCB.setRenderer(comboBoxColorRenderer);
167          chordRootNoteCB.setMaximumRowCount(12);
168          updateCheckBoxes();
169          
170          chordsInputPanel = new ChordsPanel(getCalcMelody());
171          chordsDisplayChordsPanel = new ChordsPanel(getCalcMelody()); // (TODO: use only this panel for chordsInput and get rid of chordsInputFrame & bufferChords)
172          chordsDisplayChordsPanel.setErase(true);
173  
174          // GUI structuring
175  
176          frame.add(frameBorderPanel);
177          try{
178              frame.setIconImage(ImageIO.read(new File("res/edits/quarter_transparent.png")).getScaledInstance(16, 32, Image.SCALE_SMOOTH)); // Image -> Quarter
179              rhythmInput.setIconImage(ImageIO.read(new File("res/edits/quarter_transparent.png")).getScaledInstance(16, 32, Image.SCALE_SMOOTH)); // Image -> Quarter
180              chordsInput.setIconImage(ImageIO.read(new File("res/edits/quarter_transparent.png")).getScaledInstance(16, 32, Image.SCALE_SMOOTH)); // Image -> Quarter
181              oneChordInput.setIconImage(ImageIO.read(new File("res/edits/quarter_transparent.png")).getScaledInstance(16, 32, Image.SCALE_SMOOTH)); // Image -> Quarter
182          } catch (Exception e){
183              System.out.println("Oooops, something went wrong!");
184          }
185          frame.setSize(Main.MAIN_FRAME_WIDTH, Main.MAIN_FRAME_HEIGHT);
186          frame.setResizable(false);
187          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
188  
189          frameBorderPanel.add(userInputPanel, BorderLayout.CENTER);
190  
191          userInputPanel.add(extraInputPanel);
192          userInputPanel.add(lengthAndMelodyPanel);
193  
194          extraInputPanel.add(keyL);
195          extraInputPanel.add(keyChoicePanel);
196          extraInputPanel.add(enterRhythmB);
197          extraInputPanel.add(rhythmDisplayPanel);
198          extraInputPanel.add(enterChordsB);
199          extraInputPanel.add(chordsDisplayPanel);
200          extraInputPanel.add(createMelodyB);
201  
202          keyChoicePanel.add(tonicCB);
203          keyChoicePanel.add(scaleCB);
204  
205          rhythmInput.add(rhythmFramePanel);
206          rhythmInput.pack();
207          rhythmInput.setResizable(false);
208          rhythmInput.setLocationRelativeTo(frame);
209          rhythmInput.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
210          rhythmInput.setVisible(false);
211  
212          rhythmFramePanel.add(rhythmInputPanel, BorderLayout.CENTER);
213          rhythmFramePanel.add(saveRhythmB, BorderLayout.SOUTH); // TODO: add FlowLayout.RIGHT
214  
215          chordsInput.add(chordsFramePanel);
216          chordsInput.pack();
217          chordsInput.setResizable(false);
218          chordsInput.setLocationRelativeTo(frame);
219          chordsInput.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
220          chordsInput.setVisible(false);
221  
222          chordsFramePanel.add(chordsInputPanel, BorderLayout.CENTER);
223          chordsFramePanel.add(saveChordsB, BorderLayout.SOUTH); // TODO: add FlowLayout.RIGHT
224  
225          oneChordInput.add(oneChordPanel);
226          oneChordInput.pack();
227          oneChordInput.setResizable(false);
228          oneChordInput.setLocationRelativeTo(chordsInput);
229          oneChordInput.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
230          oneChordInput.setVisible(false);
231  
232          oneChordPanel.add(oneChordContentPanel, BorderLayout.CENTER);
233          oneChordPanel.add(arpeggiateCB, BorderLayout.EAST); // TODO: make this look nicer
234          oneChordPanel.add(saveOneChordB, BorderLayout.SOUTH); // TODO: add FlowLayout.RIGHT
235  
236          oneChordContentPanel.add(rootNoteL);
237          oneChordContentPanel.add(keyNotesL);
238          oneChordContentPanel.add(extraNotesL);
239          oneChordContentPanel.add(chordRootNoteCB);
240          oneChordContentPanel.add(keyNotesCheckBoxPanel);
241          oneChordContentPanel.add(extraNotesCheckBoxPanel);
242  
243          keyNotesCheckBoxPanel.add(keyNoteCheckBox2);
244          keyNotesCheckBoxPanel.add(keyNoteCheckBox3);
245          keyNotesCheckBoxPanel.add(keyNoteCheckBox4);
246          keyNotesCheckBoxPanel.add(keyNoteCheckBox5);
247          keyNotesCheckBoxPanel.add(keyNoteCheckBox6);
248          keyNotesCheckBoxPanel.add(keyNoteCheckBox7);
249          keyNotesCheckBoxPanel.add(keyNoteCheckBox8);
250  
251          extraNotesCheckBoxPanel.add(extraNoteCheckBox1);
252          extraNotesCheckBoxPanel.add(extraNoteCheckBox2);
253          extraNotesCheckBoxPanel.add(extraNoteCheckBox3);
254          extraNotesCheckBoxPanel.add(extraNoteCheckBox4);
255          extraNotesCheckBoxPanel.add(extraNoteCheckBox5);
256  
257          rhythmDisplayPanel.add(rhythmDisplayRhythmPanel, BorderLayout.CENTER);
258          rhythmDisplayPanel.add(deleteRhythm, BorderLayout.SOUTH); // TODO: add FlowLayout.RIGHT
259  
260          chordsDisplayPanel.add(chordsDisplayChordsPanel, BorderLayout.CENTER);
261          chordsDisplayPanel.add(deleteChordsB, BorderLayout.SOUTH); // TODO: add FlowLayout.RIGHT
262  
263          lengthAndMelodyPanel.add(lengthParametersLabelsPanel);
264          lengthAndMelodyPanel.add(lengthParametersComboBoxesPanel);
265          lengthAndMelodyPanel.add(new JPanel());
266          lengthAndMelodyPanel.add(new JPanel());
267          lengthAndMelodyPanel.add(melodyL);
268          lengthAndMelodyPanel.add(melodyDisplayMelodyPanel);
269          lengthAndMelodyPanel.add(playMelodyB);
270  
271          lengthParametersLabelsPanel.add(timeSigL);
272          lengthParametersLabelsPanel.add(numberMeasuresL);
273          lengthParametersLabelsPanel.add(smallestSubdivL);
274  
275          lengthParametersComboBoxesPanel.add(timeSigCB);
276          lengthParametersComboBoxesPanel.add(numberMeasuresCB);
277          lengthParametersComboBoxesPanel.add(smallestSubdivCB);
278  
279          frame.setVisible(true);
280  
281  
282          // ActionListeners
283  
284          enterRhythmB.addActionListener(new ActionListener(){
285              @Override
286              public void actionPerformed(ActionEvent e){
287                  rhythmInput.setVisible(true);
288              }
289          });
290  
291          rhythmInput.addComponentListener(new ComponentAdapter(){
292              @Override
293              public void componentShown(ComponentEvent e){
294                  super.componentShown(e);
295                  // setBufferRhythm(getRhythm());
296                  setBufferRhythm(new boolean[getLength()]); // TODO: use this approach for every setter
297                  for(int i = 0; i < getLength(); i++){
298                      getBufferRhythm()[i] = getRhythm()[i];
299                  }
300              }
301  
302              @Override
303              public void componentHidden(ComponentEvent e){
304                  super.componentHidden(e);
305                  rhythmInputPanel.setRhythm(getRhythm());
306              }
307          });
308  
309          rhythmInputPanel.addMouseListener(new MouseListener(){
310              @Override
311              public void mouseClicked(MouseEvent e){
312                  int clear = (Main.OTHER_FRAME_WIDTH/4)/(getLength()+1); // width of the space in between rectangles
313                  int rect = (Main.OTHER_FRAME_WIDTH*3/4)/getLength(); // width of each rectangle
314                  for(int i = 1; i <= getLength(); i++){
315                      if(clear*i+rect*(i-1) <= e.getX() & e.getX() <= clear*i+rect*(i-1)+rect && Main.OTHER_FRAME_HEIGHT/3 <= e.getY() && e.getY() <= Main.OTHER_FRAME_HEIGHT*2/3){
316                          getBufferRhythm()[i-1] = !getBufferRhythm()[i-1];
317                          break;
318                      }
319                  }
320                  rhythmInputPanel.setRhythm(getBufferRhythm());
321                  rhythmInputPanel.repaint();
322              }
323  
324              @Override
325              public void mousePressed(MouseEvent e){
326  
327              }
328  
329              @Override
330              public void mouseReleased(MouseEvent e){
331  
332              }
333  
334              @Override
335              public void mouseEntered(MouseEvent e){
336  
337              }
338  
339              @Override
340              public void mouseExited(MouseEvent e){
341  
342              }
343          });
344  
345          saveRhythmB.addActionListener(new ActionListener(){
346              @Override
347              public void actionPerformed(ActionEvent e){
348                  setRhythm(getBufferRhythm());
349                  rhythmDisplayRhythmPanel.setRhythm(getRhythm());
350                  rhythmInput.setVisible(false);
351                  setRhythmEntered(false);
352                  for(boolean beat : getRhythm()){
353                      if(beat){
354                          setRhythmEntered(true);
355                          deleteRhythm.setVisible(true);
356                          enterRhythmB.setText("Edit rhythm");
357                          rhythmDisplayRhythmPanel.setErase(false);
358                          break;
359                      }
360                  }
361                  if(!getRhythmEntered()){
362                      deleteRhythm.setVisible(false);
363                      enterRhythmB.setText("Enter rhythm");
364                      rhythmDisplayRhythmPanel.setErase(true);
365                  }
366                  rhythmDisplayRhythmPanel.repaint();
367              }
368          });
369  
370          deleteRhythm.addActionListener(new ActionListener(){
371              @Override
372              public void actionPerformed(ActionEvent e){
373                  setRhythm(new boolean[getLength()]);
374                  setBufferRhythm(new boolean[getLength()]);
375                  rhythmInputPanel.setRhythm(getRhythm());
376                  rhythmInputPanel.repaint();
377                  rhythmDisplayRhythmPanel.setRhythm(getRhythm());
378                  rhythmDisplayRhythmPanel.setErase(true);
379                  rhythmDisplayRhythmPanel.repaint();
380                  setRhythmEntered(false);
381                  deleteRhythm.setVisible(false);
382                  enterRhythmB.setText("Enter rhythm");
383              }
384          });
385  
386          enterChordsB.addActionListener(new ActionListener(){
387              @Override
388              public void actionPerformed(ActionEvent e){
389                  chordsInput.setVisible(true);
390              }
391          });
392  
393          chordsInput.addComponentListener(new ComponentAdapter() {
394              @Override
395              public void componentShown(ComponentEvent e) {
396                  super.componentShown(e);
397                  setBufferChords(new Chord[getLength()]);
398                  // set BufferChords to actual Chords for editing of actual Chords
399                  for(int i = 0; i < getLength(); i++){
400                      getBufferChords()[i] = getChords()[i];
401                  }
402              }
403  
404              @Override
405              public void componentHidden(ComponentEvent e) {
406                  super.componentHidden(e);
407                  chordsInputPanel.setChords(getChords());
408                  oneChordInput.setVisible(false);
409              }
410          });
411  
412          chordsInputPanel.addMouseListener(new MouseListener(){
413              @Override
414              public void mouseClicked(MouseEvent e){
415  
416              }
417  
418              @Override
419              public void mousePressed(MouseEvent e){
420                  if(e.getButton() == MouseEvent.BUTTON1){
421                      setEditChord(false);
422                      setDeleteChord(false);
423                  } else if(e.getButton() == MouseEvent.BUTTON2){
424                      setDeleteChord(true);
425                      setEditChord(false);
426                  } else if(e.getButton() == MouseEvent.BUTTON3){
427                      setEditChord(true);
428                      setDeleteChord(false);
429                  }
430                  setChordBeginningIndex(-1);
431                  setChordEndingIndex(-1);
432                  int clear = (Main.OTHER_FRAME_WIDTH/4)/(getLength()+1); // width of the space in between rectangles
433                  int rect = (Main.OTHER_FRAME_WIDTH*3/4)/getLength(); // width of each rectangle
434                  for(int i = 1; i <= getLength(); i++){
435                      if(clear*i+rect*(i-1) <= e.getX() & e.getX() <= clear*i+rect*(i-1)+rect && Main.OTHER_FRAME_HEIGHT/3 <= e.getY() && e.getY() <= Main.OTHER_FRAME_HEIGHT*2/3){
436                          setChordBeginningIndex(i-1);
437                          break;
438                      }
439                  }
440              }
441  
442              @Override
443              public void mouseReleased(MouseEvent e){
444                  int clear = (Main.OTHER_FRAME_WIDTH/4)/(getLength()+1); // width of the space in between rectangles
445                  int rect = (Main.OTHER_FRAME_WIDTH*3/4)/getLength(); // width of each rectangle
446                  for(int i = 1; i <= getLength(); i++){
447                      if(clear*i+rect*(i-1) <= e.getX() & e.getX() <= clear*i+rect*(i-1)+rect && Main.OTHER_FRAME_HEIGHT/3 <= e.getY() && e.getY() <= Main.OTHER_FRAME_HEIGHT*2/3){
448                          setChordEndingIndex(i-1);
449                          break;
450                      }
451                  }
452  
453                  if(getChordBeginningIndex() != -1 && getChordEndingIndex() != -1){ // only try to make new chord / edit chord if user selected proper interval of beats
454                      if(getDeleteChord()){
455                          setBufferOneChord(null);
456                          for(ActionListener a : saveOneChordB.getActionListeners()){ // invoke ActionListener of saveOneChordB so that it saves the fact that chords have been deleted
457                              a.actionPerformed(new ActionEvent(saveOneChordB, ActionEvent.ACTION_PERFORMED, null));
458                          }
459                      } else {
460                          if(getBufferChords()[getChordBeginningIndex()] == null){ // if no chord is entered as of now, the user can't edit a chord -> this is also done if getEditChord() is false because one will always have to check at least one if-statement (more inefficient way would be this: 1. if-statement -> if(getEditChord()); 2. if-statement -> the current one)
461                              setEditChord(false);
462                          }
463                          oneChordInput.setVisible(true); // the chord editing window is only supposed to be shown when the user either wants to edit or create a chord
464                      }
465                  }
466              }
467  
468              @Override
469              public void mouseEntered(MouseEvent e){
470  
471              }
472  
473              @Override
474              public void mouseExited(MouseEvent e){
475  
476              }
477          });
478  
479          oneChordInput.addComponentListener(new ComponentAdapter(){
480              @Override
481              public void componentShown(ComponentEvent e){
482                  super.componentShown(e);
483                  if(getEditChord()){
484                      setBufferOneChord(copyOnlyChordInformationAndNotReference(getBufferChords()[getChordBeginningIndex()]));
485                      updateCheckBoxSelectionStatus(getBufferOneChord());
486                      updateArpeggiateCBSelectedIndex();
487                      chordRootNoteCB.setSelectedIndex(findChordRootNoteCBNoteIndex(getBufferOneChord().getRootNote()));
488                  } else {
489                      setBufferOneChord(new Chord((String)chordRootNoteCB.getItemAt(0), true));
490                      updateCheckBoxSelectionStatus(getBufferOneChord());
491                      chordRootNoteCB.setSelectedIndex(0);
492                      arpeggiateCB.setSelectedIndex(0);
493                  }
494              }
495  
496              @Override
497              public void componentHidden(ComponentEvent e){
498                  super.componentHidden(e);
499              }
500          });
501  
502          chordRootNoteCB.addActionListener(new ActionListener(){
503              @Override
504              public void actionPerformed(ActionEvent e){
505                  updateCheckBoxes();
506                  if(getBufferOneChord() != null){ // if the bufferChord is null, the user doesn't want to enter a chord (every time the enterOneChord frame is opened a new bufferChord is created), which means that the bufferChord's notes don't have to be updated
507                      getBufferOneChord().setRootNote((String)chordRootNoteCB.getSelectedItem(), getCalcMelody().findKeyNoteIndex(Melody.extractActualNoteName((String)chordRootNoteCB.getSelectedItem())) != -1);
508                      invokeCheckBoxActionListeners();
509                  }
510              }
511          });
512  
513          // keyNotesCheckBoxes ActionListeners
514          for(int i = 0; i < keyNotesCheckBoxesArray.length; i++){
515              int finalI = i; // i has to be "effectively final" (god knows why)
516              keyNotesCheckBoxesArray[i].addActionListener(new ActionListener(){
517                  @Override
518                  public void actionPerformed(ActionEvent e){
519                      if(getCalcMelody().findKeyNoteIndex(Melody.extractActualNoteName((String)chordRootNoteCB.getSelectedItem())) != -1){ // rootNote == keyNote
520                          if(finalI != 6){ // the rootNote (which is at the last index (of 6) in the keyNotesCheckBoxesArray) belongs to the first index of the keyChordNoteArray -> the index of everything else is shifted by one
521                              if(keyNotesCheckBoxesArray[finalI].isSelected()){
522                                  getBufferOneChord().getKeyChordNotes()[finalI+1] = Melody.extractActualNoteName(keyNotesCheckBoxesArray[finalI].getText());
523                              } else {
524                                  getBufferOneChord().getKeyChordNotes()[finalI+1] = null;
525                              }
526                          }
527                      } else { // rootNote == extraNote -> copy keyNotesArray the way it is
528                          if(keyNotesCheckBoxesArray[finalI].isSelected()){
529                              getBufferOneChord().getKeyChordNotes()[finalI] = Melody.extractActualNoteName(keyNotesCheckBoxesArray[finalI].getText());
530                          } else {
531                              getBufferOneChord().getKeyChordNotes()[finalI] = null;
532                          }
533                      }
534                  }
535              });
536          }
537  
538          // extraNotesCheckBoxes ActionListeners
539          for(int i = 0; i < extraNotesCheckBoxesArray.length; i++){
540              int finalI = i; // i has to be "effectively final" (god knows why)
541              extraNotesCheckBoxesArray[i].addActionListener(new ActionListener(){
542                  @Override
543                  public void actionPerformed(ActionEvent e){
544                      if(getCalcMelody().findKeyNoteIndex(Melody.extractActualNoteName((String)chordRootNoteCB.getSelectedItem())) != -1){ // rootNote == keyNote -> copy extraNotesArray the way it is
545                          if(extraNotesCheckBoxesArray[finalI].isSelected()){
546                              getBufferOneChord().getExtraChordNotes()[finalI] = extraNotesCheckBoxesArray[finalI].getText();
547                          } else {
548                              getBufferOneChord().getExtraChordNotes()[finalI] = null;
549                          }
550                      } else { // rootNote == extraNote
551                          if(finalI != 4){ // the rootNote (which is at the last index (of 4) in the extraNotesCheckBoxesArray) belongs to the first index of the extraChordNotesArray  -> the index of everything else is shifted by one
552                              if(extraNotesCheckBoxesArray[finalI].isSelected()){
553                                  getBufferOneChord().getExtraChordNotes()[finalI+1] = extraNotesCheckBoxesArray[finalI].getText();
554                              } else {
555                                  getBufferOneChord().getExtraChordNotes()[finalI+1] = null;
556                              }
557                          }
558                      }
559                  }
560              });
561          }
562  
563          arpeggiateCB.addActionListener(new ActionListener(){
564              @Override
565              public void actionPerformed(ActionEvent actionEvent) {
566                  getBufferOneChord().setArpeggiate(arpeggiateCB.getSelectedIndex() == 1);
567              }
568          });
569  
570          saveOneChordB.addActionListener(new ActionListener(){
571              @Override
572              public void actionPerformed(ActionEvent e){
573                  if(getBufferOneChord() != null){
574                      getBufferOneChord().setChordRootNoteCBIndex(findChordRootNoteCBNoteIndex(getBufferOneChord().getRootNote()));
575                  }
576                  if(getChordEndingIndex() < getChordBeginningIndex()){
577                      // swap values if endingIndex is greater than beginningIndex
578                      // 1: a; 2: b (1 == getChordBeginningIndex(); a == getChordBeginningIndex()'s value at the start; 2 == getChordEndingIndex(); b == getChordEndingIndex()'s value at the start)
579                      // 1 = 1 - 2
580                      setChordBeginningIndex(getChordBeginningIndex()-getChordEndingIndex()); // ==> 1: a-b; 2: b
581                      // 2 = 2 + 1
582                      setChordEndingIndex(getChordEndingIndex()+getChordBeginningIndex()); // ==> 1: a-b; 2: a
583                      // 1 = 2 - 1
584                      setChordBeginningIndex(getChordEndingIndex()-getChordBeginningIndex()); // ==> 1: b; 2: a
585                  }
586                  for(int i = getChordBeginningIndex(); i <= getChordEndingIndex(); i++){
587                      getBufferChords()[i] = getBufferOneChord();
588                  }
589                  oneChordInput.setVisible(false);
590                  chordsInputPanel.setChords(getBufferChords());
591                  chordsInputPanel.repaint();
592              }
593          });
594  
595          saveChordsB.addActionListener(new ActionListener(){
596              @Override
597              public void actionPerformed(ActionEvent e){
598                  setChords(getBufferChords());
599                  chordsDisplayChordsPanel.setChords(getChords());
600                  melodyDisplayMelodyPanel.setChords(getChords());
601                  chordsInput.setVisible(false);
602                  oneChordInput.setVisible(false);
603                  setChordsEntered(false);
604                  for(Chord chord : getChords()){
605                      if(chord != null){
606                          setChordsEntered(true);
607                          deleteChordsB.setVisible(true);
608                          enterChordsB.setText("Edit chords");
609                          chordsDisplayChordsPanel.setErase(false);
610                          break;
611                      }
612                  }
613                  if(!getChordsEntered()){
614                      deleteChordsB.setVisible(false);
615                      enterChordsB.setText("Enter chords");
616                      chordsDisplayChordsPanel.setErase(true);
617                  }
618                  chordsDisplayChordsPanel.repaint();
619              }
620          });
621  
622          deleteChordsB.addActionListener(new ActionListener(){
623              @Override
624              public void actionPerformed(ActionEvent e){
625                  setChords(new Chord[getLength()]);
626                  setBufferChords(new Chord[getLength()]);
627                  chordsInputPanel.setChords(getChords()); // TODO: find out whether it's smarter to create a new Chord[] or to reference getChords() which were just given the value of a new Chord[]
628                  chordsInputPanel.repaint();
629                  chordsDisplayChordsPanel.setChords(getChords());
630                  chordsDisplayChordsPanel.setErase(true);
631                  chordsDisplayChordsPanel.repaint();
632                  melodyDisplayMelodyPanel.setChords(getChords());
633                  setChordsEntered(false);
634                  deleteChordsB.setVisible(false);
635                  enterChordsB.setText("Enter chords");
636              }
637          });
638  
639          // TODO: improve project structure by always using an instance of the Melody class to store all the rhythmic & chords information so that the GUI class actually only deals with GUI stuff
640  
641          createMelodyB.addActionListener(new ActionListener(){
642              @Override
643              public void actionPerformed(ActionEvent e){
644                  setMelody(new Melody(getLength()));
645                  getMelody().createKeyNotes((String)tonicCB.getSelectedItem(), scaleCB.getSelectedIndex());
646                  if(getRhythmEntered()){
647                      getMelody().setRhythm(getRhythm());
648                  } else {
649                      getMelody().createRhythm();
650                  }
651                  if(getChordsEntered()){
652                      getMelody().createChordsMelody(getChords());
653                  } else {
654                      getMelody().createMelody();
655                  }
656                  melodyDisplayMelodyPanel.setMelody(getMelody());
657                  melodyDisplayMelodyPanel.setErase(false);
658                  melodyDisplayMelodyPanel.repaint();
659              }
660          });
661  
662          playMelodyB.addActionListener(new ActionListener(){
663              @Override
664              public void actionPerformed(ActionEvent e){
665                  if(getMelody() != null){
666                      for(int i = 0; i < getLength(); i++){
667                          if(getMelody().getRhythm()[i]){
668                              if(getMelody().findKeyNoteIndex(getMelody().getMelody()[i]) < getMelody().getChangeIndex()){
669                                  getMusicPlayer().playNote(getMusicPlayer().getNotes().get(getMelody().getMelody()[i]), 500);
670                              } else {
671                                  getMusicPlayer().playNote(getMusicPlayer().getNotes().get(getMelody().getMelody()[i] + "'"), 500);
672                              }
673                          } else {
674                              getMusicPlayer().playNote(getMusicPlayer().getNotes().get("click"), 500);
675                          }
676                          try{
677                              Thread.sleep(500);
678                          }
679                          catch(Exception k) {
680                              System.out.println("Whoooops...");
681                          }
682                      }
683                  }
684              }
685          });
686  
687          // TODO: update getChords() when key is changed -> transpose
688  
689          tonicCB.addActionListener(new ActionListener(){
690              @Override
691              public void actionPerformed(ActionEvent e){
692                  updateKey();
693              }
694          });
695  
696          scaleCB.addActionListener(new ActionListener(){
697              @Override
698              public void actionPerformed(ActionEvent e){
699                  updateKey();
700              }
701          });
702  
703          timeSigCB.addActionListener(new ActionListener(){ // TODO: store images in an array and use only one smart "for statement" to add the respective elements to the subdivModel
704              @Override
705              public void actionPerformed(ActionEvent e){
706                  // Delete all elements in smallestSubdivCB
707                  int size = subdivModel.getSize();
708                  for(int i = 0; i < size; i++){
709                      subdivModel.removeElementAt(0);
710                  }
711                  // Add all fitting elements to smallestSubdivCB
712                  switch(timeSigCB.getSelectedIndex()){
713                      case 0:
714                          subdivModel.addElement(whole);
715                          subdivModel.addElement(half);
716                          subdivModel.addElement(quarter);
717                          subdivModel.addElement(eighth);
718                          subdivModel.addElement(sixteenth);
719                          subdivModel.addElement(thirtysecond);
720                          smallestSubdivCB.setModel(subdivModel);
721                          smallestSubdivCB.setSelectedIndex(4);
722                          break;
723                      case 2:
724                      case 3:
725                          subdivModel.addElement(half);
726                          subdivModel.addElement(quarter);
727                          subdivModel.addElement(eighth);
728                          subdivModel.addElement(sixteenth);
729                          subdivModel.addElement(thirtysecond);
730                          smallestSubdivCB.setModel(subdivModel);
731                          smallestSubdivCB.setSelectedIndex(3);
732                          break;
733                      case 1:
734                      case 4:
735                      case 5:
736                          subdivModel.addElement(quarter);
737                          subdivModel.addElement(eighth);
738                          subdivModel.addElement(sixteenth);
739                          subdivModel.addElement(thirtysecond);
740                          smallestSubdivCB.setModel(subdivModel);
741                          smallestSubdivCB.setSelectedIndex(2);
742                          break;
743                      case 6:
744                          subdivModel.addElement(eighth);
745                          subdivModel.addElement(sixteenth);
746                          subdivModel.addElement(thirtysecond);
747                          smallestSubdivCB.setModel(subdivModel);
748                          smallestSubdivCB.setSelectedIndex(1);
749                          break;
750                      case 7:
751                          subdivModel.addElement(sixteenth);
752                          subdivModel.addElement(thirtysecond);
753                          smallestSubdivCB.setModel(subdivModel);
754                          smallestSubdivCB.setSelectedIndex(0);
755                          break;
756                      default:
757                          break;
758                  }
759                  updateLength();
760              }
761          });
762  
763          numberMeasuresCB.addActionListener(new ActionListener(){
764              @Override
765              public void actionPerformed(ActionEvent e){
766                  updateLength();
767              }
768          });
769  
770          smallestSubdivCB.addActionListener(new ActionListener(){
771              @Override
772              public void actionPerformed(ActionEvent e){
773                  updateLength();
774              }
775          });
776      }
777  
778  
779      // Getters & Setters
780  
781      private Melody getMelody() {
782          return this.melody;
783      }
784  
785      private void setMelody(Melody melody) {
786          this.melody = melody;
787      }
788  
789      public Melody getCalcMelody() {
790          return this.calcMelody;
791      }
792  
793      public void setCalcMelody(Melody calcMelody) {
794          this.calcMelody = calcMelody;
795          calcMelody.createKeyNotes((String)tonicCB.getSelectedItem(), scaleCB.getSelectedIndex()); // updateCalcMelodyNotes
796      }
797  
798      public MusicPlayer getMusicPlayer(){
799          return this.musicPlayer;
800      }
801  
802      public void setMusicPlayer(MusicPlayer musicPlayer){
803          this.musicPlayer = musicPlayer;
804      }
805  
806      private boolean getRhythmEntered() {
807          return this.rhythmEntered;
808      }
809  
810      private void setRhythmEntered(boolean rhythmEntered) {
811          this.rhythmEntered = rhythmEntered;
812      }
813  
814      private boolean getChordsEntered() {
815          return this.chordsEntered;
816      }
817  
818      private void setChordsEntered(boolean chordsEntered) {
819          this.chordsEntered = chordsEntered;
820      }
821  
822      public boolean getEditChord(){
823          return this.editChord;
824      }
825  
826      public void setEditChord(boolean editChord) {
827          this.editChord = editChord;
828      }
829  
830      public boolean getDeleteChord(){
831          return this.deleteChord;
832      }
833  
834      public void setDeleteChord(boolean deleteChord){
835          this.deleteChord = deleteChord;
836      }
837  
838      public boolean[] getRhythm() {
839          return this.rhythm;
840      }
841  
842      public void setRhythm(boolean[] rhythm) {
843          this.rhythm = rhythm;
844      }
845  
846      public boolean[] getBufferRhythm() {
847          return this.bufferRhythm;
848      }
849  
850      public void setBufferRhythm(boolean[] bufferRhythm) {
851          this.bufferRhythm = bufferRhythm;
852      }
853  
854      public Chord[] getChords() {
855          return this.chords;
856      }
857  
858      public void setChords(Chord[] chords) {
859          this.chords = chords;
860      }
861  
862      public Chord[] getBufferChords(){
863          return this.bufferChords;
864      }
865  
866      public void setBufferChords(Chord[] bufferChords){
867          this.bufferChords = bufferChords;
868      }
869  
870      public Chord getBufferOneChord(){
871          return this.bufferOneChord;
872      }
873  
874      public void setBufferOneChord(Chord bufferOneChord){
875          this.bufferOneChord = bufferOneChord;
876      }
877  
878      private int getLength() {
879          return this.length;
880      }
881  
882      private void setLength(String timeSig, int numberMeasures, int smallestSubdiv) {
883          if(timeSigCB.getSelectedIndex() != 7){
884              this.length = numberMeasures * Integer.parseInt(String.valueOf(timeSig.charAt(0))) * smallestSubdiv / Integer.parseInt(String.valueOf(timeSig.charAt(2)));
885          }
886          else {
887              this.length = numberMeasures * 15 * smallestSubdiv / 16; // fixes bug with 15/16
888          }
889      }
890  
891      public int getChordBeginningIndex(){
892          return this.chordBeginningIndex;
893      }
894  
895      public void setChordBeginningIndex(int chordBeginningIndex){
896          this.chordBeginningIndex = chordBeginningIndex;
897      }
898  
899      public int getChordEndingIndex(){
900          return this.chordEndingIndex;
901      }
902  
903      public void setChordEndingIndex(int chordEndingIndex){
904          this.chordEndingIndex = chordEndingIndex;
905      }
906  
907  
908      // Actual methods
909  
910      // (TODO: make new getChords() when length is changed (except when only numberOfMeasures is changed -> then copy the respective measures))
911  
912      private void updateLength(){
913          if(smallestSubdivCB.getSelectedItem() == whole){
914              setLength((String)timeSigCB.getSelectedItem(), numberMeasuresCB.getSelectedIndex()+1, 1);
915          } else if(smallestSubdivCB.getSelectedItem() == half){
916              setLength((String)timeSigCB.getSelectedItem(), numberMeasuresCB.getSelectedIndex()+1, 2);
917          } else if(smallestSubdivCB.getSelectedItem() == quarter){
918              setLength((String)timeSigCB.getSelectedItem(), numberMeasuresCB.getSelectedIndex()+1, 4);
919          } else if(smallestSubdivCB.getSelectedItem() == eighth){
920              setLength((String)timeSigCB.getSelectedItem(), numberMeasuresCB.getSelectedIndex()+1, 8);
921          } else if(smallestSubdivCB.getSelectedItem() == sixteenth){
922              setLength((String)timeSigCB.getSelectedItem(), numberMeasuresCB.getSelectedIndex()+1, 16);
923          } else if(smallestSubdivCB.getSelectedItem() == thirtysecond){
924              setLength((String)timeSigCB.getSelectedItem(), numberMeasuresCB.getSelectedIndex()+1, 32);
925          }
926          setCalcMelody(new Melody(getLength()));
927          setMelody(null);
928          comboBoxColorRenderer.setCalcMelody(getCalcMelody());
929          chordsInputPanel.setCalcMelody(getCalcMelody());
930          chordsDisplayChordsPanel.setCalcMelody(getCalcMelody());
931          setRhythm(new boolean[getLength()]);
932          setBufferRhythm(new boolean[getLength()]);
933          for(ActionListener a : saveRhythmB.getActionListeners()){
934              a.actionPerformed(new ActionEvent(saveRhythmB, ActionEvent.ACTION_PERFORMED, null)); // TODO: potentially reopen the windows that were opened before the length was changed for improved workflow
935          }
936          setChords(new Chord[getLength()]);
937          setBufferChords(new Chord[getLength()]);
938          for(ActionListener a : saveChordsB.getActionListeners()){
939              a.actionPerformed(new ActionEvent(saveChordsB, ActionEvent.ACTION_PERFORMED, null)); // TODO: potentially reopen the windows that were opened before the length was changed for improved workflow
940          }
941          rhythmInputPanel.setLength(getLength());
942          rhythmInputPanel.repaint();
943          rhythmDisplayRhythmPanel.setLength(getLength());
944          chordsInputPanel.setLength(getLength());
945          chordsInputPanel.repaint();
946          chordsDisplayChordsPanel.setLength(getLength());
947          oneChordInput.setVisible(false); // TODO: potentially reopen the windows that were opened before the length was changed for improved workflow
948          melodyDisplayMelodyPanel.setLength(getLength());
949          melodyDisplayMelodyPanel.setErase(true);
950          melodyDisplayMelodyPanel.repaint();
951      }
952  
953      private void updateChordRootNoteModel(){
954          // Delete all elements but the last one (caused NullPointerException)
955          int size = chordRootNoteModel.getSize();
956          for(int i = 0; i < size-1; i++){
957              chordRootNoteModel.removeElementAt(0);
958          }
959          // Add new elements
960          addChordRootNoteModelElements();
961          // Delete the last element that was still left from the last set of notes
962          chordRootNoteModel.removeElementAt(0);
963      }
964  
965      private void addChordRootNoteModelElements(){
966          for(int i = getCalcMelody().findAllNotesIndex((String)tonicCB.getSelectedItem()); i < getCalcMelody().findAllNotesIndex((String)tonicCB.getSelectedItem()) + getCalcMelody().getAllNotes().length; i++){
967              if(i < getCalcMelody().getAllNotes().length){
968                  if(getCalcMelody().findKeyNoteIndex(getCalcMelody().getAllNotes()[i]) != -1){
969                      chordRootNoteModel.addElement(getCalcMelody().getAllNotes()[i] + " (" + toRoman(getCalcMelody().findKeyNoteIndex(getCalcMelody().getAllNotes()[i]) + 1) + ")");
970                  } else {
971                      chordRootNoteModel.addElement(getCalcMelody().getAllNotes()[i]);
972                  }
973              } else {
974                  if(getCalcMelody().findKeyNoteIndex(getCalcMelody().getAllNotes()[i-getCalcMelody().getAllNotes().length]) != -1){
975                      chordRootNoteModel.addElement(getCalcMelody().getAllNotes()[i-getCalcMelody().getAllNotes().length] + " (" + toRoman(getCalcMelody().findKeyNoteIndex(getCalcMelody().getAllNotes()[i-getCalcMelody().getAllNotes().length]) + 1) + ")");
976                  } else {
977                      chordRootNoteModel.addElement(getCalcMelody().getAllNotes()[i-getCalcMelody().getAllNotes().length]);
978                  }
979              }
980          }
981      }
982  
983      private void updateCheckBoxes(){ // updates which CheckBoxes should be visible depending on the currently selected key/rootNote & updates the names of the notes of the CheckBoxes
984          if(getCalcMelody().findKeyNoteIndex(Melody.extractActualNoteName((String)chordRootNoteCB.getSelectedItem())) != -1){ // rootNote == keyNote
985              keyNoteCheckBox8.setVisible(false);
986              extraNoteCheckBox5.setVisible(true);
987              updateCheckBoxNotes();
988          } else { // rootNote == extraNote
989              keyNoteCheckBox8.setVisible(true);
990              extraNoteCheckBox5.setVisible(false);
991              updateCheckBoxNotes();
992          }
993      }
994  
995      private void updateCheckBoxNotes(){ // updates the names of the notes of the CheckBoxes
996          int keyIndex = 0;
997          int extraIndex = 0;
998          for(int i = getCalcMelody().findAllNotesIndex(Melody.extractActualNoteName((String)chordRootNoteCB.getSelectedItem()))+1; i < getCalcMelody().getAllNotes().length; i++){ // start iteration through allNotes on note after rootNote
999              if(getCalcMelody().findKeyNoteIndex(getCalcMelody().getAllNotes()[i]) != -1){ // current note = keyNote
1000                 keyNotesCheckBoxesArray[keyIndex].setText(getCalcMelody().getAllNotes()[i] + " (" + (keyIndex+2) + "/" + (keyIndex+2+7) + ")");
1001                 keyIndex++;
1002             } else { // current note = extraNote
1003                 extraNotesCheckBoxesArray[extraIndex].setText(getCalcMelody().getAllNotes()[i]);
1004                 extraIndex++;
1005             }
1006         }
1007         for(int i = 0; i <= getCalcMelody().findAllNotesIndex(Melody.extractActualNoteName((String)chordRootNoteCB.getSelectedItem())); i++){ // finish iteration through allNotes
1008             if(getCalcMelody().findKeyNoteIndex(getCalcMelody().getAllNotes()[i]) != -1){ // current note = keyNote
1009                 if(keyIndex != 6){
1010                     keyNotesCheckBoxesArray[keyIndex].setText(getCalcMelody().getAllNotes()[i] + " (" + (keyIndex+2) + "/" + (keyIndex+2+7) + ")");
1011                 } else {
1012                     keyNotesCheckBoxesArray[keyIndex].setText(getCalcMelody().getAllNotes()[i] + " (" + (keyIndex+2) + ")");
1013                 }
1014                 keyIndex++;
1015             } else { // current note = extraNote
1016                 extraNotesCheckBoxesArray[extraIndex].setText(getCalcMelody().getAllNotes()[i]);
1017                 extraIndex++;
1018             }
1019         }
1020     }
1021 
1022     private void invokeCheckBoxActionListeners(){ // updates getBufferChord() information
1023         // keyNoteCheckBoxes
1024         for(int i = 0; i < keyNotesCheckBoxesArray.length; i++){
1025             for(ActionListener a: keyNotesCheckBoxesArray[i].getActionListeners()){
1026                 a.actionPerformed(new ActionEvent(keyNotesCheckBoxesArray[i], ActionEvent.ACTION_PERFORMED, null));
1027             }
1028         }
1029         // extraNoteCheckBoxes
1030         for(int i = 0; i < extraNotesCheckBoxesArray.length; i++){
1031             for(ActionListener a: extraNotesCheckBoxesArray[i].getActionListeners()){
1032                 a.actionPerformed(new ActionEvent(extraNotesCheckBoxesArray[i], ActionEvent.ACTION_PERFORMED, null));
1033             }
1034         }
1035     }
1036 
1037     private void updateCheckBoxSelectionStatus(Chord chord){ // updates the CheckBoxes so that their selection status corresponds to the selected notes of the parameter (input) chord
1038         if(getCalcMelody().findKeyNoteIndex(Melody.extractActualNoteName((String)chordRootNoteCB.getSelectedItem())) != -1){ // rootNote == keyNote
1039             // keyNoteCheckBoxes
1040             for(int i = 0; i < keyNotesCheckBoxesArray.length-1; i++){ // omit the last CheckBox because it's the root note and not visible anyway
1041                 keyNotesCheckBoxesArray[i].setSelected(chord.getKeyChordNotes()[i+1] != null);
1042             }
1043             // extraNoteCheckBoxes
1044             for(int i = 0; i < extraNotesCheckBoxesArray.length; i++){
1045                 extraNotesCheckBoxesArray[i].setSelected(chord.getExtraChordNotes()[i] != null);
1046             }
1047         } else { // rootNote == extraNote
1048             // keyNoteCheckBoxes
1049             for(int i = 0; i < keyNotesCheckBoxesArray.length; i++){
1050                 keyNotesCheckBoxesArray[i].setSelected(chord.getKeyChordNotes()[i] != null);
1051             }
1052             // extraNoteCheckBoxes
1053             for(int i = 0; i < extraNotesCheckBoxesArray.length-1; i++){ // omit the last CheckBox because it's the root note and not visible anyway
1054                 extraNotesCheckBoxesArray[i].setSelected(chord.getExtraChordNotes()[i+1] != null);
1055             }
1056         }
1057     }
1058 
1059     private void updateArpeggiateCBSelectedIndex(){
1060         if(getBufferOneChord().getArpeggiate()){
1061             arpeggiateCB.setSelectedIndex(1);
1062         } else {
1063             arpeggiateCB.setSelectedIndex(0);
1064         }
1065     }
1066 
1067     private static String toRoman(int number) {
1068         return String.valueOf(new char[number]).replace('\0', 'I')
1069                 .replace("IIIII", "V")
1070                 .replace("IIII", "IV")
1071                 .replace("VV", "X")
1072                 .replace("VIV", "IX")
1073                 .replace("XXXXX", "L")
1074                 .replace("XXXX", "XL")
1075                 .replace("LL", "C")
1076                 .replace("LXL", "XC")
1077                 .replace("CCCCC", "D")
1078                 .replace("CCCC", "CD")
1079                 .replace("DD", "M")
1080                 .replace("DCD", "CM");
1081     }
1082 
1083     private void outputChords(Chord[] chords){
1084         for(int i = 0; i < chords.length; i++){
1085             System.out.println(i + ": ");
1086             if(chords[i] != null){
1087                 System.out.println("Rootnote: " + chords[i].getRootNote());
1088                 System.out.println("Arpeggiate: " + chords[i].getArpeggiate());
1089                 System.out.println("KeyChordNotes: ");
1090                 for(int j = 0; j < chords[i].getKeyChordNotes().length; j++){
1091                     System.out.print(chords[i].getKeyChordNotes()[j] + ", ");
1092                 }
1093                 System.out.println("");
1094                 System.out.println("ExtraChordNotes: ");
1095                 for(int j = 0; j < chords[i].getExtraChordNotes().length; j++){
1096                     System.out.print(chords[i].getExtraChordNotes()[j] + ", ");
1097                 }
1098             } else {
1099                 System.out.println("Null");
1100             }
1101             System.out.println("\n");
1102         }
1103     }
1104 
1105     private int findChordRootNoteCBNoteIndex(String note){
1106         for(int i = 0; i < 12; i++){
1107             if(chordRootNoteCB.getItemAt(i).equals(note)){
1108                 return i;
1109             }
1110         }
1111         return -1;
1112     }
1113 
1114     private Chord copyOnlyChordInformationAndNotReference(Chord chord){ // returns new Chord with all the information of the input chord
1115         // copy rootNote
1116         Chord newChord = new Chord(chord.getRootNote(), getCalcMelody().findKeyNoteIndex(Melody.extractActualNoteName(chord.getRootNote())) != -1);
1117         // copy keyNotes
1118         for(int i = 0; i < newChord.getKeyChordNotes().length; i++){
1119             newChord.getKeyChordNotes()[i] = chord.getKeyChordNotes()[i];
1120         }
1121         // copy extraNotes
1122         for(int i = 0; i < newChord.getExtraChordNotes().length; i++){
1123             newChord.getExtraChordNotes()[i] = chord.getExtraChordNotes()[i];
1124         }
1125         // copy arpeggiate
1126         newChord.setArpeggiate(chord.getArpeggiate());
1127         // copy chordRootNoteCBIndex
1128         newChord.setChordRootNoteCBIndex(chord.getChordRootNoteCBIndex());
1129         return newChord;
1130     }
1131 
1132     private void transposeChords(Chord[] chords){ // this is only used when the key was changed and getChordsEntered() is true
1133         int index = 0;
1134         for(int i = 0; i < chords.length; i++){
1135             if(i == index){
1136                 if(chords[i] != null){
1137                     // transpose the chord at the index 'i'
1138                     chordRootNoteCB.setSelectedIndex(chords[i].getChordRootNoteCBIndex()); // this updates the notes to the transposed chord's ones
1139                     setBufferOneChord(new Chord((String)chordRootNoteCB.getSelectedItem(), getCalcMelody().findKeyNoteIndex(Melody.extractActualNoteName((String)chordRootNoteCB.getSelectedItem())) != -1)); // make sure that each chord references a new (transposed) chord
1140                     getBufferOneChord().setChordRootNoteCBIndex(chords[i].getChordRootNoteCBIndex());
1141                     getBufferOneChord().setArpeggiate(chords[i].getArpeggiate());
1142                     updateCheckBoxSelectionStatus(chords[i]); // this keeps the selected notes of the original chord stored in the oneChordFrame
1143                     invokeCheckBoxActionListeners(); // this extracts the new note information from the frame to the bufferChord
1144                     // save the transposed chord to as many beats as necessary
1145                     while(index < chords.length-1 && Chord.chordsEqual(chords[i], chords[index+1])){ // always keep the chord of the first beat of potentially several beats of the same chord in order to have something to compare the other beats to
1146                         chords[index+1] = copyOnlyChordInformationAndNotReference(getBufferOneChord()); // save some time by not repeating this process of transposing for every beat that actually stores the same chord info as the beat before
1147                         index++;
1148                     }
1149                     chords[i] = copyOnlyChordInformationAndNotReference(getBufferOneChord());
1150                 }
1151                 index++; // index has to be incremented even if the current chord is null
1152             }
1153         }
1154     }
1155 
1156     private void updateKey(){
1157         calcMelody.createKeyNotes((String)tonicCB.getSelectedItem(), scaleCB.getSelectedIndex()); // updateCalcMelodyNotes
1158         updateChordRootNoteModel();
1159         if(getChordsEntered()){
1160             // transpose getBufferChords() & getChords()
1161             transposeChords(getBufferChords());
1162             transposeChords(getChords());
1163             // update chords everywhere else
1164             chordsInputPanel.setChords(getBufferChords());
1165             chordsInputPanel.repaint();
1166             chordsDisplayChordsPanel.setChords(getChords());
1167             chordsDisplayChordsPanel.repaint();
1168             melodyDisplayMelodyPanel.setChords(getChords());
1169         }
1170     }
1171 }
1172