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

Mutations

90

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

91

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

92

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

97

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

103

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

106

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

107

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

108

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

109

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

110

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

113

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

114

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

115

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

116

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

117

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

124

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

126

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

129

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

132

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

134

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

137

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

138

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

142

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

146

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

147

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

152

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

155

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

159

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

160

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

161

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

170

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

171

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

172

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

182

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

183

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

185

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