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