Changed license to CC0
[instantlauncher.git] / src / main / java / eu / svjatoslav / instantlauncher / menu / Menu.java
1 /*
2  * Instantlauncher. Author: Svjatoslav Agejenko, svjatoslav@svjatoslav.eu
3  * This project is released under Creative Commons Zero (CC0) license.
4  */
5 package eu.svjatoslav.instantlauncher.menu;
6
7 import eu.svjatoslav.commons.gui.dialog.ExceptionDialog;
8 import eu.svjatoslav.instantlauncher.Utils;
9
10 import javax.swing.*;
11 import javax.swing.border.EmptyBorder;
12 import java.awt.*;
13 import java.awt.event.MouseEvent;
14 import java.awt.event.MouseListener;
15 import java.io.File;
16 import java.util.Arrays;
17 import java.util.HashSet;
18 import java.util.Set;
19
20 class Menu {
21
22     public static final Dimension SIZE_MENU_PANEL = new Dimension(210, 900);
23     private static final Color BUTTON_BG_DIRECTORY = new Color(0, 0, 60);
24
25     private static final Color BUTTON_BG_DIRECTORY_SELECTED = new Color(0, 0, 100);
26     private static final Color BUTTON_BG_LINK = new Color(60, 60, 0);
27
28     private static final Color BUTTON_BG_LINK_SELECTED = new Color(100, 100, 0);
29     private static final Color BUTTON_BG_EXECUTABLE_FILE = new Color(60, 0, 0);
30
31     private static final Color BUTTON_BG_EXECUTABLE_FILE_SELECTED = new Color(100, 0, 0);
32     private static final Color BUTTON_BG_NONEXECUTABLE_FILE = new Color(0, 60, 0);
33
34     private static final Color BUTTON_BG_NONEXECUTABLE_FILE_SELECTED = new Color(0, 100, 0);
35     private static final Dimension SIZE_BUTTON = new Dimension(200, 30);
36     private final Set<MenuListener> menuListeners = new HashSet<>();
37     private JPanel menuPanel;
38     private JButton selectedButton;
39     private File selectedFile;
40
41     public Menu(final File directory) {
42         buildContentPanel(directory);
43     }
44
45     /**
46      * <pre>
47      * Assign specific colors to:
48      *    Directory
49      *    Executable file
50      *    Non executable file
51      * </pre>
52      */
53     private static Color getFileColor(final File file, final boolean selected) {
54         if (file.isDirectory())
55             if (selected)
56                 return BUTTON_BG_DIRECTORY_SELECTED;
57             else
58                 return BUTTON_BG_DIRECTORY;
59
60         if (file.isFile())
61             if (file.canExecute()) {
62                 if (selected)
63                     return BUTTON_BG_EXECUTABLE_FILE_SELECTED;
64                 else
65                     return BUTTON_BG_EXECUTABLE_FILE;
66             } else if (selected)
67                 return BUTTON_BG_NONEXECUTABLE_FILE_SELECTED;
68             else
69                 return BUTTON_BG_NONEXECUTABLE_FILE;
70
71         if (selected)
72             return BUTTON_BG_LINK_SELECTED;
73         else
74             return BUTTON_BG_LINK;
75     }
76
77     public void addMenuListener(final MenuListener menuListener) {
78         menuListeners.add(menuListener);
79     }
80
81     private JButton buildButton(final File file) {
82         JButton button;
83         if (file.isDirectory())
84             button = new JButton("[ " + file.getName() + " ]");
85         else
86             button = new JButton(file.getName());
87
88         button.setBackground(getFileColor(file, false));
89         button.setForeground(new Color(255, 255, 255));
90
91         button.setBorder(new EmptyBorder(5, 10, 5, 10));
92
93         final Menu.ButtonMouseListener mouseListener = new ButtonMouseListener(button, this, file);
94         button.addMouseListener(mouseListener);
95
96         button.setHorizontalTextPosition(SwingConstants.CENTER);
97
98         // set button size
99         Utils.setComponentSize(button, SIZE_BUTTON);
100
101         return button;
102     }
103
104     private void buildContentPanel(final File directory) {
105         menuPanel = new JPanel();
106
107         Utils.setComponentSize(menuPanel, SIZE_MENU_PANEL);
108
109         final BoxLayout layout = new BoxLayout(menuPanel, BoxLayout.Y_AXIS);
110         menuPanel.setLayout(layout);
111         menuPanel.setBackground(Color.BLACK);
112
113         final File[] listFiles = directory.listFiles();
114
115         // Sort files by name
116         Arrays.sort(listFiles, (f1, f2) -> {
117
118             // directories come before files
119             if (f1.isFile() && f2.isDirectory())
120                 return 1;
121             if (f2.isFile() && f1.isDirectory())
122                 return -1;
123
124             // order by file name
125             return f1.getName().toUpperCase().compareTo(f2.getName().toUpperCase());
126         });
127
128         // add files to the panel
129         for (final File file : listFiles)
130             // ignore hidden files
131             if (!file.getName().startsWith(".")) {
132                 menuPanel.add(Box.createVerticalStrut(10));
133                 menuPanel.add(buildButton(file));
134             }
135     }
136
137     public JPanel getMenuPanel() {
138         return menuPanel;
139     }
140
141     private JButton getSelectedButton() {
142         return selectedButton;
143     }
144
145     private File getSelectedFile() {
146         return selectedFile;
147     }
148
149     private void menuItemHighlighted(final File chosenFile) {
150         for (final MenuListener menuListener : menuListeners)
151             menuListener.menuItemHighlighted(this, chosenFile);
152     }
153
154     private void menuItemSelected(final File chosenFile) {
155         for (final MenuListener menuListener : menuListeners)
156             menuListener.menuItemSelected(chosenFile);
157     }
158
159     private void menuItemSelectedAlternative(final File chosenFile) {
160         for (final MenuListener menuListener : menuListeners)
161             menuListener.menuItemSelectedAlternative(chosenFile);
162     }
163
164     private void menuItemSelectedAlternative2(final File chosenFile) {
165         for (final MenuListener menuListener : menuListeners)
166             menuListener.menuItemSelectedAlternative2(chosenFile);
167     }
168
169     private void setSelected(final JButton selectedButton, final File selectedFile) {
170         this.selectedButton = selectedButton;
171         this.selectedFile = selectedFile;
172     }
173
174     public static class ButtonMouseListener implements MouseListener {
175
176         final JButton parentButton;
177         final Menu parentMenu;
178         final File file;
179
180         public ButtonMouseListener(final JButton button, final Menu parentMenu, final File file) {
181             parentButton = button;
182             this.parentMenu = parentMenu;
183             this.file = file;
184         }
185
186         @Override
187         public void mouseClicked(final MouseEvent e) {
188             try {
189
190                 if (e.getButton() == 1) // left mouse click
191                     parentMenu.menuItemSelected(file);
192                 if (e.getButton() == 2) // middle mouse click
193                     parentMenu.menuItemSelectedAlternative2(file);
194                 if (e.getButton() == 3) //right mouse click
195                     parentMenu.menuItemSelectedAlternative(file);
196             } catch (final Exception ex) {
197                 new ExceptionDialog(ex);
198             }
199         }
200
201         @Override
202         public void mouseEntered(final MouseEvent e) {
203             try {
204                 if (parentButton != parentMenu.getSelectedButton()) {
205
206                     if (parentMenu.getSelectedButton() != null)
207                         parentMenu.getSelectedButton().setBackground(getFileColor(parentMenu.getSelectedFile(), false));
208
209                     parentMenu.setSelected(parentButton, file);
210                     parentButton.setBackground(getFileColor(file, true));
211
212                     parentMenu.menuItemHighlighted(file);
213                 }
214             } catch (final Exception ex) {
215                 new ExceptionDialog(ex);
216             }
217         }
218
219         @Override
220         public void mouseExited(final MouseEvent e) {
221         }
222
223         @Override
224         public void mousePressed(final MouseEvent e) {
225         }
226
227         @Override
228         public void mouseReleased(final MouseEvent e) {
229         }
230
231     }
232
233 }