View Javadoc
1   package com.jsql.view.swing.menubar;
2   
3   import com.formdev.flatlaf.intellijthemes.FlatDarkFlatIJTheme;
4   import com.formdev.flatlaf.intellijthemes.FlatHighContrastIJTheme;
5   import com.formdev.flatlaf.intellijthemes.FlatLightFlatIJTheme;
6   import com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatMTGitHubDarkIJTheme;
7   import com.formdev.flatlaf.intellijthemes.materialthemeuilite.FlatMTGitHubIJTheme;
8   import com.formdev.flatlaf.themes.FlatMacDarkLaf;
9   import com.formdev.flatlaf.themes.FlatMacLightLaf;
10  import com.jsql.util.I18nUtil;
11  import com.jsql.util.PreferencesUtil;
12  import com.jsql.view.swing.action.ActionNewWindow;
13  import com.jsql.view.swing.dialog.translate.Language;
14  import com.jsql.view.swing.panel.PanelPreferences;
15  import com.jsql.view.swing.sql.SqlEngine;
16  import com.jsql.view.swing.tab.TabHeader;
17  import com.jsql.view.swing.util.I18nViewUtil;
18  import com.jsql.view.swing.util.MediatorHelper;
19  import com.jsql.view.swing.util.RadioItemNonClosing;
20  import com.jsql.view.swing.util.UiUtil;
21  import org.apache.logging.log4j.util.Strings;
22  
23  import javax.swing.*;
24  import java.awt.*;
25  import java.awt.event.ActionEvent;
26  import java.awt.event.InputEvent;
27  import java.awt.event.KeyEvent;
28  import java.awt.event.MouseEvent;
29  import java.util.AbstractMap;
30  import java.util.Arrays;
31  import java.util.Locale;
32  import java.util.concurrent.atomic.AtomicBoolean;
33  import java.util.concurrent.atomic.AtomicInteger;
34  
35  public class MenuWindows extends JMenu {
36  
37      private static final String I18N_SQL_ENGINE = "MENUBAR_SQL_ENGINE";
38      private static final String I18N_PREFERENCES = "MENUBAR_PREFERENCES";
39  
40      public static final String ACTION_STARTING_APP = "init";
41      public static final String MENU_WINDOWS = "menuWindows";
42      public static final String MENU_TRANSLATION = "menuTranslation";
43      public static final String ITEM_RUSSIAN = "itemRussian";
44      public static final String ITEM_ENGLISH = "itemEnglish";
45  
46      private final AppMenubar appMenubar;
47  
48      private final JMenu menuView;
49  
50      public MenuWindows(AppMenubar appMenubar) {
51          super(I18nUtil.valueByKey("MENUBAR_WINDOWS"));
52          this.appMenubar = appMenubar;
53  
54          this.setName(MenuWindows.MENU_WINDOWS);
55          I18nViewUtil.addComponentForKey("MENUBAR_WINDOWS", this);
56          this.setMnemonic('W');
57  
58          JMenuItem itemNewWindows = new JMenuItem(new ActionNewWindow());
59          I18nViewUtil.addComponentForKey("NEW_WINDOW_MENU", itemNewWindows);
60  
61          this.add(itemNewWindows);
62          var menuAppearance = new JMenu(I18nUtil.valueByKey("MENUBAR_APPEARANCE"));
63          I18nViewUtil.addComponentForKey("MENUBAR_APPEARANCE", menuAppearance);
64          menuAppearance.setMnemonic('A');
65  
66          JMenuItem itemNewWindows4k = new JMenuItem(
67              new ActionNewWindow("Open window in 4K resolution...", "-Dsun.java2d.uiScale=2.5")
68          );
69          menuAppearance.add(itemNewWindows4k);
70  
71          var groupRadio = new ButtonGroup();
72          var menuThemes = new JMenu(I18nUtil.valueByKey("MENUBAR_THEMES"));
73          I18nViewUtil.addComponentForKey("MENUBAR_THEMES", menuAppearance);
74          menuThemes.setMnemonic('T');
75  
76          Arrays.asList(
77              new AbstractMap.SimpleEntry<>(FlatLightFlatIJTheme.class.getName(), "IntelliJ"),
78              new AbstractMap.SimpleEntry<>(FlatDarkFlatIJTheme.class.getName(), "IntelliJ Dark"),
79              new AbstractMap.SimpleEntry<>(FlatMacLightLaf.class.getName(), "macOS"),
80              new AbstractMap.SimpleEntry<>(FlatMacDarkLaf.class.getName(), "macOS Dark"),
81              new AbstractMap.SimpleEntry<>(FlatMTGitHubIJTheme.class.getName(), "GitHub"),
82              new AbstractMap.SimpleEntry<>(FlatMTGitHubDarkIJTheme.class.getName(), "GitHub Dark"),
83              new AbstractMap.SimpleEntry<>(FlatHighContrastIJTheme.class.getName(), "High contrast")
84          ).forEach(entry -> {
85              JMenuItem item = new RadioItemNonClosing(
86                  new AbstractAction() {
87                      @Override
88                      public void actionPerformed(ActionEvent e) {
89                          AppMenubar.applyTheme(entry.getKey());
90                      }
91                  }
92              );
93              item.setText(entry.getValue());
94              item.setSelected(entry.getKey().equals(MediatorHelper.model().getMediatorUtils().preferencesUtil().getThemeFlatLafName()));
95              groupRadio.add(item);
96              menuThemes.add(item);
97          });
98  
99          this.add(itemNewWindows);
100         this.add(menuAppearance);
101         this.add(menuThemes);
102         this.add(new JSeparator());
103         this.add(this.initMenuTranslation());
104         this.add(new JSeparator());
105 
106         this.menuView = new JMenu(I18nUtil.valueByKey("MENUBAR_VIEW"));
107         I18nViewUtil.addComponentForKey("MENUBAR_VIEW", this.menuView);
108         this.menuView.setMnemonic('V');
109 
110         AtomicInteger accelerator = new AtomicInteger(0x31);
111         AtomicInteger tabPosition = new AtomicInteger();
112         MediatorHelper.frame().getTabManagers().getIconsTabs().forEach(entry -> {
113             var menuItem = new JMenuItem(I18nUtil.valueByKey(entry.getKeyLabel()), entry.getIcon());
114             I18nViewUtil.addComponentForKey(entry.getKeyLabel(), menuItem);
115             menuItem.setName(entry.getKeyLabel());  // required by card manager switch
116             this.menuView.add(menuItem);
117 
118             menuItem.setAccelerator(KeyStroke.getKeyStroke(
119                 KeyEvent.getExtendedKeyCodeForChar(accelerator.getAndIncrement()),
120                 InputEvent.CTRL_DOWN_MASK
121             ));
122 
123             final var position = tabPosition.get();  // required by closure
124             menuItem.addActionListener(actionEvent -> {  // setAction() could set action+text+icon but i18n not easy
125                 CardLayout cardLayout = (CardLayout) MediatorHelper.tabManagersCards().getLayout();
126                 cardLayout.show(MediatorHelper.tabManagersCards(), menuItem.getName());
127                 MediatorHelper.frame().getTabManagers().setSelectedIndex(position);
128             });
129             tabPosition.getAndIncrement();
130         });
131 
132         this.add(this.menuView);
133 
134         var menuPanel = new JMenu(I18nUtil.valueByKey("MENUBAR_PANEL"));
135         I18nViewUtil.addComponentForKey("MENUBAR_PANEL", menuPanel);
136         menuPanel.setMnemonic('C');
137 
138         Arrays.asList(
139             new ModelCheckboxMenu(
140                 "CONSOLE_CHUNK_LABEL",
141                 PreferencesUtil.CHUNK_VISIBLE,
142                 () -> MediatorHelper.panelConsoles().insertChunkTab(),
143                 UiUtil.CHUNK.getIcon()
144             ),
145             new ModelCheckboxMenu(
146                 "CONSOLE_BINARY_LABEL",
147                 PreferencesUtil.BINARY_VISIBLE,
148                 () -> MediatorHelper.panelConsoles().insertBooleanTab(),
149                 UiUtil.BINARY.getIcon()
150             ),
151             new ModelCheckboxMenu(
152                 "CONSOLE_NETWORK_LABEL",
153                 PreferencesUtil.NETWORK_VISIBLE,
154                 () -> MediatorHelper.panelConsoles().insertNetworkTab(),
155                 UiUtil.NETWORK.getIcon()
156             ),
157             new ModelCheckboxMenu(
158                 "CONSOLE_JAVA_LABEL",
159                 PreferencesUtil.JAVA_VISIBLE,
160                 () -> MediatorHelper.panelConsoles().insertJavaTab(),
161                 UiUtil.CUP.getIcon(),
162                 false
163             )
164         ).forEach(model -> {
165             var menuItem = new JCheckBoxMenuItem(
166                 I18nUtil.valueByKey(model.i18n),
167                 model.icon,
168                 model.isChecked
169             ) {
170                 @Override
171                 protected void processMouseEvent(MouseEvent e) {
172                     if (RadioItemNonClosing.shouldClose(e, this)) {
173                         super.processMouseEvent(e);
174                     }
175                 }
176             };
177             I18nViewUtil.addComponentForKey(model.i18n, menuItem);
178             menuPanel.add(menuItem);
179 
180             menuItem.addActionListener(actionEvent -> {
181                 if (menuItem.isSelected()) {
182                     model.runnableInsertTab.run();
183                 } else {
184                     MediatorHelper.tabConsoles().remove(MediatorHelper.tabConsoles().indexOfTab(model.icon));
185                 }
186             });
187         });
188 
189         this.add(menuPanel);
190         this.add(new JSeparator());
191         this.add(this.getMenuItemSqlEngine());
192         this.add(this.getMenuItemPreferences());
193     }
194 
195     private JMenuItem getMenuItemSqlEngine() {
196         var itemSqlEngine = new JMenuItem(I18nUtil.valueByKey(MenuWindows.I18N_SQL_ENGINE));
197         I18nViewUtil.addComponentForKey(MenuWindows.I18N_SQL_ENGINE, itemSqlEngine);
198         itemSqlEngine.setName("itemSqlEngine");
199         itemSqlEngine.setMnemonic('S');
200 
201         itemSqlEngine.addActionListener(actionEvent -> {
202             var titleTabSqlEngine = "SQL Engine";
203             for (var i = 0 ; i < MediatorHelper.tabResults().getTabCount() ; i++) {
204                 if (titleTabSqlEngine.equals(MediatorHelper.tabResults().getTitleAt(i))) {
205                     MediatorHelper.tabResults().setSelectedIndex(i);
206                     return;
207                 }
208             }
209 
210             MediatorHelper.frame().getSplitNS().initSplitOrientation();
211 
212             var panelSqlEngine = new SqlEngine();
213             MediatorHelper.tabResults().addTab(titleTabSqlEngine, panelSqlEngine);
214             MediatorHelper.tabResults().setSelectedComponent(panelSqlEngine);  // Focus on the new tab
215 
216             // Create a custom tab header
217             var header = new TabHeader(I18nViewUtil.valueByKey(MenuWindows.I18N_SQL_ENGINE), UiUtil.COG.getIcon());
218             I18nViewUtil.addComponentForKey(MenuWindows.I18N_SQL_ENGINE, header.getTabLabel());
219 
220             // Apply the custom header to the tab
221             MediatorHelper.tabResults().setTabComponentAt(MediatorHelper.tabResults().indexOfComponent(panelSqlEngine), header);
222             MediatorHelper.tabResults().updateUI();  // required: light, open/close prefs, dark => light artifacts
223         });
224 
225         return itemSqlEngine;
226     }
227 
228     private JMenuItem getMenuItemPreferences() {
229         JMenuItem itemPreferences = new JMenuItem(I18nUtil.valueByKey(MenuWindows.I18N_PREFERENCES), 'P');
230         I18nViewUtil.addComponentForKey(MenuWindows.I18N_PREFERENCES, itemPreferences);
231         itemPreferences.setName("itemPreferences");
232 
233         // Render the Preferences dialog behind the scene
234         var titleTabPreferences = "Preferences";
235 
236         itemPreferences.addActionListener(actionEvent -> {
237             for (var i = 0 ; i < MediatorHelper.tabResults().getTabCount() ; i++) {
238                 if (titleTabPreferences.equals(MediatorHelper.tabResults().getTitleAt(i))) {
239                     MediatorHelper.tabResults().setSelectedIndex(i);
240                     return;
241                 }
242             }
243 
244             MediatorHelper.frame().getSplitNS().initSplitOrientation();
245 
246             var panelPreferences = new PanelPreferences();
247             MediatorHelper.tabResults().addTab(titleTabPreferences, panelPreferences);
248             MediatorHelper.tabResults().setSelectedComponent(panelPreferences);  // Focus on the new tab
249 
250             // Create a custom tab header
251             var header = new TabHeader(I18nViewUtil.valueByKey(MenuWindows.I18N_PREFERENCES), UiUtil.COG.getIcon());
252             I18nViewUtil.addComponentForKey(MenuWindows.I18N_PREFERENCES, header.getTabLabel());
253 
254             // Apply the custom header to the tab
255             MediatorHelper.tabResults().setTabComponentAt(MediatorHelper.tabResults().indexOfComponent(panelPreferences), header);
256 
257             MediatorHelper.tabResults().updateUI();  // required: light, open/close prefs, dark => light artifacts
258         });
259 
260         return itemPreferences;
261     }
262 
263     private JMenu initMenuTranslation() {
264         var menuTranslation = new JMenu(I18nUtil.valueByKey("MENUBAR_LANGUAGE"));
265         I18nViewUtil.addComponentForKey("MENUBAR_LANGUAGE", menuTranslation);
266         menuTranslation.setName(MenuWindows.MENU_TRANSLATION);
267         menuTranslation.setMnemonic('L');
268 
269         var groupRadioLanguage = new ButtonGroup();
270         var atomicIsAnySelected = new AtomicBoolean(false);
271         AppMenubar.ITEMS_TRANSLATE.forEach(model -> {
272             atomicIsAnySelected.set(atomicIsAnySelected.get() || model.getLanguage().isCurrentLanguage());
273             model.setMenuItem(new RadioItemNonClosing(
274                 model.getLanguage().getMenuItemLabel(),
275                 model.getLanguage().getFlag(),
276                 model.getLanguage().isCurrentLanguage()
277             ));
278             model.getMenuItem().addActionListener(actionEvent -> {
279                 var newLocale = model.getLanguage() == Language.EN
280                     ? Locale.ROOT  // required as no bundle 'en'
281                     : Locale.forLanguageTag(model.getLanguage().getLanguageTag());
282                 this.appMenubar.switchLocale(newLocale);
283                 if (!MenuWindows.ACTION_STARTING_APP.equals(model.getMenuItem().getActionCommand())) {
284                     MediatorHelper.model().getPropertiesUtil().displayI18nStatus(newLocale);
285                 }
286                 model.getMenuItem().setActionCommand(Strings.EMPTY);
287                 MediatorHelper.model().getMediatorUtils().preferencesUtil().withLanguageTag(model.getLanguage().getLanguageTag()).persist();
288             });
289             menuTranslation.add(model.getMenuItem());
290             groupRadioLanguage.add(model.getMenuItem());
291         });
292 
293         AppMenubar.ITEMS_TRANSLATE.stream()
294         .filter(model -> model.getLanguage() == Language.EN)
295         .forEach(modelItem -> {
296             modelItem.getMenuItem().setSelected(!atomicIsAnySelected.get());
297             modelItem.getMenuItem().setName(MenuWindows.ITEM_ENGLISH);
298         });
299         AppMenubar.ITEMS_TRANSLATE.stream()
300         .filter(model -> model.getLanguage() == Language.RU)
301         .forEach(modelItem -> modelItem.getMenuItem().setName(MenuWindows.ITEM_RUSSIAN));
302         AppMenubar.ITEMS_TRANSLATE.stream()
303         .filter(model -> model.getLanguage() == Language.AR)
304         .forEach(modelItem -> modelItem.getMenuItem().setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT));
305 
306         return menuTranslation;
307     }
308 
309     public void switchLocaleFromPreferences() {
310         AppMenubar.ITEMS_TRANSLATE.stream().filter(model -> model.getLanguage().getLanguageTag().equals(
311             MediatorHelper.model().getMediatorUtils().preferencesUtil().getLanguageTag()
312         ))
313         .forEach(modelItem -> {
314             modelItem.getMenuItem().setActionCommand(MenuWindows.ACTION_STARTING_APP);
315             modelItem.getMenuItem().doClick();
316         });
317     }
318 
319 
320     // Getter and setter
321 
322     public JMenu getMenuView() {
323         return this.menuView;
324     }
325 }