CreateAdminPageTab.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.interaction;
12
13
import com.jsql.util.I18nUtil;
14
import com.jsql.util.LogLevelUtil;
15
import com.jsql.view.interaction.InteractionCommand;
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.UiUtil;
20
import org.apache.commons.lang3.StringUtils;
21
import org.apache.logging.log4j.LogManager;
22
import org.apache.logging.log4j.Logger;
23
import org.jsoup.Jsoup;
24
import org.jsoup.safety.Safelist;
25
26
import javax.swing.*;
27
import javax.swing.text.DefaultEditorKit;
28
import java.awt.*;
29
import java.awt.datatransfer.StringSelection;
30
import java.awt.event.*;
31
import java.io.IOException;
32
import java.util.EmptyStackException;
33
34
/**
35
 * Create a new tab for an administration webpage.
36
 */
37
public class CreateAdminPageTab extends CreateTabHelper implements InteractionCommand {
38
    
39
    private static final Logger LOGGER = LogManager.getRootLogger();
40
41
    /**
42
     * Url for the administration webpage.
43
     */
44
    private final String url;
45
46
    /**
47
     * @param interactionParams Url of the webpage
48
     */
49
    public CreateAdminPageTab(Object[] interactionParams) {
50
        this.url = (String) interactionParams[0];
51
    }
52
53
    @Override
54
    public void execute() {
55
        String htmlSource = StringUtils.EMPTY;
56
        
57
        // Fix #4081: SocketTimeoutException on get()
58
        // Fix #44642: NoClassDefFoundError on get()
59
        // Fix #44641: ExceptionInInitializerError on get()
60
        try {
61
            // Previous test for 2xx Success and 3xx Redirection was Header only,
62
            // now get the HTML content.
63
            // Proxy is used by jsoup
64
            htmlSource = Jsoup.clean(
65
                Jsoup.connect(this.url)
66
                    // Prevent exception on UnsupportedMimeTypeException: Unhandled content type. Must be text/*, application/xml, or application/*+xml
67
                    .ignoreContentType(true)
68
                    // Prevent exception on HTTP errors
69
                    .ignoreHttpErrors(true)
70
                    .get()
71
                    .html()
72
                    .replaceAll("<img[^>]*>", StringUtils.EMPTY)
73
                    .replaceAll("<input[^>]*type=\"?hidden\"?[^>]*>", StringUtils.EMPTY)
74
                    .replaceAll("<input[^>]*type=\"?(submit|button)\"?[^>]*>", "<div style=\"background-color:#eeeeee;text-align:center;border:1px solid black;width:100px;\">button</div>")
75
                    .replaceAll("<input[^>]*>", "<div style=\"text-align:center;border:1px solid black;width:100px;\">input</div>"),
76
                Safelist.relaxed()
77
                    .addTags("center", "div", "span")
78
                    .addAttributes(":all", "style")
79
            );
80
        } catch (IOException e) {
81
            LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Failure opening page: {}", e.getMessage());
82
        } catch (ExceptionInInitializerError | NoClassDefFoundError e) {
83
            LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
84
        }
85
86
        final var browser = new JTextPane();
87 1 1. execute : removed call to javax/swing/JTextPane::setContentType → NO_COVERAGE
        browser.setContentType("text/html");
88 1 1. execute : removed call to javax/swing/JTextPane::setEditable → NO_COVERAGE
        browser.setEditable(false);
89 1 1. execute : removed call to javax/swing/JTextPane::setCaretPosition → NO_COVERAGE
        browser.setCaretPosition(0);
90
91
        // Fix #43220: EmptyStackException on setText()
92
        // Fix #94242: IndexOutOfBoundsException on setText()
93
        try {
94 1 1. execute : removed call to javax/swing/JTextPane::setText → NO_COVERAGE
            browser.setText(htmlSource);
95
        } catch (IndexOutOfBoundsException | EmptyStackException e) {
96
            LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
97
        }
98
99
        JMenuItem itemCopyUrl = new JMenuItem(I18nUtil.valueByKey("CONTEXT_MENU_COPY_PAGE_URL"));
100 1 1. execute : removed call to com/jsql/view/swing/util/I18nViewUtil::addComponentForKey → NO_COVERAGE
        I18nViewUtil.addComponentForKey("CONTEXT_MENU_COPY_PAGE_URL", itemCopyUrl);
101
102
        JMenuItem itemCopy = new JMenuItem();
103 1 1. execute : removed call to javax/swing/JMenuItem::setAction → NO_COVERAGE
        itemCopy.setAction(browser.getActionMap().get(DefaultEditorKit.copyAction));
104 1 1. execute : removed call to javax/swing/JMenuItem::setAccelerator → NO_COVERAGE
        itemCopy.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_DOWN_MASK));
105 1 1. execute : removed call to javax/swing/JMenuItem::setMnemonic → NO_COVERAGE
        itemCopy.setMnemonic('C');
106 1 1. execute : removed call to javax/swing/JMenuItem::setText → NO_COVERAGE
        itemCopy.setText(I18nUtil.valueByKey("CONTEXT_MENU_COPY"));
107 1 1. execute : removed call to com/jsql/view/swing/util/I18nViewUtil::addComponentForKey → NO_COVERAGE
        I18nViewUtil.addComponentForKey("CONTEXT_MENU_COPY", itemCopy);
108
109
        JMenuItem itemSelectAll = new JMenuItem();
110 1 1. execute : removed call to javax/swing/JMenuItem::setAction → NO_COVERAGE
        itemSelectAll.setAction(browser.getActionMap().get(DefaultEditorKit.selectAllAction));
111 1 1. execute : removed call to javax/swing/JMenuItem::setAccelerator → NO_COVERAGE
        itemSelectAll.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.CTRL_DOWN_MASK));
112 1 1. execute : removed call to javax/swing/JMenuItem::setText → NO_COVERAGE
        itemSelectAll.setText(I18nUtil.valueByKey("CONTEXT_MENU_SELECT_ALL"));
113 1 1. execute : removed call to com/jsql/view/swing/util/I18nViewUtil::addComponentForKey → NO_COVERAGE
        I18nViewUtil.addComponentForKey("CONTEXT_MENU_SELECT_ALL", itemSelectAll);
114 1 1. execute : removed call to javax/swing/JMenuItem::setMnemonic → NO_COVERAGE
        itemSelectAll.setMnemonic('A');
115
116
        final var menu = new JPopupMenu();
117
        menu.add(itemCopyUrl);
118
        menu.add(new JSeparator());
119
        menu.add(itemCopy);
120
        menu.add(itemSelectAll);
121 1 1. execute : removed call to javax/swing/JPopupMenu::applyComponentOrientation → NO_COVERAGE
        menu.applyComponentOrientation(ComponentOrientation.getOrientation(I18nUtil.getCurrentLocale()));
122
123 1 1. execute : removed call to javax/swing/JMenuItem::addActionListener → NO_COVERAGE
        itemCopyUrl.addActionListener(actionEvent -> {
124
            var stringSelection = new StringSelection(this.url);
125
            var clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
126 1 1. lambda$execute$0 : removed call to java/awt/datatransfer/Clipboard::setContents → NO_COVERAGE
            clipboard.setContents(stringSelection, null);
127
        });
128
129 2 1. lambda$execute$1 : removed call to javax/swing/JTextPane::selectAll → NO_COVERAGE
2. execute : removed call to javax/swing/JMenuItem::addActionListener → NO_COVERAGE
        itemSelectAll.addActionListener(actionEvent -> browser.selectAll());
130
        
131 1 1. execute : removed call to javax/swing/JTextPane::addFocusListener → NO_COVERAGE
        browser.addFocusListener(new FocusAdapter() {
132
            @Override
133
            public void focusGained(FocusEvent focusEvent) {
134 1 1. focusGained : removed call to javax/swing/text/Caret::setVisible → NO_COVERAGE
                browser.getCaret().setVisible(true);
135 1 1. focusGained : removed call to javax/swing/text/Caret::setSelectionVisible → NO_COVERAGE
                browser.getCaret().setSelectionVisible(true);
136
            }
137
        });
138
        
139 1 1. execute : removed call to javax/swing/JTextPane::addMouseListener → NO_COVERAGE
        browser.addMouseListener(new MouseAdapter() {
140
            @Override
141
            public void mousePressed(MouseEvent evt) {
142
                browser.requestFocusInWindow();
143 1 1. mousePressed : negated conditional → NO_COVERAGE
                if (evt.isPopupTrigger()) {
144 1 1. mousePressed : removed call to javax/swing/JPopupMenu::show → NO_COVERAGE
                    menu.show(evt.getComponent(), evt.getX(), evt.getY());
145
                }
146
            }
147
            @Override
148
            public void mouseReleased(MouseEvent evt) {
149 1 1. mouseReleased : negated conditional → NO_COVERAGE
                if (evt.isPopupTrigger()) {
150
                    // Fix #45348: IllegalComponentStateException on show()
151
                    try {
152 1 1. mouseReleased : removed call to javax/swing/JPopupMenu::show → NO_COVERAGE
                        menu.show(evt.getComponent(), evt.getX(), evt.getY());
153
                    } catch (IllegalComponentStateException e) {
154
                        LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
155
                    }
156 1 1. mouseReleased : removed call to javax/swing/JPopupMenu::setLocation → NO_COVERAGE
                    menu.setLocation(
157 1 1. mouseReleased : negated conditional → NO_COVERAGE
                        ComponentOrientation.RIGHT_TO_LEFT.equals(ComponentOrientation.getOrientation(I18nUtil.getCurrentLocale()))
158 1 1. mouseReleased : Replaced integer subtraction with addition → NO_COVERAGE
                        ? evt.getXOnScreen() - menu.getWidth()
159
                        : evt.getXOnScreen(),
160
                        evt.getYOnScreen()
161
                    );
162
                }
163
            }
164
        });
165
166
        final var scroller = new JScrollPane(browser);
167 1 1. execute : removed call to com/jsql/view/swing/tab/TabResults::addTab → NO_COVERAGE
        MediatorHelper.tabResults().addTab(this.url.replaceAll(".*/", StringUtils.EMPTY) + StringUtils.SPACE, scroller);
168 1 1. execute : removed call to com/jsql/view/swing/tab/TabResults::setSelectedComponent → NO_COVERAGE
        MediatorHelper.tabResults().setSelectedComponent(scroller);  // Focus on the new tab
169 1 1. execute : removed call to com/jsql/view/swing/tab/TabResults::setToolTipTextAt → NO_COVERAGE
        MediatorHelper.tabResults().setToolTipTextAt(
170
            MediatorHelper.tabResults().indexOfComponent(scroller),
171
            String.format("<html>%s</html>", this.url)
172
        );
173
174
        // Create a custom tab header
175
        var header = new TabHeader(
176
            this.url.replaceAll(".*/", StringUtils.EMPTY),
177
            UiUtil.ADMIN.getIcon()
178
        );
179 1 1. execute : removed call to com/jsql/view/swing/tab/TabResults::setTabComponentAt → NO_COVERAGE
        MediatorHelper.tabResults().setTabComponentAt(MediatorHelper.tabResults().indexOfComponent(scroller), header);  // Apply the custom header to the tab
180 1 1. execute : removed call to javax/swing/JTextPane::setCaretPosition → NO_COVERAGE
        browser.setCaretPosition(0);
181
182 1 1. execute : removed call to com/jsql/view/swing/tab/TabResults::updateUI → NO_COVERAGE
        MediatorHelper.tabResults().updateUI();  // required: light, open/close prefs, dark => light artifacts
183
    }
184
}

Mutations

87

1.1
Location : execute
Killed by : none
removed call to javax/swing/JTextPane::setContentType → NO_COVERAGE

88

1.1
Location : execute
Killed by : none
removed call to javax/swing/JTextPane::setEditable → NO_COVERAGE

89

1.1
Location : execute
Killed by : none
removed call to javax/swing/JTextPane::setCaretPosition → NO_COVERAGE

94

1.1
Location : execute
Killed by : none
removed call to javax/swing/JTextPane::setText → NO_COVERAGE

100

1.1
Location : execute
Killed by : none
removed call to com/jsql/view/swing/util/I18nViewUtil::addComponentForKey → NO_COVERAGE

103

1.1
Location : execute
Killed by : none
removed call to javax/swing/JMenuItem::setAction → NO_COVERAGE

104

1.1
Location : execute
Killed by : none
removed call to javax/swing/JMenuItem::setAccelerator → NO_COVERAGE

105

1.1
Location : execute
Killed by : none
removed call to javax/swing/JMenuItem::setMnemonic → NO_COVERAGE

106

1.1
Location : execute
Killed by : none
removed call to javax/swing/JMenuItem::setText → NO_COVERAGE

107

1.1
Location : execute
Killed by : none
removed call to com/jsql/view/swing/util/I18nViewUtil::addComponentForKey → NO_COVERAGE

110

1.1
Location : execute
Killed by : none
removed call to javax/swing/JMenuItem::setAction → NO_COVERAGE

111

1.1
Location : execute
Killed by : none
removed call to javax/swing/JMenuItem::setAccelerator → NO_COVERAGE

112

1.1
Location : execute
Killed by : none
removed call to javax/swing/JMenuItem::setText → NO_COVERAGE

113

1.1
Location : execute
Killed by : none
removed call to com/jsql/view/swing/util/I18nViewUtil::addComponentForKey → NO_COVERAGE

114

1.1
Location : execute
Killed by : none
removed call to javax/swing/JMenuItem::setMnemonic → NO_COVERAGE

121

1.1
Location : execute
Killed by : none
removed call to javax/swing/JPopupMenu::applyComponentOrientation → NO_COVERAGE

123

1.1
Location : execute
Killed by : none
removed call to javax/swing/JMenuItem::addActionListener → NO_COVERAGE

126

1.1
Location : lambda$execute$0
Killed by : none
removed call to java/awt/datatransfer/Clipboard::setContents → NO_COVERAGE

129

1.1
Location : lambda$execute$1
Killed by : none
removed call to javax/swing/JTextPane::selectAll → NO_COVERAGE

2.2
Location : execute
Killed by : none
removed call to javax/swing/JMenuItem::addActionListener → NO_COVERAGE

131

1.1
Location : execute
Killed by : none
removed call to javax/swing/JTextPane::addFocusListener → NO_COVERAGE

134

1.1
Location : focusGained
Killed by : none
removed call to javax/swing/text/Caret::setVisible → NO_COVERAGE

135

1.1
Location : focusGained
Killed by : none
removed call to javax/swing/text/Caret::setSelectionVisible → NO_COVERAGE

139

1.1
Location : execute
Killed by : none
removed call to javax/swing/JTextPane::addMouseListener → NO_COVERAGE

143

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

144

1.1
Location : mousePressed
Killed by : none
removed call to javax/swing/JPopupMenu::show → NO_COVERAGE

149

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

152

1.1
Location : mouseReleased
Killed by : none
removed call to javax/swing/JPopupMenu::show → NO_COVERAGE

156

1.1
Location : mouseReleased
Killed by : none
removed call to javax/swing/JPopupMenu::setLocation → NO_COVERAGE

157

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

158

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

167

1.1
Location : execute
Killed by : none
removed call to com/jsql/view/swing/tab/TabResults::addTab → NO_COVERAGE

168

1.1
Location : execute
Killed by : none
removed call to com/jsql/view/swing/tab/TabResults::setSelectedComponent → NO_COVERAGE

169

1.1
Location : execute
Killed by : none
removed call to com/jsql/view/swing/tab/TabResults::setToolTipTextAt → NO_COVERAGE

179

1.1
Location : execute
Killed by : none
removed call to com/jsql/view/swing/tab/TabResults::setTabComponentAt → NO_COVERAGE

180

1.1
Location : execute
Killed by : none
removed call to javax/swing/JTextPane::setCaretPosition → NO_COVERAGE

182

1.1
Location : execute
Killed by : none
removed call to com/jsql/view/swing/tab/TabResults::updateUI → NO_COVERAGE

Active mutators

Tests examined


Report generated by PIT 1.19.1