View Javadoc
1   /*******************************************************************************
2    * Copyhacked (H) 2012-2025.
3    * This program and the accompanying materials
4    * are made available under no term at all, use it like
5    * you want, but share and discuss it
6    * every time possible with every body.
7    * 
8    * Contributors:
9    *      ron190 at ymail dot com - initial implementation
10   ******************************************************************************/
11  package com.jsql.view.swing.list;
12  
13  import com.jsql.util.I18nUtil;
14  import com.jsql.util.LogLevelUtil;
15  import com.jsql.view.swing.util.I18nViewUtil;
16  import com.jsql.view.swing.util.MediatorHelper;
17  import org.apache.logging.log4j.LogManager;
18  import org.apache.logging.log4j.Logger;
19  
20  import javax.swing.*;
21  import java.awt.*;
22  import java.awt.event.*;
23  import java.util.AbstractMap.SimpleEntry;
24  import java.util.Arrays;
25  import java.util.stream.Stream;
26  
27  /**
28   * A Mouse action to display a popupmenu on a JList.
29   */
30  public class MouseAdapterMenuAction extends MouseAdapter {
31      
32      private static final Logger LOGGER = LogManager.getRootLogger();
33      
34      /**
35       * JList to add popupmenu.
36       */
37      private final DnDList dndList;
38      
39      /**
40       * Create a popup menu for current JList item.
41       * @param dndList List with action
42       */
43      public MouseAdapterMenuAction(DnDList dndList) {
44          this.dndList = dndList;
45      }
46      
47      /**
48       * Displays a popup menu for JList.
49       * @param mouseEvent Mouse event
50       */
51      @SuppressWarnings("unchecked")
52      public void showPopup(final MouseEvent mouseEvent) {
53          if (mouseEvent.isPopupTrigger()) {
54              JList<ItemList> list = (JList<ItemList>) mouseEvent.getSource();
55  
56              JPopupMenu popupMenuList = this.initMenu(mouseEvent);
57              popupMenuList.applyComponentOrientation(ComponentOrientation.getOrientation(I18nUtil.getCurrentLocale()));
58              // Fix #26274: IllegalComponentStateException on show()
59              try {
60                  popupMenuList.show(
61                      list,
62                      ComponentOrientation.RIGHT_TO_LEFT.equals(ComponentOrientation.getOrientation(I18nUtil.getCurrentLocale()))
63                      ? mouseEvent.getX() - popupMenuList.getWidth()
64                      : mouseEvent.getX(),
65                      mouseEvent.getY()
66                  );
67              } catch (IllegalComponentStateException e) {
68                  LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
69              }
70              
71              popupMenuList.setLocation(
72                  ComponentOrientation.RIGHT_TO_LEFT.equals(ComponentOrientation.getOrientation(I18nUtil.getCurrentLocale()))
73                  ? mouseEvent.getXOnScreen() - popupMenuList.getWidth()
74                  : mouseEvent.getXOnScreen(),
75                  mouseEvent.getYOnScreen()
76              );
77          }
78      }
79  
80      private JPopupMenu initMenu(final MouseEvent mouseEvent) {
81          var popupMenuList = new JPopupMenu();
82          
83          boolean isNonUbuntu = I18nViewUtil.isNonUbuntu(I18nUtil.getCurrentLocale());
84          
85          JMenuItem menuImport = new JMenuItem();
86          JMenuItem menuExport = new JMenuItem();
87          JMenuItem menuCut = new JMenuItem();
88          JMenuItem menuCopy = new JMenuItem();
89          JMenuItem menuPaste = new JMenuItem();
90          JMenuItem menuDelete = new JMenuItem();
91          JMenuItem menuNew = new JMenuItem();
92          JMenuItem menuRestoreDefault = new JMenuItem();
93          JMenuItem menuSelectAll = new JMenuItem();
94          
95          Stream.of(
96              new SimpleEntry<>(menuImport, "LIST_IMPORT_CONFIRM_TITLE"),
97              new SimpleEntry<>(menuExport, "LIST_EXPORT_TITLE"),
98              new SimpleEntry<>(menuCut, "LIST_CUT"),
99              new SimpleEntry<>(menuCopy, "CONTEXT_MENU_COPY"),
100             new SimpleEntry<>(menuPaste, "LIST_PASTE"),
101             new SimpleEntry<>(menuDelete, "LIST_DELETE"),
102             new SimpleEntry<>(menuNew, "LIST_NEW_VALUE"),
103             new SimpleEntry<>(menuRestoreDefault, "LIST_RESTORE_DEFAULT"),
104             new SimpleEntry<>(menuSelectAll, "CONTEXT_MENU_SELECT_ALL")
105         )
106         .forEach(entry -> {
107             entry.getKey().setText(
108                 isNonUbuntu
109                 ? I18nViewUtil.valueByKey(entry.getValue())
110                 : I18nUtil.valueByKey(entry.getValue())
111             );
112             entry.getKey().setName(entry.getValue());
113             I18nViewUtil.addComponentForKey(entry.getValue(), entry.getKey());
114         });
115 
116         menuCut.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.CTRL_DOWN_MASK));
117         menuCopy.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_DOWN_MASK));
118         menuPaste.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_DOWN_MASK));
119         menuSelectAll.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.CTRL_DOWN_MASK));
120         
121         final var importFileDialog = new JFileChooser(MediatorHelper.model().getMediatorUtils().getPreferencesUtil().getPathFile());
122         importFileDialog.setDialogTitle(I18nUtil.valueByKey("LIST_IMPORT_CONFIRM_TITLE"));
123         importFileDialog.setMultiSelectionEnabled(true);
124 
125         menuNew.addActionListener(new MenuActionNewValue(this.dndList));
126 
127         menuImport.addActionListener(actionEvent -> {
128             var choice = 0;
129             // Fix #1896: NullPointerException on showOpenDialog()
130             // Fix #42831: ClassCastException on showOpenDialog()
131             try {
132                 choice = importFileDialog.showOpenDialog(this.dndList.getTopLevelAncestor());
133             } catch (ClassCastException | NullPointerException e) {
134                 LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
135             }
136             if (choice == JFileChooser.APPROVE_OPTION) {
137                 this.dndList.dropPasteFile(
138                     Arrays.asList(importFileDialog.getSelectedFiles()),
139                     this.dndList.locationToIndex(mouseEvent.getPoint())
140                 );
141             }
142         });
143 
144         menuCopy.addActionListener(actionEvent -> {
145             var action = this.dndList.getActionMap().get(TransferHandler.getCopyAction().getValue(Action.NAME));
146             if (action != null) {
147                 action.actionPerformed(
148                     new ActionEvent(this.dndList, ActionEvent.ACTION_PERFORMED, null)
149                 );
150             }
151         });
152 
153         menuCut.addActionListener(actionEvent -> {
154             var action = this.dndList.getActionMap().get(TransferHandler.getCutAction().getValue(Action.NAME));
155             if (action != null) {
156                 action.actionPerformed(
157                     new ActionEvent(this.dndList, ActionEvent.ACTION_PERFORMED, null)
158                 );
159             }
160         });
161 
162         menuPaste.addActionListener(actionEvent -> {
163             var action = this.dndList.getActionMap().get(TransferHandler.getPasteAction().getValue(Action.NAME));
164             if (action != null) {
165                 action.actionPerformed(
166                     new ActionEvent(this.dndList, ActionEvent.ACTION_PERFORMED, null)
167                 );
168             }
169         });
170 
171         menuDelete.addActionListener(actionEvent -> this.dndList.removeSelectedItem());
172         menuExport.addActionListener(new MenuActionExport(this.dndList));
173         menuRestoreDefault.addActionListener(actionEvent -> this.dndList.restore());
174         menuSelectAll.addActionListener(actionEvent -> {
175             var start = 0;
176             int end = this.dndList.getModel().getSize() - 1;
177             if (end >= 0) {
178                 this.dndList.setSelectionInterval(start, end);
179             }
180         });
181 
182         popupMenuList.add(menuNew);
183         popupMenuList.add(new JSeparator());
184         popupMenuList.add(menuCut);
185         popupMenuList.add(menuCopy);
186         popupMenuList.add(menuPaste);
187         popupMenuList.add(menuDelete);
188         popupMenuList.add(new JSeparator());
189         popupMenuList.add(menuSelectAll);
190         popupMenuList.add(new JSeparator());
191         popupMenuList.add(menuImport);
192         popupMenuList.add(menuExport);
193         popupMenuList.add(new JSeparator());
194         popupMenuList.add(menuRestoreDefault);
195         return popupMenuList;
196     }
197 
198     @Override
199     public void mousePressed(MouseEvent e) {
200         if (SwingUtilities.isRightMouseButton(e)) {
201             int clickIndex = this.dndList.locationToIndex(e.getPoint());
202             var containsIndex = false;
203             for (int currentIndex: this.dndList.getSelectedIndices()) {
204                 if (currentIndex == clickIndex) {
205                     containsIndex = true;
206                     break;
207                 }
208             }
209             if (!containsIndex) {
210                 this.dndList.setSelectedIndex(clickIndex);
211             }
212         }
213         this.showPopup(e);
214     }
215 
216     @Override
217     public void mouseReleased(MouseEvent e) {
218         this.showPopup(e);
219     }
220 }