• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

jiangxincode / ApkToolBoxGUI / #1138

23 Aug 2025 09:51AM UTC coverage: 2.877% (-0.06%) from 2.94%
#1138

push

jiangxincode
add pdf password remover function

0 of 205 new or added lines in 4 files covered. (0.0%)

1 existing line in 1 file now uncovered.

236 of 8202 relevant lines covered (2.88%)

0.03 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/main/java/edu/jiangxin/apktoolbox/pdf/passwordremover/PdfPasswordRemoverPanel.java
1
package edu.jiangxin.apktoolbox.pdf.passwordremover;
2

3
import edu.jiangxin.apktoolbox.pdf.PdfUtils;
4
import edu.jiangxin.apktoolbox.swing.extend.EasyPanel;
5
import edu.jiangxin.apktoolbox.swing.extend.FileListPanel;
6
import edu.jiangxin.apktoolbox.swing.extend.filepanel.FilePanel;
7
import edu.jiangxin.apktoolbox.utils.Constants;
8

9
import javax.swing.*;
10
import java.awt.event.ActionEvent;
11
import java.awt.event.ActionListener;
12
import java.io.File;
13
import java.util.ArrayList;
14
import java.util.List;
15
import java.util.Set;
16
import java.util.TreeSet;
17
import java.util.concurrent.ExecutorService;
18
import java.util.concurrent.Executors;
19
import java.util.concurrent.Future;
20
import java.util.concurrent.atomic.AtomicInteger;
21

NEW
22
public class PdfPasswordRemoverPanel extends EasyPanel {
×
23
    private FileListPanel fileListPanel;
24

25
    private JCheckBox isRecursiveSearched;
26

27
    private FilePanel targetDirPanel;
28

29
    private JButton startButton;
30
    private JButton cancelButton;
31

32
    private JProgressBar progressBar;
33

34
    private WorkderThread searchThread;
35

NEW
36
    final private List<File> scannedFileList = new ArrayList<>();
×
37
    @Override
38
    public void initUI() {
NEW
39
        BoxLayout boxLayout = new BoxLayout(this, BoxLayout.Y_AXIS);
×
NEW
40
        setLayout(boxLayout);
×
41

NEW
42
        createInputPanel();
×
NEW
43
        add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER));
×
44

NEW
45
        createOutputPanel();
×
NEW
46
        add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER));
×
47

NEW
48
        createOptionPanel();
×
NEW
49
        add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER));
×
50

NEW
51
        createOperationPanel();
×
NEW
52
        add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER));
×
53

NEW
54
        createProcessBarPanel();
×
NEW
55
    }
×
56

57
    private void createInputPanel() {
NEW
58
        fileListPanel = new FileListPanel();
×
NEW
59
        add(fileListPanel);
×
NEW
60
    }
×
61

62
    private void createOutputPanel() {
NEW
63
        targetDirPanel = new FilePanel("Target Directory");
×
NEW
64
        targetDirPanel.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
×
NEW
65
        add(targetDirPanel);
×
NEW
66
    }
×
67

68
    private void createOptionPanel() {
NEW
69
        JPanel optionPanel = new JPanel();
×
NEW
70
        optionPanel.setLayout(new BoxLayout(optionPanel, BoxLayout.X_AXIS));
×
NEW
71
        optionPanel.setBorder(BorderFactory.createTitledBorder("Options"));
×
72

NEW
73
        isRecursiveSearched = new JCheckBox("Recursive Search");
×
NEW
74
        isRecursiveSearched.setSelected(true);
×
NEW
75
        optionPanel.add(isRecursiveSearched);
×
NEW
76
        optionPanel.add(Box.createHorizontalGlue());
×
77

NEW
78
        add(optionPanel);
×
NEW
79
    }
×
80

81
    private void createOperationPanel() {
NEW
82
        JPanel operationPanel = new JPanel();
×
NEW
83
        operationPanel.setLayout(new BoxLayout(operationPanel, BoxLayout.X_AXIS));
×
NEW
84
        operationPanel.setBorder(BorderFactory.createTitledBorder("Operations"));
×
85

NEW
86
        startButton = new JButton("Start");
×
NEW
87
        cancelButton = new JButton("Cancel");
×
NEW
88
        cancelButton.setEnabled(false);
×
NEW
89
        startButton.addActionListener(new OperationButtonActionListener());
×
NEW
90
        cancelButton.addActionListener(new OperationButtonActionListener());
×
NEW
91
        operationPanel.add(startButton);
×
NEW
92
        operationPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
×
NEW
93
        operationPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
×
NEW
94
        operationPanel.add(cancelButton);
×
NEW
95
        operationPanel.add(Box.createHorizontalGlue());
×
96

NEW
97
        add(operationPanel);
×
NEW
98
    }
×
99

100
    private void createProcessBarPanel() {
NEW
101
        progressBar = new JProgressBar();
×
NEW
102
        progressBar.setStringPainted(true);
×
NEW
103
        progressBar.setString("Ready");
×
104

NEW
105
        add(progressBar);
×
NEW
106
    }
×
107

108
    private void processFile(File encryptedFile, File targetDir) {
109
        try {
NEW
110
            if (Thread.currentThread().isInterrupted()) {
×
NEW
111
                return;
×
112
            }
NEW
113
            PdfUtils.removePassword(encryptedFile, targetDir);
×
NEW
114
        } catch (Exception e) {
×
NEW
115
            logger.error("Process file failed: " + encryptedFile.getAbsolutePath(), e);
×
NEW
116
        } catch (Throwable t) {
×
NEW
117
            logger.error("Process file failed: " + encryptedFile.getAbsolutePath(), t);
×
NEW
118
        }
×
NEW
119
    }
×
120

NEW
121
    class OperationButtonActionListener implements ActionListener {
×
122
        @Override
123
        public void actionPerformed(ActionEvent e) {
NEW
124
            Object source = e.getSource();
×
NEW
125
            if (source.equals(startButton)) {
×
NEW
126
                startButton.setEnabled(false);
×
NEW
127
                cancelButton.setEnabled(true);
×
NEW
128
                searchThread = new WorkderThread(isRecursiveSearched.isSelected());
×
NEW
129
                searchThread.start();
×
NEW
130
            } else if (source.equals(cancelButton)) {
×
NEW
131
                startButton.setEnabled(true);
×
NEW
132
                cancelButton.setEnabled(false);
×
NEW
133
                if (searchThread.isAlive()) {
×
NEW
134
                    searchThread.interrupt();
×
NEW
135
                    searchThread.executorService.shutdownNow();
×
136
                }
137
            }
138

NEW
139
        }
×
140
    }
141

142
    class WorkderThread extends Thread {
143
        public final ExecutorService executorService;
NEW
144
        private final AtomicInteger processedFiles = new AtomicInteger(0);
×
NEW
145
        private int totalFiles = 0;
×
146
        private final boolean isRecursiveSearched;
147

NEW
148
        public WorkderThread(boolean isRecursiveSearched) {
×
NEW
149
            super();
×
NEW
150
            this.isRecursiveSearched = isRecursiveSearched;
×
NEW
151
            this.executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
×
152

NEW
153
            SwingUtilities.invokeLater(() -> {
×
NEW
154
                progressBar.setValue(0);
×
NEW
155
                progressBar.setString("Starting remove process...");
×
NEW
156
            });
×
NEW
157
        }
×
158

159
        @Override
160
        public void run() {
161
            try {
NEW
162
                List<File> fileList = fileListPanel.getFileList();
×
NEW
163
                Set<File> fileSet = new TreeSet<>();
×
NEW
164
                String[] extensions = new String[]{"pdf", "PDF"};
×
NEW
165
                for (File file : fileList) {
×
NEW
166
                    fileSet.addAll(org.apache.commons.io.FileUtils.listFiles(file, extensions, isRecursiveSearched));
×
NEW
167
                }
×
168

NEW
169
                List<Future<?>> futures = new ArrayList<>();
×
NEW
170
                totalFiles = fileSet.size();
×
NEW
171
                updateProgress();
×
172

NEW
173
                for (File file : fileSet) {
×
NEW
174
                    if (Thread.currentThread().isInterrupted()) {
×
NEW
175
                        return;
×
176
                    }
NEW
177
                    futures.add(executorService.submit(() -> {
×
NEW
178
                        if (Thread.currentThread().isInterrupted()) {
×
NEW
179
                            return null;
×
180
                        }
NEW
181
                        processFile(file, targetDirPanel.getFile());
×
NEW
182
                        incrementProcessedFiles();
×
NEW
183
                        return null;
×
184
                    }));
NEW
185
                }
×
186

187
                // Wait for all tasks to complete
NEW
188
                for (Future<?> future : futures) {
×
189
                    try {
NEW
190
                        future.get();
×
NEW
191
                    } catch (InterruptedException e) {
×
NEW
192
                        logger.error("Remove process interrupted", e);
×
NEW
193
                        Thread.currentThread().interrupt(); // Restore interrupted status
×
NEW
194
                        return;
×
NEW
195
                    }
×
NEW
196
                }
×
NEW
197
            } catch (Exception e) {
×
NEW
198
                logger.error("Remove process failed", e);
×
NEW
199
                SwingUtilities.invokeLater(() -> progressBar.setString("Remove process failed"));
×
200
            } finally {
NEW
201
                executorService.shutdown();
×
NEW
202
                SwingUtilities.invokeLater(() -> {
×
NEW
203
                    startButton.setEnabled(true);
×
NEW
204
                    cancelButton.setEnabled(false);
×
NEW
205
                });
×
206
            }
NEW
207
        }
×
208

209
        private void incrementProcessedFiles() {
NEW
210
            processedFiles.incrementAndGet();
×
NEW
211
            updateProgress();
×
NEW
212
        }
×
213

214
        private void updateProgress() {
NEW
215
            if (totalFiles > 0) {
×
NEW
216
                SwingUtilities.invokeLater(() -> {
×
NEW
217
                    int processed = processedFiles.get();
×
NEW
218
                    int percentage = (int) ((processed * 100.0) / totalFiles);
×
NEW
219
                    progressBar.setValue(percentage);
×
NEW
220
                    progressBar.setString(String.format("Processing: %d/%d files (%d%%)", processed, totalFiles, percentage));
×
NEW
221
                });
×
222
            }
NEW
223
        }
×
224
    }
225
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc