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

Mutations

50

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

58

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

64

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

83

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

84

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

89

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

90

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

96

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

97

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

98

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

99

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

100

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

104

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

105

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

106

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

107

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

108

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

112

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

120

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

133

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

140

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

143

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

144

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

160

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

161

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