JPopupTextComponent.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.text;
12
13
import com.jsql.util.LogLevelUtil;
14
import com.jsql.view.swing.popupmenu.JPopupMenuText;
15
import com.jsql.view.swing.text.action.SilentDeleteTextAction;
16
import org.apache.logging.log4j.LogManager;
17
import org.apache.logging.log4j.Logger;
18
19
import javax.swing.*;
20
import javax.swing.text.DefaultEditorKit;
21
import javax.swing.text.JTextComponent;
22
import javax.swing.undo.CannotRedoException;
23
import javax.swing.undo.CannotUndoException;
24
import javax.swing.undo.CompoundEdit;
25
import javax.swing.undo.UndoManager;
26
import java.awt.event.ActionEvent;
27
28
/**
29
 * A swing JTextComponent with Undo/Redo functionality.
30
 * @param <T> Component like JTextField or JTextArea to decorate
31
 */
32
public class JPopupTextComponent<T extends JTextComponent> extends JPopupComponent<T> implements DecoratorJComponent<T> {
33
    
34
    private static final Logger LOGGER = LogManager.getRootLogger();
35
36
    /**
37
     * Save the component to decorate, add the Undo/Redo.
38
     * @param proxy Swing component to decorate
39
     */
40
    public JPopupTextComponent(final T proxy) {
41
        super(proxy);
42
43 1 1. <init> : removed call to javax/swing/text/JTextComponent::setComponentPopupMenu → NO_COVERAGE
        this.getProxy().setComponentPopupMenu(new JPopupMenuText(this.getProxy()));
44 1 1. <init> : removed call to javax/swing/text/JTextComponent::setDragEnabled → NO_COVERAGE
        this.getProxy().setDragEnabled(true);
45
46
        var undoRedoManager = new UndoManager();
47
48
        // Time-based grouping for words undo/redo instead of chars
49
        final CompoundEdit[] currentEdit = {new CompoundEdit()};
50
        Timer commitTimer = new Timer(500, e -> {
51 1 1. lambda$new$0 : removed call to javax/swing/undo/CompoundEdit::end → NO_COVERAGE
            currentEdit[0].end();
52
            undoRedoManager.addEdit(currentEdit[0]);
53
            currentEdit[0] = new CompoundEdit();
54
        });
55 1 1. <init> : removed call to javax/swing/Timer::setRepeats → NO_COVERAGE
        commitTimer.setRepeats(false);
56
57
        // Listen for undo and redo events
58
        var doc = this.getProxy().getDocument();
59 1 1. <init> : removed call to javax/swing/text/Document::addUndoableEditListener → NO_COVERAGE
        doc.addUndoableEditListener(e -> {
60
            currentEdit[0].addEdit(e.getEdit());
61 1 1. lambda$new$1 : removed call to javax/swing/Timer::restart → NO_COVERAGE
            commitTimer.restart();
62
        });
63
64 1 1. <init> : removed call to com/jsql/view/swing/text/JPopupTextComponent::initUndo → NO_COVERAGE
        this.initUndo(undoRedoManager);
65 1 1. <init> : removed call to com/jsql/view/swing/text/JPopupTextComponent::initRedo → NO_COVERAGE
        this.initRedo(undoRedoManager);
66 1 1. <init> : removed call to com/jsql/view/swing/text/JPopupTextComponent::makeDeleteSilent → NO_COVERAGE
        this.makeDeleteSilent();
67
    }
68
69
    private void initUndo(final UndoManager undo) {
70
        final var undoIdentifier = "Undo";  // Create an undo action and add it to the text component
71
        
72 1 1. initUndo : removed call to javax/swing/ActionMap::put → NO_COVERAGE
        this.getProxy().getActionMap().put(undoIdentifier, new AbstractAction(undoIdentifier) {
73
            @Override
74
            public void actionPerformed(ActionEvent evt) {
75
                // Unhandled ArrayIndexOutOfBoundsException #92146 on undo()
76
                try {
77 1 1. actionPerformed : negated conditional → NO_COVERAGE
                    if (undo.canUndo()) {
78 1 1. actionPerformed : removed call to javax/swing/undo/UndoManager::undo → NO_COVERAGE
                        undo.undo();
79
                    }
80
                } catch (ArrayIndexOutOfBoundsException | CannotUndoException e) {
81
                    LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
82
                }
83
            }
84
       });
85
86
        // Bind the undo action to ctl-Z
87 1 1. initUndo : removed call to javax/swing/InputMap::put → NO_COVERAGE
        this.getProxy().getInputMap().put(KeyStroke.getKeyStroke("control Z"), undoIdentifier);
88
    }
89
90
    private void initRedo(final UndoManager undo) {
91
        final var redoIdentifier = "Redo";  // Create a redo action and add it to the text component
92
        
93 1 1. initRedo : removed call to javax/swing/ActionMap::put → NO_COVERAGE
        this.getProxy().getActionMap().put(redoIdentifier, new AbstractAction(redoIdentifier) {
94
            @Override
95
            public void actionPerformed(ActionEvent evt) {
96
                try {
97 1 1. actionPerformed : negated conditional → NO_COVERAGE
                    if (undo.canRedo()) {
98 1 1. actionPerformed : removed call to javax/swing/undo/UndoManager::redo → NO_COVERAGE
                        undo.redo();
99
                    }
100
                } catch (CannotRedoException e) {
101
                    LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
102
                }
103
            }
104
        });
105
106
        // Bind the redo action to ctl-Y
107 1 1. initRedo : removed call to javax/swing/InputMap::put → NO_COVERAGE
        this.getProxy().getInputMap().put(KeyStroke.getKeyStroke("control Y"), redoIdentifier);
108
    }
109
110
    private void makeDeleteSilent() {
111
        var actionMap = this.getProxy().getActionMap();  // Silent delete
112
113
        String key = DefaultEditorKit.deletePrevCharAction;
114 1 1. makeDeleteSilent : removed call to javax/swing/ActionMap::put → NO_COVERAGE
        actionMap.put(key, new SilentDeleteTextAction(key, actionMap.get(key)));
115
116
        key = DefaultEditorKit.deleteNextCharAction;
117 1 1. makeDeleteSilent : removed call to javax/swing/ActionMap::put → NO_COVERAGE
        actionMap.put(key, new SilentDeleteTextAction(key, actionMap.get(key)));
118
    }
119
}

Mutations

43

1.1
Location : <init>
Killed by : none
removed call to javax/swing/text/JTextComponent::setComponentPopupMenu → NO_COVERAGE

44

1.1
Location : <init>
Killed by : none
removed call to javax/swing/text/JTextComponent::setDragEnabled → NO_COVERAGE

51

1.1
Location : lambda$new$0
Killed by : none
removed call to javax/swing/undo/CompoundEdit::end → NO_COVERAGE

55

1.1
Location : <init>
Killed by : none
removed call to javax/swing/Timer::setRepeats → NO_COVERAGE

59

1.1
Location : <init>
Killed by : none
removed call to javax/swing/text/Document::addUndoableEditListener → NO_COVERAGE

61

1.1
Location : lambda$new$1
Killed by : none
removed call to javax/swing/Timer::restart → NO_COVERAGE

64

1.1
Location : <init>
Killed by : none
removed call to com/jsql/view/swing/text/JPopupTextComponent::initUndo → NO_COVERAGE

65

1.1
Location : <init>
Killed by : none
removed call to com/jsql/view/swing/text/JPopupTextComponent::initRedo → NO_COVERAGE

66

1.1
Location : <init>
Killed by : none
removed call to com/jsql/view/swing/text/JPopupTextComponent::makeDeleteSilent → NO_COVERAGE

72

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

77

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

78

1.1
Location : actionPerformed
Killed by : none
removed call to javax/swing/undo/UndoManager::undo → NO_COVERAGE

87

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

93

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

97

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

98

1.1
Location : actionPerformed
Killed by : none
removed call to javax/swing/undo/UndoManager::redo → NO_COVERAGE

107

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

114

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

117

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

Active mutators

Tests examined


Report generated by PIT 1.22.1