AbstractListTransfertHandler.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.list;
12
13
import com.jsql.util.LogLevelUtil;
14
import org.apache.logging.log4j.LogManager;
15
import org.apache.logging.log4j.Logger;
16
17
import javax.swing.*;
18
import java.awt.*;
19
import java.awt.datatransfer.DataFlavor;
20
import java.awt.datatransfer.StringSelection;
21
import java.awt.datatransfer.Transferable;
22
import java.awt.datatransfer.UnsupportedFlavorException;
23
import java.io.File;
24
import java.io.IOException;
25
import java.util.List;
26
27
/**
28
 * Handler for processing cut/copy/paste/drag/drop action on a JList items.
29
 */
30
public abstract class AbstractListTransfertHandler extends TransferHandler {
31
    
32
    private static final Logger LOGGER = LogManager.getRootLogger();
33
34
    /**
35
     * List of cut/copy/paste/drag/drop items.
36
     */
37
    protected transient List<ItemList> dragPaths = null;
38
    
39
    protected abstract String initTransferable();
40
    
41
    protected abstract void parseStringDrop(TransferSupport support, DnDList list, DefaultListModel<ItemList> listModel);
42
    
43
    protected abstract List<Integer> initStringPaste(String clipboardText, int selectedIndex, DefaultListModel<ItemList> listModel);
44
    
45
    @Override
46
    public int getSourceActions(JComponent c) {
47 1 1. getSourceActions : replaced int return with 0 for com/jsql/view/swing/list/AbstractListTransfertHandler::getSourceActions → NO_COVERAGE
        return TransferHandler.COPY_OR_MOVE;
48
    }
49
    
50
    @Override
51
    protected Transferable createTransferable(JComponent component) {
52
        DnDList list = (DnDList) component;
53
        this.dragPaths = list.getSelectedValuesList();
54
        var stringTransferable = this.initTransferable();
55 1 1. createTransferable : replaced return value with null for com/jsql/view/swing/list/AbstractListTransfertHandler::createTransferable → NO_COVERAGE
        return new StringSelection(stringTransferable.trim());
56
    }
57
58
    @SuppressWarnings("unchecked")
59
    @Override
60
    protected void exportDone(JComponent c, Transferable data, int action) {
61 1 1. exportDone : negated conditional → NO_COVERAGE
        if (action == TransferHandler.MOVE) {
62
            JList<ItemList> list = (JList<ItemList>) c;
63
            DefaultListModel<ItemList> model = (DefaultListModel<ItemList>) list.getModel();
64
            
65
            for (ItemList itemPath: this.dragPaths) {
66
                // Unhandled ArrayIndexOutOfBoundsException #56115 on remove()
67
                try {
68
                    model.remove(model.indexOf(itemPath));
69
                } catch (ArrayIndexOutOfBoundsException e) {
70
                    LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e.getMessage(), e);
71
                }
72
            }
73
            
74
            this.dragPaths = null;
75
        }
76
    }
77
78
    @Override
79
    public boolean canImport(TransferSupport support) {
80 2 1. canImport : replaced boolean return with true for com/jsql/view/swing/list/AbstractListTransfertHandler::canImport → NO_COVERAGE
2. canImport : negated conditional → NO_COVERAGE
        return support.isDataFlavorSupported(DataFlavor.stringFlavor)
81 1 1. canImport : negated conditional → NO_COVERAGE
            || support.isDataFlavorSupported(DataFlavor.javaFileListFlavor);
82
    }
83
84
    @Override
85
    public boolean importData(TransferSupport support) {
86 1 1. importData : negated conditional → NO_COVERAGE
        if (!this.canImport(support)) {
87 1 1. importData : replaced boolean return with true for com/jsql/view/swing/list/AbstractListTransfertHandler::importData → NO_COVERAGE
            return false;
88
        }
89
90
        DnDList list = (DnDList) support.getComponent();
91
        DefaultListModel<ItemList> listModel = (DefaultListModel<ItemList>) list.getModel();
92
        
93 1 1. importData : negated conditional → NO_COVERAGE
        if (support.isDrop()) {  // drop
94 1 1. importData : negated conditional → NO_COVERAGE
            if (support.isDataFlavorSupported(DataFlavor.stringFlavor)) {
95 1 1. importData : removed call to com/jsql/view/swing/list/AbstractListTransfertHandler::parseStringDrop → NO_COVERAGE
                this.parseStringDrop(support, list, listModel);
96 1 1. importData : negated conditional → NO_COVERAGE
            } else if (support.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
97 1 1. importData : removed call to com/jsql/view/swing/list/AbstractListTransfertHandler::parseFileDrop → NO_COVERAGE
                this.parseFileDrop(support, list);
98
            }
99
        } else {
100
            var transferableFromClipboard = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null);
101 1 1. importData : negated conditional → NO_COVERAGE
            if (transferableFromClipboard != null) {  // paste
102 1 1. importData : negated conditional → NO_COVERAGE
                if (transferableFromClipboard.isDataFlavorSupported(DataFlavor.stringFlavor)) {
103 1 1. importData : removed call to com/jsql/view/swing/list/AbstractListTransfertHandler::parseStringPaste → NO_COVERAGE
                    this.parseStringPaste(list, listModel, transferableFromClipboard);
104 1 1. importData : negated conditional → NO_COVERAGE
                } else if (transferableFromClipboard.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
105 1 1. importData : removed call to com/jsql/view/swing/list/AbstractListTransfertHandler::parseFilePaste → NO_COVERAGE
                    this.parseFilePaste(list, transferableFromClipboard);
106
                }
107
            }
108
        }
109 1 1. importData : replaced boolean return with false for com/jsql/view/swing/list/AbstractListTransfertHandler::importData → NO_COVERAGE
        return true;
110
    }
111
112
    @SuppressWarnings("unchecked")
113
    private void parseFileDrop(TransferSupport support, DnDList list) {
114
        JList.DropLocation dropLocation = (JList.DropLocation) support.getDropLocation();
115
        int childIndex = dropLocation.getIndex();
116
        try {
117 1 1. parseFileDrop : removed call to com/jsql/view/swing/list/DnDList::dropPasteFile → NO_COVERAGE
            list.dropPasteFile(
118
                (List<File>) support.getTransferable().getTransferData(DataFlavor.javaFileListFlavor),
119
                childIndex
120
            );
121
        } catch (UnsupportedFlavorException | IOException e) {
122
            LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
123
        }
124
    }
125
126
    private void parseStringPaste(DnDList list, DefaultListModel<ItemList> listModel, Transferable transferableFromClipboard) {
127
        try {
128
            String clipboardText = (String) transferableFromClipboard.getTransferData(DataFlavor.stringFlavor);
129
            var selectedIndexPaste = Math.max(list.getSelectedIndex(), 0);
130 1 1. parseStringPaste : removed call to com/jsql/view/swing/list/DnDList::clearSelection → NO_COVERAGE
            list.clearSelection();
131
            List<Integer> selectedIndexes = this.initStringPaste(clipboardText, selectedIndexPaste, listModel);
132
            var selectedIndexesPasted = new int[selectedIndexes.size()];
133
            var i = 0;
134
            
135
            for (Integer selectedIndex: selectedIndexes) {
136
                selectedIndexesPasted[i] = selectedIndex;
137 1 1. parseStringPaste : Changed increment from 1 to -1 → NO_COVERAGE
                i++;
138
            }
139
            
140 1 1. parseStringPaste : removed call to com/jsql/view/swing/list/DnDList::setSelectedIndices → NO_COVERAGE
            list.setSelectedIndices(selectedIndexesPasted);
141 1 1. parseStringPaste : removed call to com/jsql/view/swing/list/DnDList::scrollRectToVisible → NO_COVERAGE
            list.scrollRectToVisible(
142
                list.getCellBounds(
143
                    list.getMinSelectionIndex(),
144
                    list.getMaxSelectionIndex()
145
                )
146
            );
147
        } catch (NullPointerException | UnsupportedFlavorException | IOException e) {
148
            // Fix #8831: Multiple Exception on scrollRectToVisible()
149
            LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
150
        }
151
    }
152
153
    @SuppressWarnings("unchecked")
154
    private void parseFilePaste(DnDList list, Transferable transferableFromClipboard) {
155
        try {
156
            var selectedIndex = Math.max(list.getSelectedIndex(), 0);
157 1 1. parseFilePaste : removed call to com/jsql/view/swing/list/DnDList::clearSelection → NO_COVERAGE
            list.clearSelection();
158 1 1. parseFilePaste : removed call to com/jsql/view/swing/list/DnDList::dropPasteFile → NO_COVERAGE
            list.dropPasteFile(
159
                (List<File>) transferableFromClipboard.getTransferData(DataFlavor.javaFileListFlavor),
160
                selectedIndex
161
            );
162
        } catch (UnsupportedFlavorException | IOException e) {
163
            LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
164
        }
165
    }
166
}

Mutations

47

1.1
Location : getSourceActions
Killed by : none
replaced int return with 0 for com/jsql/view/swing/list/AbstractListTransfertHandler::getSourceActions → NO_COVERAGE

55

1.1
Location : createTransferable
Killed by : none
replaced return value with null for com/jsql/view/swing/list/AbstractListTransfertHandler::createTransferable → NO_COVERAGE

61

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

80

1.1
Location : canImport
Killed by : none
replaced boolean return with true for com/jsql/view/swing/list/AbstractListTransfertHandler::canImport → NO_COVERAGE

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

81

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

86

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

87

1.1
Location : importData
Killed by : none
replaced boolean return with true for com/jsql/view/swing/list/AbstractListTransfertHandler::importData → NO_COVERAGE

93

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

94

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

95

1.1
Location : importData
Killed by : none
removed call to com/jsql/view/swing/list/AbstractListTransfertHandler::parseStringDrop → NO_COVERAGE

96

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

97

1.1
Location : importData
Killed by : none
removed call to com/jsql/view/swing/list/AbstractListTransfertHandler::parseFileDrop → NO_COVERAGE

101

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

102

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

103

1.1
Location : importData
Killed by : none
removed call to com/jsql/view/swing/list/AbstractListTransfertHandler::parseStringPaste → NO_COVERAGE

104

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

105

1.1
Location : importData
Killed by : none
removed call to com/jsql/view/swing/list/AbstractListTransfertHandler::parseFilePaste → NO_COVERAGE

109

1.1
Location : importData
Killed by : none
replaced boolean return with false for com/jsql/view/swing/list/AbstractListTransfertHandler::importData → NO_COVERAGE

117

1.1
Location : parseFileDrop
Killed by : none
removed call to com/jsql/view/swing/list/DnDList::dropPasteFile → NO_COVERAGE

130

1.1
Location : parseStringPaste
Killed by : none
removed call to com/jsql/view/swing/list/DnDList::clearSelection → NO_COVERAGE

137

1.1
Location : parseStringPaste
Killed by : none
Changed increment from 1 to -1 → NO_COVERAGE

140

1.1
Location : parseStringPaste
Killed by : none
removed call to com/jsql/view/swing/list/DnDList::setSelectedIndices → NO_COVERAGE

141

1.1
Location : parseStringPaste
Killed by : none
removed call to com/jsql/view/swing/list/DnDList::scrollRectToVisible → NO_COVERAGE

157

1.1
Location : parseFilePaste
Killed by : none
removed call to com/jsql/view/swing/list/DnDList::clearSelection → NO_COVERAGE

158

1.1
Location : parseFilePaste
Killed by : none
removed call to com/jsql/view/swing/list/DnDList::dropPasteFile → NO_COVERAGE

Active mutators

Tests examined


Report generated by PIT 1.19.1