HotkeyUtil.java

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.action;
12
13
import com.jsql.view.swing.menubar.AppMenubar;
14
import com.jsql.view.swing.util.MediatorHelper;
15
16
import javax.swing.*;
17
import java.awt.*;
18
import java.awt.event.ActionEvent;
19
import java.util.HashSet;
20
import java.util.Set;
21
22
/**
23
 * Keyword shortcut definition. <br>
24
 * - ctrl TAB: switch to next tab, <br>
25
 * - ctrl shift TAB: switch to previous tab, <br>
26
 * - ctrl W: delete tab
27
 */
28
public final class HotkeyUtil {
29
    
30
    private static final String STR_CTRL_TAB = "ctrl TAB";
31
    private static final String STR_CTRL_SHIFT_TAB = "ctrl shift TAB";
32
    private static final String STR_SELECT_TAB = "actionString-selectTab";
33
    
34
    private HotkeyUtil() {
35
        // Utility class
36
    }
37
    
38
    /**
39
     * Select all textfield content when focused.
40
     */
41
    public static void addTextFieldShortcutSelectAll() {
42 1 1. addTextFieldShortcutSelectAll : removed call to java/awt/KeyboardFocusManager::addPropertyChangeListener → NO_COVERAGE
        KeyboardFocusManager.getCurrentKeyboardFocusManager().addPropertyChangeListener(
43
            "permanentFocusOwner",
44
            propertyChangeEvent -> {
45 1 1. lambda$addTextFieldShortcutSelectAll$1 : negated conditional → NO_COVERAGE
                if (propertyChangeEvent.getNewValue() instanceof JTextField) {
46 1 1. lambda$addTextFieldShortcutSelectAll$1 : removed call to javax/swing/SwingUtilities::invokeLater → NO_COVERAGE
                    SwingUtilities.invokeLater(() -> {
47
                        JTextField textField = (JTextField) propertyChangeEvent.getNewValue();
48 1 1. lambda$addTextFieldShortcutSelectAll$0 : removed call to javax/swing/JTextField::selectAll → NO_COVERAGE
                        textField.selectAll();
49
                    });
50
                }
51
            }
52
        );
53
    }
54
    
55
    /**
56
     * Add action to a single tabbedpane (ctrl-tab, ctrl-shift-tab).
57
     */
58
    public static void addShortcut(JTabbedPane tabbedPane) {
59
        var ctrlTab = KeyStroke.getKeyStroke(HotkeyUtil.STR_CTRL_TAB);
60
        var ctrlShiftTab = KeyStroke.getKeyStroke(HotkeyUtil.STR_CTRL_SHIFT_TAB);
61
62
        // Remove ctrl-tab from default focus traversal
63
        Set<AWTKeyStroke> forwardKeys = new HashSet<>(tabbedPane.getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS));
64
        forwardKeys.remove(ctrlTab);
65 1 1. addShortcut : removed call to javax/swing/JTabbedPane::setFocusTraversalKeys → NO_COVERAGE
        tabbedPane.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, forwardKeys);
66
67
        // Remove ctrl-shift-tab from default focus traversal
68
        Set<AWTKeyStroke> backwardKeys = new HashSet<>(tabbedPane.getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS));
69
        backwardKeys.remove(ctrlShiftTab);
70 1 1. addShortcut : removed call to javax/swing/JTabbedPane::setFocusTraversalKeys → NO_COVERAGE
        tabbedPane.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, backwardKeys);
71
72
        // Add keys to the tab's input map
73
        var inputMap = tabbedPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
74 1 1. addShortcut : removed call to javax/swing/InputMap::put → NO_COVERAGE
        inputMap.put(ctrlTab, "navigateNext");
75 1 1. addShortcut : removed call to javax/swing/InputMap::put → NO_COVERAGE
        inputMap.put(ctrlShiftTab, "navigatePrevious");
76
    }
77
    
78
    /**
79
     * Add action to global root (ctrl-tab, ctrl-shift-tab, ctrl-W).
80
     */
81
    public static void addShortcut(JRootPane rootPane, final JTabbedPane valuesTabbedPane) {
82
        Action closeTab = new ActionCloseTabResult();
83
        Action nextTab = new AbstractAction() {
84
            @Override
85
            public void actionPerformed(ActionEvent e) {
86 2 1. actionPerformed : changed conditional boundary → NO_COVERAGE
2. actionPerformed : negated conditional → NO_COVERAGE
                if (valuesTabbedPane.getTabCount() > 0) {
87
                    int selectedIndex = valuesTabbedPane.getSelectedIndex();
88 3 1. actionPerformed : Replaced integer addition with subtraction → NO_COVERAGE
2. actionPerformed : changed conditional boundary → NO_COVERAGE
3. actionPerformed : negated conditional → NO_COVERAGE
                    if (selectedIndex + 1 < valuesTabbedPane.getTabCount()) {
89 2 1. actionPerformed : Replaced integer addition with subtraction → NO_COVERAGE
2. actionPerformed : removed call to javax/swing/JTabbedPane::setSelectedIndex → NO_COVERAGE
                        valuesTabbedPane.setSelectedIndex(selectedIndex + 1);
90
                    } else {
91 1 1. actionPerformed : removed call to javax/swing/JTabbedPane::setSelectedIndex → NO_COVERAGE
                        valuesTabbedPane.setSelectedIndex(0);
92
                    }
93
                }
94
            }
95
        };
96
        Action previousTab = new AbstractAction() {
97
            @Override
98
            public void actionPerformed(ActionEvent e) {
99 2 1. actionPerformed : changed conditional boundary → NO_COVERAGE
2. actionPerformed : negated conditional → NO_COVERAGE
                if (valuesTabbedPane.getTabCount() > 0) {
100
                    int selectedIndex = valuesTabbedPane.getSelectedIndex();
101 3 1. actionPerformed : Replaced integer subtraction with addition → NO_COVERAGE
2. actionPerformed : changed conditional boundary → NO_COVERAGE
3. actionPerformed : negated conditional → NO_COVERAGE
                    if (selectedIndex - 1 > -1) {
102 2 1. actionPerformed : removed call to javax/swing/JTabbedPane::setSelectedIndex → NO_COVERAGE
2. actionPerformed : Replaced integer subtraction with addition → NO_COVERAGE
                        valuesTabbedPane.setSelectedIndex(selectedIndex - 1);
103
                    } else {
104 2 1. actionPerformed : Replaced integer subtraction with addition → NO_COVERAGE
2. actionPerformed : removed call to javax/swing/JTabbedPane::setSelectedIndex → NO_COVERAGE
                        valuesTabbedPane.setSelectedIndex(valuesTabbedPane.getTabCount() - 1);
105
                    }
106
                }
107
            }
108
        };
109
        
110
        Set<AWTKeyStroke> forwardKeys = new HashSet<>(rootPane.getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS));
111
        forwardKeys.remove(KeyStroke.getKeyStroke(HotkeyUtil.STR_CTRL_TAB));
112 1 1. addShortcut : removed call to javax/swing/JRootPane::setFocusTraversalKeys → NO_COVERAGE
        rootPane.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, forwardKeys);
113
        
114
        Set<AWTKeyStroke> backwardKeys = new HashSet<>(rootPane.getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS));
115
        backwardKeys.remove(KeyStroke.getKeyStroke(HotkeyUtil.STR_CTRL_SHIFT_TAB));
116 1 1. addShortcut : removed call to javax/swing/JRootPane::setFocusTraversalKeys → NO_COVERAGE
        rootPane.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, backwardKeys);
117
        
118
        var inputMap = rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
119
        var actionMap = rootPane.getActionMap();
120
121 1 1. addShortcut : removed call to javax/swing/InputMap::put → NO_COVERAGE
        inputMap.put(KeyStroke.getKeyStroke("ctrl W"), "actionString-closeTab");
122 1 1. addShortcut : removed call to javax/swing/ActionMap::put → NO_COVERAGE
        actionMap.put("actionString-closeTab", closeTab);
123
        
124 1 1. addShortcut : removed call to javax/swing/InputMap::put → NO_COVERAGE
        inputMap.put(KeyStroke.getKeyStroke(HotkeyUtil.STR_CTRL_TAB), "actionString-nextTab");
125 1 1. addShortcut : removed call to javax/swing/ActionMap::put → NO_COVERAGE
        actionMap.put("actionString-nextTab", nextTab);
126
127 1 1. addShortcut : removed call to javax/swing/InputMap::put → NO_COVERAGE
        inputMap.put(KeyStroke.getKeyStroke(HotkeyUtil.STR_CTRL_SHIFT_TAB), "actionString-previousTab");
128 1 1. addShortcut : removed call to javax/swing/ActionMap::put → NO_COVERAGE
        actionMap.put("actionString-previousTab", previousTab);
129
130
        int tabCount = MediatorHelper.tabManagersCards().getComponentCount();
131
        
132 2 1. addShortcut : changed conditional boundary → NO_COVERAGE
2. addShortcut : negated conditional → NO_COVERAGE
        for (var currentTab = 1 ; currentTab <= tabCount ; currentTab++) {
133 1 1. addShortcut : removed call to javax/swing/InputMap::put → NO_COVERAGE
            inputMap.put(KeyStroke.getKeyStroke("ctrl "+ currentTab), HotkeyUtil.STR_SELECT_TAB + currentTab);
134 1 1. addShortcut : removed call to javax/swing/InputMap::put → NO_COVERAGE
            inputMap.put(KeyStroke.getKeyStroke("ctrl NUMPAD"+ currentTab), HotkeyUtil.STR_SELECT_TAB + currentTab);
135
            
136
            final int currentTabFinal = currentTab;
137 1 1. addShortcut : removed call to javax/swing/ActionMap::put → NO_COVERAGE
            actionMap.put(HotkeyUtil.STR_SELECT_TAB + currentTab, new AbstractAction() {
138
                @Override
139
                public void actionPerformed(ActionEvent e) {
140 2 1. actionPerformed : Replaced integer subtraction with addition → NO_COVERAGE
2. actionPerformed : removed call to com/jsql/view/swing/tab/TabManagers::setSelectedIndex → NO_COVERAGE
                    MediatorHelper.frame().getTabManagers().setSelectedIndex(currentTabFinal - 1);
141
                }
142
            });
143
        }
144
        
145 1 1. addShortcut : removed call to javax/swing/InputMap::put → NO_COVERAGE
        inputMap.put(KeyStroke.getKeyStroke("ctrl S"), "actionString-saveTab");
146 1 1. addShortcut : removed call to javax/swing/ActionMap::put → NO_COVERAGE
        actionMap.put("actionString-saveTab", new ActionSaveTab());
147
    }
148
149
    /**
150
     * Create Alt shortcut to display menubar ; remove menubar when focus is set to a component.
151
     * @param appMenubar The menubar to display
152
     */
153
    public static void addShortcut(final AppMenubar appMenubar) {
154 1 1. addShortcut : removed call to java/awt/KeyboardFocusManager::addPropertyChangeListener → NO_COVERAGE
        KeyboardFocusManager.getCurrentKeyboardFocusManager().addPropertyChangeListener(  // Hide Menubar when focusing any component
155
            "permanentFocusOwner",
156 1 1. lambda$addShortcut$3 : removed call to javax/swing/SwingUtilities::invokeLater → NO_COVERAGE
            propertyChangeEvent -> SwingUtilities.invokeLater(() -> {
157
                if (
158
                    // Fix #40924: NullPointerException on MediatorGui.panelAddressBar()
159 1 1. lambda$addShortcut$2 : negated conditional → NO_COVERAGE
                    MediatorHelper.panelAddressBar() != null
160 1 1. lambda$addShortcut$2 : negated conditional → NO_COVERAGE
                    && MediatorHelper.panelAddressBar().isAdvanceActivated()
161
                ) {
162 1 1. lambda$addShortcut$2 : removed call to com/jsql/view/swing/menubar/AppMenubar::setVisible → NO_COVERAGE
                    appMenubar.setVisible(false);
163
                }
164
            })
165
        );
166 1 1. addShortcut : removed call to java/awt/KeyboardFocusManager::addKeyEventDispatcher → NO_COVERAGE
        KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(  // Show/Hide the Menubar with Alt key (not Alt Graph)
167
            new AltKeyEventDispatcher()
168
        );
169
    }
170
}

Mutations

42

1.1
Location : addTextFieldShortcutSelectAll
Killed by : none
removed call to java/awt/KeyboardFocusManager::addPropertyChangeListener → NO_COVERAGE

45

1.1
Location : lambda$addTextFieldShortcutSelectAll$1
Killed by : none
negated conditional → NO_COVERAGE

46

1.1
Location : lambda$addTextFieldShortcutSelectAll$1
Killed by : none
removed call to javax/swing/SwingUtilities::invokeLater → NO_COVERAGE

48

1.1
Location : lambda$addTextFieldShortcutSelectAll$0
Killed by : none
removed call to javax/swing/JTextField::selectAll → NO_COVERAGE

65

1.1
Location : addShortcut
Killed by : none
removed call to javax/swing/JTabbedPane::setFocusTraversalKeys → NO_COVERAGE

70

1.1
Location : addShortcut
Killed by : none
removed call to javax/swing/JTabbedPane::setFocusTraversalKeys → NO_COVERAGE

74

1.1
Location : addShortcut
Killed by : none
removed call to javax/swing/InputMap::put → NO_COVERAGE

75

1.1
Location : addShortcut
Killed by : none
removed call to javax/swing/InputMap::put → NO_COVERAGE

86

1.1
Location : actionPerformed
Killed by : none
changed conditional boundary → NO_COVERAGE

2.2
Location : actionPerformed
Killed by : none
negated conditional → NO_COVERAGE

88

1.1
Location : actionPerformed
Killed by : none
Replaced integer addition with subtraction → NO_COVERAGE

2.2
Location : actionPerformed
Killed by : none
changed conditional boundary → NO_COVERAGE

3.3
Location : actionPerformed
Killed by : none
negated conditional → NO_COVERAGE

89

1.1
Location : actionPerformed
Killed by : none
Replaced integer addition with subtraction → NO_COVERAGE

2.2
Location : actionPerformed
Killed by : none
removed call to javax/swing/JTabbedPane::setSelectedIndex → NO_COVERAGE

91

1.1
Location : actionPerformed
Killed by : none
removed call to javax/swing/JTabbedPane::setSelectedIndex → NO_COVERAGE

99

1.1
Location : actionPerformed
Killed by : none
changed conditional boundary → NO_COVERAGE

2.2
Location : actionPerformed
Killed by : none
negated conditional → NO_COVERAGE

101

1.1
Location : actionPerformed
Killed by : none
Replaced integer subtraction with addition → NO_COVERAGE

2.2
Location : actionPerformed
Killed by : none
changed conditional boundary → NO_COVERAGE

3.3
Location : actionPerformed
Killed by : none
negated conditional → NO_COVERAGE

102

1.1
Location : actionPerformed
Killed by : none
removed call to javax/swing/JTabbedPane::setSelectedIndex → NO_COVERAGE

2.2
Location : actionPerformed
Killed by : none
Replaced integer subtraction with addition → NO_COVERAGE

104

1.1
Location : actionPerformed
Killed by : none
Replaced integer subtraction with addition → NO_COVERAGE

2.2
Location : actionPerformed
Killed by : none
removed call to javax/swing/JTabbedPane::setSelectedIndex → NO_COVERAGE

112

1.1
Location : addShortcut
Killed by : none
removed call to javax/swing/JRootPane::setFocusTraversalKeys → NO_COVERAGE

116

1.1
Location : addShortcut
Killed by : none
removed call to javax/swing/JRootPane::setFocusTraversalKeys → NO_COVERAGE

121

1.1
Location : addShortcut
Killed by : none
removed call to javax/swing/InputMap::put → NO_COVERAGE

122

1.1
Location : addShortcut
Killed by : none
removed call to javax/swing/ActionMap::put → NO_COVERAGE

124

1.1
Location : addShortcut
Killed by : none
removed call to javax/swing/InputMap::put → NO_COVERAGE

125

1.1
Location : addShortcut
Killed by : none
removed call to javax/swing/ActionMap::put → NO_COVERAGE

127

1.1
Location : addShortcut
Killed by : none
removed call to javax/swing/InputMap::put → NO_COVERAGE

128

1.1
Location : addShortcut
Killed by : none
removed call to javax/swing/ActionMap::put → NO_COVERAGE

132

1.1
Location : addShortcut
Killed by : none
changed conditional boundary → NO_COVERAGE

2.2
Location : addShortcut
Killed by : none
negated conditional → NO_COVERAGE

133

1.1
Location : addShortcut
Killed by : none
removed call to javax/swing/InputMap::put → NO_COVERAGE

134

1.1
Location : addShortcut
Killed by : none
removed call to javax/swing/InputMap::put → NO_COVERAGE

137

1.1
Location : addShortcut
Killed by : none
removed call to javax/swing/ActionMap::put → NO_COVERAGE

140

1.1
Location : actionPerformed
Killed by : none
Replaced integer subtraction with addition → NO_COVERAGE

2.2
Location : actionPerformed
Killed by : none
removed call to com/jsql/view/swing/tab/TabManagers::setSelectedIndex → NO_COVERAGE

145

1.1
Location : addShortcut
Killed by : none
removed call to javax/swing/InputMap::put → NO_COVERAGE

146

1.1
Location : addShortcut
Killed by : none
removed call to javax/swing/ActionMap::put → NO_COVERAGE

154

1.1
Location : addShortcut
Killed by : none
removed call to java/awt/KeyboardFocusManager::addPropertyChangeListener → NO_COVERAGE

156

1.1
Location : lambda$addShortcut$3
Killed by : none
removed call to javax/swing/SwingUtilities::invokeLater → NO_COVERAGE

159

1.1
Location : lambda$addShortcut$2
Killed by : none
negated conditional → NO_COVERAGE

160

1.1
Location : lambda$addShortcut$2
Killed by : none
negated conditional → NO_COVERAGE

162

1.1
Location : lambda$addShortcut$2
Killed by : none
removed call to com/jsql/view/swing/menubar/AppMenubar::setVisible → NO_COVERAGE

166

1.1
Location : addShortcut
Killed by : none
removed call to java/awt/KeyboardFocusManager::addKeyEventDispatcher → NO_COVERAGE

Active mutators

Tests examined


Report generated by PIT 1.19.1