ActionSaveTab.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.util.LogLevelUtil;
14
import com.jsql.view.swing.dialog.ReplaceFileChooser;
15
import com.jsql.view.swing.table.PanelTable;
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 javax.swing.text.JTextComponent;
22
import java.awt.event.ActionEvent;
23
import java.awt.event.InputEvent;
24
import java.awt.event.KeyEvent;
25
import java.io.BufferedWriter;
26
import java.io.FileWriter;
27
import java.io.IOException;
28
import java.nio.charset.StandardCharsets;
29
import java.nio.file.InvalidPathException;
30
31
/**
32
 * Save the content of tab in a file.
33
 */
34
public class ActionSaveTab extends AbstractAction {
35
    
36
    private static final Logger LOGGER = LogManager.getRootLogger();
37
    
38
    private ReplaceFileChooser replaceFileChooser;
39
40
    public ActionSaveTab() {
41
        // Unhandled NoSuchMethodError #82561 on constructor: NoSuchMethodError
42
        // Unhandled InternalError #93015 on constructor: InvocationTargetException
43
        // Unhandled NullPointerException #95805 on constructor: desktop null on Windows
44
        // Unhandled IllegalArgumentException #95985 on constructor: Comparison method violates its general contract!
45
        try {
46
            this.replaceFileChooser = new ReplaceFileChooser(
47
                MediatorHelper.model().getMediatorUtils().getPreferencesUtil().getPathFile()
48
            );
49
        } catch (IllegalArgumentException | NoSuchMethodError | InternalError | NullPointerException e) {
50
            LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Internal error in JFileChooser, verify your system and see stacktrace in tab Java: {}", e.getMessage());
51
            LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e);
52
        }
53 1 1. <init> : removed call to com/jsql/view/swing/action/ActionSaveTab::putValue → NO_COVERAGE
        this.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK));
54 1 1. <init> : removed call to com/jsql/view/swing/action/ActionSaveTab::putValue → NO_COVERAGE
        this.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_S);
55 1 1. <init> : removed call to com/jsql/view/swing/action/ActionSaveTab::putValue → NO_COVERAGE
        this.putValue(Action.NAME, "Save Tab As...");
56
    }
57
    
58
    @Override
59
    public void actionPerformed(ActionEvent e) {
60 1 1. actionPerformed : removed call to com/jsql/view/swing/dialog/ReplaceFileChooser::setDialogTitle → NO_COVERAGE
        this.replaceFileChooser.setDialogTitle("Save Tab As");
61
        var componentResult = MediatorHelper.tabResults().getSelectedComponent();
62 1 1. actionPerformed : negated conditional → NO_COVERAGE
        if (componentResult instanceof PanelTable) {
63
            JTable table = ((PanelTable) componentResult).getTableValues();
64 1 1. actionPerformed : removed call to com/jsql/view/swing/action/ActionSaveTab::saveToFile → NO_COVERAGE
            this.saveToFile(table);
65 1 1. actionPerformed : negated conditional → NO_COVERAGE
        } else if (
66
            componentResult instanceof JScrollPane
67 1 1. actionPerformed : negated conditional → NO_COVERAGE
            && ((JScrollPane) componentResult).getViewport().getView() instanceof JTextComponent
68
        ) {
69
            JTextComponent textarea = (JTextComponent) ((JScrollPane) componentResult).getViewport().getView();
70 1 1. actionPerformed : removed call to com/jsql/view/swing/action/ActionSaveTab::saveToFile → NO_COVERAGE
            this.saveToFile(textarea);
71
        }
72
    }
73
    
74
    private void saveToFile(JComponent textarea) {
75 1 1. saveToFile : negated conditional → NO_COVERAGE
        if (textarea == null) {
76
            return;
77
        }
78
79 1 1. saveToFile : removed call to com/jsql/view/swing/dialog/ReplaceFileChooser::updateUI → NO_COVERAGE
        this.replaceFileChooser.updateUI();  // required when changing dark/light mode
80
        try {  // Fix #96109: InvalidPathException on showSaveDialog()
81
            int stateSave = this.replaceFileChooser.showSaveDialog(MediatorHelper.frame());
82 1 1. saveToFile : negated conditional → NO_COVERAGE
            if (stateSave == JFileChooser.APPROVE_OPTION) {
83
                var folderSelectedFile = this.replaceFileChooser.getCurrentDirectory().toString();
84 1 1. saveToFile : removed call to com/jsql/util/PreferencesUtil::set → NO_COVERAGE
                MediatorHelper.model().getMediatorUtils().getPreferencesUtil().set(folderSelectedFile);
85 1 1. saveToFile : negated conditional → NO_COVERAGE
                if (textarea instanceof JTextComponent) {
86 1 1. saveToFile : removed call to com/jsql/view/swing/action/ActionSaveTab::saveTextToFile → NO_COVERAGE
                    this.saveTextToFile((JTextComponent) textarea);
87 1 1. saveToFile : negated conditional → NO_COVERAGE
                } else if (textarea instanceof JTable) {
88 1 1. saveToFile : removed call to com/jsql/view/swing/action/ActionSaveTab::saveTableToFile → NO_COVERAGE
                    this.saveTableToFile((JTable) textarea);
89
                }
90
            }
91
        } catch (InvalidPathException e) {
92
            LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
93
        }
94
    }
95
96
    private void saveTableToFile(JTable tableResults) {
97
        var fileSelected = this.replaceFileChooser.getSelectedFile();
98
        
99
        try (var fileWriter = new FileWriter(fileSelected, StandardCharsets.UTF_8)) {
100
            var tableModel = tableResults.getModel();
101 2 1. saveTableToFile : changed conditional boundary → NO_COVERAGE
2. saveTableToFile : negated conditional → NO_COVERAGE
            for (var i = 2 ; i < tableModel.getColumnCount() ; i++) {
102 1 1. saveTableToFile : removed call to java/io/FileWriter::write → NO_COVERAGE
                fileWriter.write(tableModel.getColumnName(i) + "\t");
103
            }
104 1 1. saveTableToFile : removed call to java/io/FileWriter::write → NO_COVERAGE
            fileWriter.write("\n");
105
            
106 2 1. saveTableToFile : changed conditional boundary → NO_COVERAGE
2. saveTableToFile : negated conditional → NO_COVERAGE
            for (var i = 0 ; i < tableModel.getRowCount() ; i++) {
107 2 1. saveTableToFile : negated conditional → NO_COVERAGE
2. saveTableToFile : changed conditional boundary → NO_COVERAGE
                for (var j = 2 ; j < tableModel.getColumnCount() ; j++) {
108
                    // Cell empty when string was too long to be injected (columnTooLong|cellEmpty|cellEmpty).
109 1 1. saveTableToFile : negated conditional → NO_COVERAGE
                    if (tableModel.getValueAt(i, j) == null) {
110 1 1. saveTableToFile : removed call to java/io/FileWriter::write → NO_COVERAGE
                        fileWriter.write("\t");
111
                    } else {
112
                        var line = tableModel.getValueAt(i, j).toString();  // Encode line break.
113
                        line = line
114
                            .replace("\n", "\\n")
115
                            .replace("\t", "\\t");
116
                        line = line + "\t";
117 1 1. saveTableToFile : removed call to java/io/FileWriter::write → NO_COVERAGE
                        fileWriter.write(line);
118
                    }
119
                }
120 1 1. saveTableToFile : removed call to java/io/FileWriter::write → NO_COVERAGE
                fileWriter.write("\n");
121
            }
122
        } catch (IOException e) {
123
            LOGGER.log(
124
                LogLevelUtil.CONSOLE_ERROR,
125
                String.format("Error writing to %s", fileSelected.getName()),
126
                e.getMessage()  // full stacktrace not required
127
            );
128
        }
129
    }
130
131
    private void saveTextToFile(JTextComponent textarea) {
132
        var fileSelected = this.replaceFileChooser.getSelectedFile();
133
        try (
134
            var fileWriter = new FileWriter(fileSelected, StandardCharsets.UTF_8);
135
            var fileOut = new BufferedWriter(fileWriter)
136
        ) {
137 1 1. saveTextToFile : removed call to javax/swing/text/JTextComponent::write → NO_COVERAGE
            textarea.write(fileOut);
138
        } catch (IOException e) {
139
            LOGGER.log(
140
                LogLevelUtil.CONSOLE_ERROR,
141
                String.format("Error writing to %s", fileSelected.getName()),
142
                e
143
            );
144
        }
145
    }
146
}

Mutations

53

1.1
Location : <init>
Killed by : none
removed call to com/jsql/view/swing/action/ActionSaveTab::putValue → NO_COVERAGE

54

1.1
Location : <init>
Killed by : none
removed call to com/jsql/view/swing/action/ActionSaveTab::putValue → NO_COVERAGE

55

1.1
Location : <init>
Killed by : none
removed call to com/jsql/view/swing/action/ActionSaveTab::putValue → NO_COVERAGE

60

1.1
Location : actionPerformed
Killed by : none
removed call to com/jsql/view/swing/dialog/ReplaceFileChooser::setDialogTitle → NO_COVERAGE

62

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

64

1.1
Location : actionPerformed
Killed by : none
removed call to com/jsql/view/swing/action/ActionSaveTab::saveToFile → NO_COVERAGE

65

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

67

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

70

1.1
Location : actionPerformed
Killed by : none
removed call to com/jsql/view/swing/action/ActionSaveTab::saveToFile → NO_COVERAGE

75

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

79

1.1
Location : saveToFile
Killed by : none
removed call to com/jsql/view/swing/dialog/ReplaceFileChooser::updateUI → NO_COVERAGE

82

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

84

1.1
Location : saveToFile
Killed by : none
removed call to com/jsql/util/PreferencesUtil::set → NO_COVERAGE

85

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

86

1.1
Location : saveToFile
Killed by : none
removed call to com/jsql/view/swing/action/ActionSaveTab::saveTextToFile → NO_COVERAGE

87

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

88

1.1
Location : saveToFile
Killed by : none
removed call to com/jsql/view/swing/action/ActionSaveTab::saveTableToFile → NO_COVERAGE

101

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

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

102

1.1
Location : saveTableToFile
Killed by : none
removed call to java/io/FileWriter::write → NO_COVERAGE

104

1.1
Location : saveTableToFile
Killed by : none
removed call to java/io/FileWriter::write → NO_COVERAGE

106

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

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

107

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

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

109

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

110

1.1
Location : saveTableToFile
Killed by : none
removed call to java/io/FileWriter::write → NO_COVERAGE

117

1.1
Location : saveTableToFile
Killed by : none
removed call to java/io/FileWriter::write → NO_COVERAGE

120

1.1
Location : saveTableToFile
Killed by : none
removed call to java/io/FileWriter::write → NO_COVERAGE

137

1.1
Location : saveTextToFile
Killed by : none
removed call to javax/swing/text/JTextComponent::write → NO_COVERAGE

Active mutators

Tests examined


Report generated by PIT 1.22.0