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