improved progress bar
This commit is contained in:
parent
571cf2cb68
commit
d809d9968c
@ -18,6 +18,8 @@ public class FileOperationQueue {
|
||||
private volatile OperationStatus status = OperationStatus.QUEUED;
|
||||
private volatile long currentProgress = 0;
|
||||
private volatile long totalProgress = 0;
|
||||
private volatile long currentFileProgress = 0;
|
||||
private volatile long totalFileProgress = 0;
|
||||
private volatile String currentFile = "";
|
||||
private volatile String errorMessage = "";
|
||||
|
||||
@ -32,6 +34,8 @@ public class FileOperationQueue {
|
||||
public OperationStatus getStatus() { return status; }
|
||||
public long getCurrentProgress() { return currentProgress; }
|
||||
public long getTotalProgress() { return totalProgress; }
|
||||
public long getCurrentFileProgress() { return currentFileProgress; }
|
||||
public long getTotalFileProgress() { return totalFileProgress; }
|
||||
public String getCurrentFile() { return currentFile; }
|
||||
public String getErrorMessage() { return errorMessage; }
|
||||
|
||||
@ -116,6 +120,13 @@ public class FileOperationQueue {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFileProgress(long current, long total) {
|
||||
task.currentFileProgress = current;
|
||||
task.totalFileProgress = total;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return task.status == OperationStatus.CANCELLED;
|
||||
|
||||
@ -118,6 +118,8 @@ public class FileOperations {
|
||||
}
|
||||
|
||||
private static void copyFileWithProgress(Path source, Path target, long totalItems, long[] currentItem, ProgressCallback callback) throws IOException {
|
||||
long fileSize = Files.size(source);
|
||||
long bytesCopied = 0;
|
||||
try (InputStream in = Files.newInputStream(source);
|
||||
OutputStream out = Files.newOutputStream(target)) {
|
||||
byte[] buffer = new byte[24576];
|
||||
@ -125,11 +127,16 @@ public class FileOperations {
|
||||
while ((length = in.read(buffer)) > 0) {
|
||||
if (callback != null && callback.isCancelled()) return;
|
||||
out.write(buffer, 0, length);
|
||||
bytesCopied += length;
|
||||
if (callback != null) {
|
||||
callback.onFileProgress(bytesCopied, fileSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
currentItem[0]++;
|
||||
if (callback != null) {
|
||||
callback.onProgress(currentItem[0], totalItems, source.getFileName().toString());
|
||||
callback.onFileProgress(fileSize, fileSize);
|
||||
}
|
||||
Files.setLastModifiedTime(target, Files.getLastModifiedTime(source));
|
||||
}
|
||||
@ -751,10 +758,19 @@ public class FileOperations {
|
||||
try (FileInputStream fis = new FileInputStream(fileToZip)) {
|
||||
ZipEntry zipEntry = new ZipEntry(fileName);
|
||||
zos.putNextEntry(zipEntry);
|
||||
long fileSize = fileToZip.length();
|
||||
long bytesCopied = 0;
|
||||
byte[] bytes = new byte[24576];
|
||||
int length;
|
||||
while ((length = fis.read(bytes)) >= 0) {
|
||||
zos.write(bytes, 0, length);
|
||||
bytesCopied += length;
|
||||
if (callback != null) {
|
||||
callback.onFileProgress(bytesCopied, fileSize);
|
||||
}
|
||||
}
|
||||
if (callback != null) {
|
||||
callback.onFileProgress(fileSize, fileSize);
|
||||
}
|
||||
zos.closeEntry();
|
||||
}
|
||||
@ -802,13 +818,22 @@ public class FileOperations {
|
||||
}
|
||||
|
||||
// write file content
|
||||
long fileSize = entry.getSize();
|
||||
long bytesCopied = 0;
|
||||
try (FileOutputStream fos = new FileOutputStream(newFile)) {
|
||||
byte[] buffer = new byte[24576];
|
||||
int len;
|
||||
while ((len = zis.read(buffer)) > 0) {
|
||||
fos.write(buffer, 0, len);
|
||||
bytesCopied += len;
|
||||
if (callback != null && fileSize > 0) {
|
||||
callback.onFileProgress(bytesCopied, fileSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (callback != null && fileSize > 0) {
|
||||
callback.onFileProgress(fileSize, fileSize);
|
||||
}
|
||||
}
|
||||
zis.closeEntry();
|
||||
}
|
||||
@ -830,6 +855,7 @@ public class FileOperations {
|
||||
|
||||
public interface ProgressCallback {
|
||||
void onProgress(long current, long total, String currentFile);
|
||||
default void onFileProgress(long current, long total) {}
|
||||
default boolean isCancelled() { return false; }
|
||||
default OverwriteResponse confirmOverwrite(File file) { return OverwriteResponse.YES; }
|
||||
default ErrorResponse onError(File file, Exception e) { return ErrorResponse.ABORT; }
|
||||
|
||||
@ -1898,6 +1898,11 @@ public class FilePanelTab extends JPanel {
|
||||
progressDialog.updateProgress(current, total, currentFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFileProgress(long current, long total) {
|
||||
progressDialog.updateFileProgress(current, total);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return progressDialog.isCancelled();
|
||||
|
||||
@ -2139,7 +2139,6 @@ public class MainWindow extends JFrame {
|
||||
*/
|
||||
private void performFileOperation(FileOperation operation, String successMessage, boolean showBytes, boolean modal, Runnable postTask, FilePanel... panelsToRefresh) {
|
||||
ProgressDialog progressDialog = new ProgressDialog(this, "File Operation", modal);
|
||||
progressDialog.setDisplayAsBytes(showBytes);
|
||||
|
||||
FileOperations.ProgressCallback callback = new FileOperations.ProgressCallback() {
|
||||
@Override
|
||||
@ -2147,6 +2146,11 @@ public class MainWindow extends JFrame {
|
||||
progressDialog.updateProgress(current, total, currentFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFileProgress(long current, long total) {
|
||||
progressDialog.updateFileProgress(current, total);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return progressDialog.isCancelled();
|
||||
|
||||
@ -4,9 +4,11 @@ import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.util.LinkedList;
|
||||
|
||||
public class ProgressDialog extends JDialog {
|
||||
private final JProgressBar progressBar;
|
||||
private final JProgressBar fileProgressBar;
|
||||
private final JLabel statusLabel;
|
||||
private final JLabel speedLabel;
|
||||
private final JButton pauseButton;
|
||||
@ -15,6 +17,12 @@ public class ProgressDialog extends JDialog {
|
||||
private volatile boolean cancelled = false;
|
||||
private volatile boolean paused = false;
|
||||
private long startTime = -1;
|
||||
private long totalBytesProcessed = 0;
|
||||
private long lastFileBytes = 0;
|
||||
private final LinkedList<long[]> speedSamples = new LinkedList<>();
|
||||
private static final int MAX_SAMPLES = 10;
|
||||
private static final long SAMPLE_INTERVAL_MS = 200;
|
||||
private long lastSampleTime = -1;
|
||||
|
||||
public ProgressDialog(Frame owner, String title) {
|
||||
this(owner, title, true);
|
||||
@ -28,15 +36,23 @@ public class ProgressDialog extends JDialog {
|
||||
|
||||
JPanel infoPanel = new JPanel(new GridLayout(2, 1, 5, 5));
|
||||
statusLabel = new JLabel("Starting...");
|
||||
speedLabel = new JLabel("Speed: 0 B/s");
|
||||
speedLabel = new JLabel(" ");
|
||||
infoPanel.add(statusLabel);
|
||||
infoPanel.add(speedLabel);
|
||||
add(infoPanel, BorderLayout.NORTH);
|
||||
|
||||
JPanel progressPanel = new JPanel(new GridLayout(2, 1, 5, 5));
|
||||
progressBar = new JProgressBar(0, 100);
|
||||
progressBar.setStringPainted(true);
|
||||
progressBar.setPreferredSize(new Dimension(400, 25));
|
||||
add(progressBar, BorderLayout.CENTER);
|
||||
progressPanel.add(progressBar);
|
||||
|
||||
fileProgressBar = new JProgressBar(0, 100);
|
||||
fileProgressBar.setStringPainted(true);
|
||||
fileProgressBar.setPreferredSize(new Dimension(400, 25));
|
||||
progressPanel.add(fileProgressBar);
|
||||
|
||||
add(progressPanel, BorderLayout.CENTER);
|
||||
|
||||
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
|
||||
pauseButton = new JButton("Pause");
|
||||
@ -83,37 +99,20 @@ public class ProgressDialog extends JDialog {
|
||||
cancelled = true;
|
||||
}
|
||||
|
||||
private boolean displayAsBytes = false;
|
||||
|
||||
public void setDisplayAsBytes(boolean displayAsBytes) {
|
||||
this.displayAsBytes = displayAsBytes;
|
||||
}
|
||||
|
||||
public void updateProgress(long current, long total, String fileName) {
|
||||
if (startTime == -1) {
|
||||
startTime = System.currentTimeMillis();
|
||||
}
|
||||
lastFileBytes = 0;
|
||||
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
if (total > 0) {
|
||||
progressBar.setIndeterminate(false);
|
||||
int percent = (int) Math.min(100, ((double) current / total * 100));
|
||||
progressBar.setValue(percent);
|
||||
if (displayAsBytes) {
|
||||
progressBar.setString(formatSize(Math.min(current, total)) + " / " + formatSize(total) + " (" + percent + "%)");
|
||||
|
||||
long elapsed = System.currentTimeMillis() - startTime;
|
||||
if (elapsed > 0) {
|
||||
long bytesPerSec = (long) (current / (elapsed / 1000.0));
|
||||
speedLabel.setText("Speed: " + formatSize(bytesPerSec) + "/s");
|
||||
}
|
||||
} else {
|
||||
progressBar.setString(current + " / " + total + " (" + percent + "%)");
|
||||
speedLabel.setText("");
|
||||
}
|
||||
progressBar.setString("Total: " + current + " / " + total + " (" + percent + "%)");
|
||||
} else {
|
||||
progressBar.setIndeterminate(true);
|
||||
speedLabel.setText("");
|
||||
}
|
||||
statusLabel.setText(fileName);
|
||||
});
|
||||
@ -121,6 +120,55 @@ public class ProgressDialog extends JDialog {
|
||||
checkState();
|
||||
}
|
||||
|
||||
public void updateFileProgress(long current, long total) {
|
||||
long currentTime = System.currentTimeMillis();
|
||||
if (startTime == -1) {
|
||||
startTime = currentTime;
|
||||
lastSampleTime = startTime;
|
||||
speedSamples.add(new long[]{startTime, 0});
|
||||
}
|
||||
|
||||
long delta = current - lastFileBytes;
|
||||
if (delta > 0) {
|
||||
totalBytesProcessed += delta;
|
||||
}
|
||||
lastFileBytes = current;
|
||||
if (current >= total) {
|
||||
lastFileBytes = 0;
|
||||
}
|
||||
|
||||
if (currentTime - lastSampleTime >= SAMPLE_INTERVAL_MS) {
|
||||
speedSamples.add(new long[]{currentTime, totalBytesProcessed});
|
||||
while (speedSamples.size() > MAX_SAMPLES) {
|
||||
speedSamples.removeFirst();
|
||||
}
|
||||
lastSampleTime = currentTime;
|
||||
}
|
||||
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
if (total > 0) {
|
||||
fileProgressBar.setIndeterminate(false);
|
||||
int percent = (int) Math.min(100, ((double) current / total * 100));
|
||||
fileProgressBar.setValue(percent);
|
||||
fileProgressBar.setString("File: " + formatSize(Math.min(current, total)) + " / " + formatSize(total) + " (" + percent + "%)");
|
||||
|
||||
if (speedSamples.size() >= 2) {
|
||||
long[] first = speedSamples.getFirst();
|
||||
long[] last = speedSamples.getLast();
|
||||
long timeDiff = last[0] - first[0];
|
||||
long byteDiff = last[1] - first[1];
|
||||
if (timeDiff > 0) {
|
||||
long bytesPerSec = (long) (byteDiff / (timeDiff / 1000.0));
|
||||
speedLabel.setText("Speed: " + formatSize(bytesPerSec) + "/s");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fileProgressBar.setIndeterminate(true);
|
||||
fileProgressBar.setString("");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private String formatSize(long bytes) {
|
||||
if (bytes < 1024) return bytes + " B";
|
||||
int exp = (int) (Math.log(bytes) / Math.log(1024));
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user