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_ARABIC = "itemArabic";
45      public static final String ITEM_ENGLISH = "itemEnglish";
46  
47      private final AppMenubar appMenubar;
48  
49      private final JMenu menuView;
50  
51      public MenuWindows(AppMenubar appMenubar) {
52          super(I18nUtil.valueByKey("MENUBAR_WINDOWS"));
53          this.appMenubar = appMenubar;
54  
55          this.setName(MenuWindows.MENU_WINDOWS);
56          I18nViewUtil.addComponentForKey("MENUBAR_WINDOWS", this);
57          this.setMnemonic('W');
58  
59          JMenuItem itemNewWindows = new JMenuItem(new ActionNewWindow());
60          I18nViewUtil.addComponentForKey("NEW_WINDOW_MENU", itemNewWindows);
61  
62          this.add(itemNewWindows);
63          var menuAppearance = new JMenu(I18nUtil.valueByKey("MENUBAR_APPEARANCE"));
64          I18nViewUtil.addComponentForKey("MENUBAR_APPEARANCE", menuAppearance);
65          menuAppearance.setMnemonic('A');
66  
67          JMenuItem itemNewWindows4k = new JMenuItem(
68              new ActionNewWindow("Open window in 4K resolution...", "-Dsun.java2d.uiScale=2.5")
69          );
70          menuAppearance.add(itemNewWindows4k);
71  
72          var groupRadio = new ButtonGroup();
73          var menuThemes = new JMenu(I18nUtil.valueByKey("MENUBAR_THEMES"));
74          I18nViewUtil.addComponentForKey("MENUBAR_THEMES", menuAppearance);
75          menuThemes.setMnemonic('T');
76  
77          Arrays.asList(
78              new AbstractMap.SimpleEntry<>(FlatLightFlatIJTheme.class.getName(), "IntelliJ"),
79              new AbstractMap.SimpleEntry<>(FlatDarkFlatIJTheme.class.getName(), "IntelliJ Dark"),
80              new AbstractMap.SimpleEntry<>(FlatMacLightLaf.class.getName(), "macOS"),
81              new AbstractMap.SimpleEntry<>(FlatMacDarkLaf.class.getName(), "macOS Dark"),
82              new AbstractMap.SimpleEntry<>(FlatMTGitHubIJTheme.class.getName(), "GitHub"),
83              new AbstractMap.SimpleEntry<>(FlatMTGitHubDarkIJTheme.class.getName(), "GitHub Dark"),
84              new AbstractMap.SimpleEntry<>(FlatHighContrastIJTheme.class.getName(), "High contrast")
85          ).forEach(entry -> {
86              JMenuItem item = new RadioItemNonClosing(
87                  new AbstractAction() {
88                      @Override
89                      public void actionPerformed(ActionEvent e) {
90                          AppMenubar.applyTheme(entry.getKey());
91                      }
92                  }
93              );
94              item.setText(entry.getValue());
95              item.setSelected(entry.getKey().equals(MediatorHelper.model().getMediatorUtils().preferencesUtil().getThemeFlatLafName()));
96              groupRadio.add(item);
97              menuThemes.add(item);
98          });
99  
100         this.add(itemNewWindows);
101         this.add(menuAppearance);
102         this.add(menuThemes);
103         this.add(new JSeparator());
104         this.add(this.initMenuTranslation());
105         this.add(new JSeparator());
106 
107         this.menuView = new JMenu(I18nUtil.valueByKey("MENUBAR_VIEW"));
108         I18nViewUtil.addComponentForKey("MENUBAR_VIEW", this.menuView);
109         this.menuView.setMnemonic('V');
110 
111         AtomicInteger accelerator = new AtomicInteger(0x31);
112         AtomicInteger tabPosition = new AtomicInteger();
113         MediatorHelper.frame().getTabManagers().getIconsTabs().forEach(entry -> {
114             var menuItem = new JMenuItem(I18nUtil.valueByKey(entry.getKeyLabel()), entry.getIcon());
115             I18nViewUtil.addComponentForKey(entry.getKeyLabel(), menuItem);
116             menuItem.setName(entry.getKeyLabel());  // required by card manager switch
117             this.menuView.add(menuItem);
118 
119             menuItem.setAccelerator(KeyStroke.getKeyStroke(
120                 KeyEvent.getExtendedKeyCodeForChar(accelerator.getAndIncrement()),
121                 InputEvent.CTRL_DOWN_MASK
122             ));
123 
124             final var position = tabPosition.get();  // required by closure
125             menuItem.addActionListener(actionEvent -> {  // setAction() could set action+text+icon but i18n not easy
126                 CardLayout cardLayout = (CardLayout) MediatorHelper.tabManagersCards().getLayout();
127                 cardLayout.show(MediatorHelper.tabManagersCards(), menuItem.getName());
128                 MediatorHelper.frame().getTabManagers().setSelectedIndex(position);
129             });
130             tabPosition.getAndIncrement();
131         });
132 
133         this.add(this.menuView);
134 
135         var menuPanel = new JMenu(I18nUtil.valueByKey("MENUBAR_PANEL"));
136         I18nViewUtil.addComponentForKey("MENUBAR_PANEL", menuPanel);
137         menuPanel.setMnemonic('C');
138 
139         Arrays.asList(
140             new ModelCheckboxMenu(
141                 "CONSOLE_CHUNK_LABEL",
142                 PreferencesUtil.CHUNK_VISIBLE,
143                 () -> MediatorHelper.panelConsoles().insertChunkTab(),
144                 UiUtil.CHUNK.getIcon()
145             ),
146             new ModelCheckboxMenu(
147                 "CONSOLE_BINARY_LABEL",
148                 PreferencesUtil.BINARY_VISIBLE,
149                 () -> MediatorHelper.panelConsoles().insertBooleanTab(),
150                 UiUtil.BINARY.getIcon()
151             ),
152             new ModelCheckboxMenu(
153                 "CONSOLE_NETWORK_LABEL",
154                 PreferencesUtil.NETWORK_VISIBLE,
155                 () -> MediatorHelper.panelConsoles().insertNetworkTab(),
156                 UiUtil.NETWORK.getIcon()
157             ),
158             new ModelCheckboxMenu(
159                 "CONSOLE_JAVA_LABEL",
160                 PreferencesUtil.JAVA_VISIBLE,
161                 () -> MediatorHelper.panelConsoles().insertJavaTab(),
162                 UiUtil.CUP.getIcon(),
163                 false
164             )
165         ).forEach(model -> {
166             var menuItem = new JCheckBoxMenuItem(
167                 I18nUtil.valueByKey(model.i18n),
168                 model.icon,
169                 model.isChecked
170             ) {
171                 @Override
172                 protected void processMouseEvent(MouseEvent e) {
173                     if (RadioItemNonClosing.shouldClose(e, this)) {
174                         super.processMouseEvent(e);
175                     }
176                 }
177             };
178             I18nViewUtil.addComponentForKey(model.i18n, menuItem);
179             menuPanel.add(menuItem);
180 
181             menuItem.addActionListener(actionEvent -> {
182                 if (menuItem.isSelected()) {
183                     model.runnableInsertTab.run();
184                 } else {
185                     MediatorHelper.tabConsoles().remove(MediatorHelper.tabConsoles().indexOfTab(model.icon));
186                 }
187             });
188         });
189 
190         this.add(menuPanel);
191         this.add(new JSeparator());
192         this.add(this.getMenuItemSqlEngine());
193         this.add(this.getMenuItemPreferences());
194     }
195 
196     private JMenuItem getMenuItemSqlEngine() {
197         var itemSqlEngine = new JMenuItem(I18nUtil.valueByKey(MenuWindows.I18N_SQL_ENGINE));
198         I18nViewUtil.addComponentForKey(MenuWindows.I18N_SQL_ENGINE, itemSqlEngine);
199         itemSqlEngine.setName("itemSqlEngine");
200         itemSqlEngine.setMnemonic('S');
201 
202         itemSqlEngine.addActionListener(actionEvent -> {
203             var titleTabSqlEngine = "SQL Engine";
204             for (var i = 0 ; i < MediatorHelper.tabResults().getTabCount() ; i++) {
205                 if (titleTabSqlEngine.equals(MediatorHelper.tabResults().getTitleAt(i))) {
206                     MediatorHelper.tabResults().setSelectedIndex(i);
207                     return;
208                 }
209             }
210 
211             MediatorHelper.frame().getSplitNS().initSplitOrientation();
212 
213             var panelSqlEngine = new SqlEngine();
214             MediatorHelper.tabResults().addTab(titleTabSqlEngine, panelSqlEngine);
215             MediatorHelper.tabResults().setSelectedComponent(panelSqlEngine);  // Focus on the new tab
216 
217             // Create a custom tab header
218             var header = new TabHeader(I18nViewUtil.valueByKey(MenuWindows.I18N_SQL_ENGINE), UiUtil.COG.getIcon());
219             I18nViewUtil.addComponentForKey(MenuWindows.I18N_SQL_ENGINE, header.getTabLabel());
220 
221             // Apply the custom header to the tab
222             MediatorHelper.tabResults().setTabComponentAt(MediatorHelper.tabResults().indexOfComponent(panelSqlEngine), header);
223             MediatorHelper.tabResults().updateUI();  // required: light, open/close prefs, dark => light artifacts
224         });
225 
226         return itemSqlEngine;
227     }
228 
229     private JMenuItem getMenuItemPreferences() {
230         JMenuItem itemPreferences = new JMenuItem(I18nUtil.valueByKey(MenuWindows.I18N_PREFERENCES), 'P');
231         I18nViewUtil.addComponentForKey(MenuWindows.I18N_PREFERENCES, itemPreferences);
232         itemPreferences.setName("itemPreferences");
233 
234         // Render the Preferences dialog behind the scene
235         var titleTabPreferences = "Preferences";
236 
237         itemPreferences.addActionListener(actionEvent -> {
238             for (var i = 0 ; i < MediatorHelper.tabResults().getTabCount() ; i++) {
239                 if (titleTabPreferences.equals(MediatorHelper.tabResults().getTitleAt(i))) {
240                     MediatorHelper.tabResults().setSelectedIndex(i);
241                     return;
242                 }
243             }
244 
245             MediatorHelper.frame().getSplitNS().initSplitOrientation();
246 
247             var panelPreferences = new PanelPreferences();
248             MediatorHelper.tabResults().addTab(titleTabPreferences, panelPreferences);
249             MediatorHelper.tabResults().setSelectedComponent(panelPreferences);  // Focus on the new tab
250 
251             // Create a custom tab header
252             var header = new TabHeader(I18nViewUtil.valueByKey(MenuWindows.I18N_PREFERENCES), UiUtil.COG.getIcon());
253             I18nViewUtil.addComponentForKey(MenuWindows.I18N_PREFERENCES, header.getTabLabel());
254 
255             // Apply the custom header to the tab
256             MediatorHelper.tabResults().setTabComponentAt(MediatorHelper.tabResults().indexOfComponent(panelPreferences), header);
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 -> {
305             modelItem.getMenuItem().setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
306             modelItem.getMenuItem().setName(MenuWindows.ITEM_ARABIC);
307         });
308 
309         return menuTranslation;
310     }
311 
312     public void switchLocaleFromPreferences() {
313         AppMenubar.ITEMS_TRANSLATE.stream().filter(model -> model.getLanguage().getLanguageTag().equals(
314             MediatorHelper.model().getMediatorUtils().preferencesUtil().getLanguageTag()
315         ))
316         .forEach(modelItem -> {
317             modelItem.getMenuItem().setActionCommand(MenuWindows.ACTION_STARTING_APP);
318             modelItem.getMenuItem().doClick();
319         });
320     }
321 
322 
323     // Getter and setter
324 
325     public JMenu getMenuView() {
326         return this.menuView;
327     }
328 }