progress dialog added
This commit is contained in:
parent
2e2f4bd4f5
commit
69afa0c738
@ -23,26 +23,84 @@ public class FileOperations {
|
|||||||
throw new IOException("Target directory does not exist");
|
throw new IOException("Target directory does not exist");
|
||||||
}
|
}
|
||||||
|
|
||||||
int current = 0;
|
long totalSize = calculateTotalSize(items);
|
||||||
int total = items.size();
|
final long[] currentCopied = {0};
|
||||||
|
|
||||||
for (FileItem item : items) {
|
for (FileItem item : items) {
|
||||||
current++;
|
if (callback != null && callback.isCancelled()) break;
|
||||||
File source = item.getFile();
|
File source = item.getFile();
|
||||||
File target = new File(targetDirectory, source.getName());
|
File target = new File(targetDirectory, source.getName());
|
||||||
|
|
||||||
if (callback != null) {
|
|
||||||
callback.onProgress(current, total, source.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (source.isDirectory()) {
|
if (source.isDirectory()) {
|
||||||
copyDirectory(source.toPath(), target.toPath());
|
copyDirectory(source.toPath(), target.toPath(), totalSize, currentCopied, callback);
|
||||||
} else {
|
} else {
|
||||||
copyFile(source.toPath(), target.toPath());
|
copyFileWithProgress(source.toPath(), target.toPath(), totalSize, currentCopied, callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static long calculateTotalSize(List<FileItem> items) {
|
||||||
|
long total = 0;
|
||||||
|
for (FileItem item : items) {
|
||||||
|
total += calculateSize(item.getFile().toPath());
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long calculateSize(Path path) {
|
||||||
|
if (!Files.exists(path)) return 0;
|
||||||
|
if (!Files.isDirectory(path)) {
|
||||||
|
try { return Files.size(path); } catch (IOException e) { return 0; }
|
||||||
|
}
|
||||||
|
final long[] size = {0};
|
||||||
|
try {
|
||||||
|
Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
|
||||||
|
@Override
|
||||||
|
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
|
||||||
|
size[0] += attrs.size();
|
||||||
|
return FileVisitResult.CONTINUE;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (IOException ignore) {}
|
||||||
|
return size[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void copyFileWithProgress(Path source, Path target, long totalSize, long[] totalCopied, ProgressCallback callback) throws IOException {
|
||||||
|
try (InputStream in = Files.newInputStream(source);
|
||||||
|
OutputStream out = Files.newOutputStream(target)) {
|
||||||
|
byte[] buffer = new byte[8192];
|
||||||
|
int length;
|
||||||
|
while ((length = in.read(buffer)) > 0) {
|
||||||
|
if (callback != null && callback.isCancelled()) return;
|
||||||
|
out.write(buffer, 0, length);
|
||||||
|
totalCopied[0] += length;
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onProgress(totalCopied[0], totalSize, source.getFileName().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Files.setLastModifiedTime(target, Files.getLastModifiedTime(source));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void copyDirectory(Path source, Path target, long totalSize, final long[] totalCopied, ProgressCallback callback) throws IOException {
|
||||||
|
Files.walkFileTree(source, new SimpleFileVisitor<Path>() {
|
||||||
|
@Override
|
||||||
|
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
|
||||||
|
Path targetDir = target.resolve(source.relativize(dir));
|
||||||
|
Files.createDirectories(targetDir);
|
||||||
|
return FileVisitResult.CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||||
|
if (callback != null && callback.isCancelled()) return FileVisitResult.TERMINATE;
|
||||||
|
Path targetFile = target.resolve(source.relativize(file));
|
||||||
|
copyFileWithProgress(file, targetFile, totalSize, totalCopied, callback);
|
||||||
|
return FileVisitResult.CONTINUE;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move files/directories to target directory
|
* Move files/directories to target directory
|
||||||
*/
|
*/
|
||||||
@ -55,6 +113,7 @@ public class FileOperations {
|
|||||||
int total = items.size();
|
int total = items.size();
|
||||||
|
|
||||||
for (FileItem item : items) {
|
for (FileItem item : items) {
|
||||||
|
if (callback != null && callback.isCancelled()) break;
|
||||||
current++;
|
current++;
|
||||||
File source = item.getFile();
|
File source = item.getFile();
|
||||||
File target = new File(targetDirectory, source.getName());
|
File target = new File(targetDirectory, source.getName());
|
||||||
@ -75,6 +134,7 @@ public class FileOperations {
|
|||||||
int total = items.size();
|
int total = items.size();
|
||||||
|
|
||||||
for (FileItem item : items) {
|
for (FileItem item : items) {
|
||||||
|
if (callback != null && callback.isCancelled()) break;
|
||||||
current++;
|
current++;
|
||||||
File file = item.getFile();
|
File file = item.getFile();
|
||||||
|
|
||||||
@ -108,34 +168,6 @@ public class FileOperations {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy a file
|
|
||||||
*/
|
|
||||||
private static void copyFile(Path source, Path target) throws IOException {
|
|
||||||
Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy directory recursively
|
|
||||||
*/
|
|
||||||
private static void copyDirectory(Path source, Path target) throws IOException {
|
|
||||||
Files.walkFileTree(source, new SimpleFileVisitor<Path>() {
|
|
||||||
@Override
|
|
||||||
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
|
|
||||||
Path targetDir = target.resolve(source.relativize(dir));
|
|
||||||
Files.createDirectories(targetDir);
|
|
||||||
return FileVisitResult.CONTINUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
|
||||||
Path targetFile = target.resolve(source.relativize(file));
|
|
||||||
copyFile(file, targetFile);
|
|
||||||
return FileVisitResult.CONTINUE;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete directory recursively
|
* Delete directory recursively
|
||||||
*/
|
*/
|
||||||
@ -243,8 +275,8 @@ public class FileOperations {
|
|||||||
*/
|
*/
|
||||||
public static void zip(List<FileItem> items, File targetZipFile, ProgressCallback callback) throws IOException {
|
public static void zip(List<FileItem> items, File targetZipFile, ProgressCallback callback) throws IOException {
|
||||||
try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(targetZipFile))) {
|
try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(targetZipFile))) {
|
||||||
int current = 0;
|
long current = 0;
|
||||||
int total = items.size();
|
long total = items.size();
|
||||||
|
|
||||||
for (FileItem item : items) {
|
for (FileItem item : items) {
|
||||||
current++;
|
current++;
|
||||||
@ -304,7 +336,7 @@ public class FileOperations {
|
|||||||
File newFile = new File(targetDirectory, entry.getName());
|
File newFile = new File(targetDirectory, entry.getName());
|
||||||
|
|
||||||
if (callback != null) {
|
if (callback != null) {
|
||||||
callback.onProgress(0, 0, entry.getName());
|
callback.onProgress(0L, 0L, entry.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry.isDirectory()) {
|
if (entry.isDirectory()) {
|
||||||
@ -338,7 +370,8 @@ public class FileOperations {
|
|||||||
* Callback pro progress operací
|
* Callback pro progress operací
|
||||||
*/
|
*/
|
||||||
public interface ProgressCallback {
|
public interface ProgressCallback {
|
||||||
void onProgress(int current, int total, String currentFile);
|
void onProgress(long current, long total, String currentFile);
|
||||||
|
default boolean isCancelled() { return false; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -955,15 +955,35 @@ public class FilePanelTab extends JPanel {
|
|||||||
JOptionPane.YES_NO_OPTION,
|
JOptionPane.YES_NO_OPTION,
|
||||||
JOptionPane.WARNING_MESSAGE);
|
JOptionPane.WARNING_MESSAGE);
|
||||||
if (res == JOptionPane.YES_OPTION) {
|
if (res == JOptionPane.YES_OPTION) {
|
||||||
try {
|
java.util.List<FileItem> toDelete = new java.util.ArrayList<>();
|
||||||
java.util.List<FileItem> toDelete = new java.util.ArrayList<>();
|
toDelete.add(item);
|
||||||
toDelete.add(item);
|
Window parentWindow = SwingUtilities.getWindowAncestor(FilePanelTab.this);
|
||||||
com.kfmanager.service.FileOperations.delete(toDelete, null);
|
ProgressDialog progressDialog = new ProgressDialog(parentWindow instanceof Frame ? (Frame)parentWindow : null, "Deleting");
|
||||||
// reload current directory
|
|
||||||
loadDirectory(getCurrentDirectory());
|
new Thread(() -> {
|
||||||
} catch (Exception ex) {
|
try {
|
||||||
try { JOptionPane.showMessageDialog(FilePanelTab.this, "Delete failed: " + ex.getMessage()); } catch (Exception ignore) {}
|
com.kfmanager.service.FileOperations.delete(toDelete, new com.kfmanager.service.FileOperations.ProgressCallback() {
|
||||||
}
|
@Override
|
||||||
|
public void onProgress(long current, long total, String currentFile) {
|
||||||
|
progressDialog.updateProgress(current, total, currentFile);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean isCancelled() {
|
||||||
|
return progressDialog.isCancelled();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
SwingUtilities.invokeLater(() -> {
|
||||||
|
progressDialog.dispose();
|
||||||
|
loadDirectory(getCurrentDirectory());
|
||||||
|
});
|
||||||
|
} catch (Exception ex) {
|
||||||
|
SwingUtilities.invokeLater(() -> {
|
||||||
|
progressDialog.dispose();
|
||||||
|
JOptionPane.showMessageDialog(FilePanelTab.this, "Delete failed: " + ex.getMessage());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
progressDialog.setVisible(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
menu.add(deleteItem);
|
menu.add(deleteItem);
|
||||||
|
|||||||
@ -652,9 +652,9 @@ public class MainWindow extends JFrame {
|
|||||||
JOptionPane.OK_CANCEL_OPTION);
|
JOptionPane.OK_CANCEL_OPTION);
|
||||||
|
|
||||||
if (result == JOptionPane.OK_OPTION) {
|
if (result == JOptionPane.OK_OPTION) {
|
||||||
performFileOperation(() -> {
|
performFileOperation((callback) -> {
|
||||||
FileOperations.copy(selectedItems, targetDir, null);
|
FileOperations.copy(selectedItems, targetDir, callback);
|
||||||
}, "Kopírování dokončeno", targetPanel);
|
}, "Kopírování dokončeno", true, targetPanel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -680,9 +680,9 @@ public class MainWindow extends JFrame {
|
|||||||
JOptionPane.OK_CANCEL_OPTION);
|
JOptionPane.OK_CANCEL_OPTION);
|
||||||
|
|
||||||
if (result == JOptionPane.OK_OPTION) {
|
if (result == JOptionPane.OK_OPTION) {
|
||||||
performFileOperation(() -> {
|
performFileOperation((callback) -> {
|
||||||
FileOperations.move(selectedItems, targetDir, null);
|
FileOperations.move(selectedItems, targetDir, callback);
|
||||||
}, "Přesouvání dokončeno", activePanel, targetPanel);
|
}, "Přesouvání dokončeno", false, activePanel, targetPanel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -718,9 +718,9 @@ public class MainWindow extends JFrame {
|
|||||||
JOptionPane.WARNING_MESSAGE);
|
JOptionPane.WARNING_MESSAGE);
|
||||||
|
|
||||||
if (result == JOptionPane.YES_OPTION) {
|
if (result == JOptionPane.YES_OPTION) {
|
||||||
performFileOperation(() -> {
|
performFileOperation((callback) -> {
|
||||||
FileOperations.delete(selectedItems, null);
|
FileOperations.delete(selectedItems, callback);
|
||||||
}, "Mazání dokončeno", activePanel);
|
}, "Mazání dokončeno", false, activePanel);
|
||||||
|
|
||||||
// After deletion and refresh, restore selection: stay on same row if possible,
|
// After deletion and refresh, restore selection: stay on same row if possible,
|
||||||
// otherwise move selection one row up.
|
// otherwise move selection one row up.
|
||||||
@ -793,9 +793,9 @@ public class MainWindow extends JFrame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final File finalTargetZip = targetZip;
|
final File finalTargetZip = targetZip;
|
||||||
performFileOperation(() -> {
|
performFileOperation((callback) -> {
|
||||||
FileOperations.zip(selectedItems, finalTargetZip, null);
|
FileOperations.zip(selectedItems, finalTargetZip, callback);
|
||||||
}, "Zabaleno do " + zipName, targetPanel);
|
}, "Zabaleno do " + zipName, false, targetPanel);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -829,9 +829,9 @@ public class MainWindow extends JFrame {
|
|||||||
JOptionPane.OK_CANCEL_OPTION);
|
JOptionPane.OK_CANCEL_OPTION);
|
||||||
|
|
||||||
if (result == JOptionPane.OK_OPTION) {
|
if (result == JOptionPane.OK_OPTION) {
|
||||||
performFileOperation(() -> {
|
performFileOperation((callback) -> {
|
||||||
FileOperations.unzip(zipFile, targetDir, null);
|
FileOperations.unzip(zipFile, targetDir, callback);
|
||||||
}, "Rozbaleno do " + targetDir.getName(), targetPanel);
|
}, "Rozbaleno do " + targetDir.getName(), false, targetPanel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -858,9 +858,9 @@ public class MainWindow extends JFrame {
|
|||||||
"New name:",
|
"New name:",
|
||||||
item.getName());
|
item.getName());
|
||||||
if (newName != null && !newName.trim().isEmpty() && !newName.equals(item.getName())) {
|
if (newName != null && !newName.trim().isEmpty() && !newName.equals(item.getName())) {
|
||||||
performFileOperation(() -> {
|
performFileOperation((callback) -> {
|
||||||
FileOperations.rename(item.getFile(), newName.trim());
|
FileOperations.rename(item.getFile(), newName.trim());
|
||||||
}, "Přejmenování dokončeno", activePanel);
|
}, "Přejmenování dokončeno", false, activePanel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -875,9 +875,9 @@ public class MainWindow extends JFrame {
|
|||||||
"New directory");
|
"New directory");
|
||||||
|
|
||||||
if (dirName != null && !dirName.trim().isEmpty()) {
|
if (dirName != null && !dirName.trim().isEmpty()) {
|
||||||
performFileOperation(() -> {
|
performFileOperation((callback) -> {
|
||||||
FileOperations.createDirectory(activePanel.getCurrentDirectory(), dirName.trim());
|
FileOperations.createDirectory(activePanel.getCurrentDirectory(), dirName.trim());
|
||||||
}, "Directory created", activePanel);
|
}, "Directory created", false, activePanel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1066,21 +1066,50 @@ public class MainWindow extends JFrame {
|
|||||||
/**
|
/**
|
||||||
* Execute file operation with error handling
|
* Execute file operation with error handling
|
||||||
*/
|
*/
|
||||||
private void performFileOperation(FileOperation operation, String successMessage, FilePanel... panelsToRefresh) {
|
private void performFileOperation(FileOperation operation, String successMessage, boolean showBytes, FilePanel... panelsToRefresh) {
|
||||||
try {
|
ProgressDialog progressDialog = new ProgressDialog(this, "Operační systém");
|
||||||
operation.execute();
|
progressDialog.setDisplayAsBytes(showBytes);
|
||||||
for (FilePanel panel : panelsToRefresh) {
|
|
||||||
if (panel.getCurrentDirectory() != null) {
|
FileOperations.ProgressCallback callback = new FileOperations.ProgressCallback() {
|
||||||
panel.loadDirectory(panel.getCurrentDirectory());
|
@Override
|
||||||
}
|
public void onProgress(long current, long total, String currentFile) {
|
||||||
|
progressDialog.updateProgress(current, total, currentFile);
|
||||||
}
|
}
|
||||||
// Info okna o úspěchu zrušena - operace proběhne tiše
|
|
||||||
} catch (Exception e) {
|
@Override
|
||||||
JOptionPane.showMessageDialog(this,
|
public boolean isCancelled() {
|
||||||
"Chyba: " + e.getMessage(),
|
return progressDialog.isCancelled();
|
||||||
"Chyba",
|
}
|
||||||
JOptionPane.ERROR_MESSAGE);
|
};
|
||||||
}
|
|
||||||
|
// Run operation in a background thread
|
||||||
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
|
operation.execute(callback);
|
||||||
|
|
||||||
|
SwingUtilities.invokeLater(() -> {
|
||||||
|
progressDialog.dispose();
|
||||||
|
for (FilePanel panel : panelsToRefresh) {
|
||||||
|
if (panel.getCurrentDirectory() != null) {
|
||||||
|
panel.loadDirectory(panel.getCurrentDirectory());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (callback.isCancelled()) {
|
||||||
|
JOptionPane.showMessageDialog(MainWindow.this, "Operace byla přerušena uživatelem.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
SwingUtilities.invokeLater(() -> {
|
||||||
|
progressDialog.dispose();
|
||||||
|
JOptionPane.showMessageDialog(MainWindow.this,
|
||||||
|
"Chyba: " + e.getMessage(),
|
||||||
|
"Chyba",
|
||||||
|
JOptionPane.ERROR_MESSAGE);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
|
||||||
|
progressDialog.setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1142,6 +1171,6 @@ public class MainWindow extends JFrame {
|
|||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
private interface FileOperation {
|
private interface FileOperation {
|
||||||
void execute() throws Exception;
|
void execute(FileOperations.ProgressCallback callback) throws Exception;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
141
src/main/java/com/kfmanager/ui/ProgressDialog.java
Normal file
141
src/main/java/com/kfmanager/ui/ProgressDialog.java
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
package com.kfmanager.ui;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.WindowAdapter;
|
||||||
|
import java.awt.event.WindowEvent;
|
||||||
|
|
||||||
|
public class ProgressDialog extends JDialog {
|
||||||
|
private final JProgressBar progressBar;
|
||||||
|
private final JLabel statusLabel;
|
||||||
|
private final JLabel speedLabel;
|
||||||
|
private final JButton pauseButton;
|
||||||
|
private final JButton cancelButton;
|
||||||
|
|
||||||
|
private volatile boolean cancelled = false;
|
||||||
|
private volatile boolean paused = false;
|
||||||
|
private long startTime = -1;
|
||||||
|
|
||||||
|
public ProgressDialog(Frame owner, String title) {
|
||||||
|
super(owner, title, true);
|
||||||
|
|
||||||
|
setLayout(new BorderLayout(10, 10));
|
||||||
|
((JPanel)getContentPane()).setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));
|
||||||
|
|
||||||
|
JPanel infoPanel = new JPanel(new GridLayout(2, 1, 5, 5));
|
||||||
|
statusLabel = new JLabel("Starting...");
|
||||||
|
speedLabel = new JLabel("Speed: 0 B/s");
|
||||||
|
infoPanel.add(statusLabel);
|
||||||
|
infoPanel.add(speedLabel);
|
||||||
|
add(infoPanel, BorderLayout.NORTH);
|
||||||
|
|
||||||
|
progressBar = new JProgressBar(0, 100);
|
||||||
|
progressBar.setStringPainted(true);
|
||||||
|
progressBar.setPreferredSize(new Dimension(400, 25));
|
||||||
|
add(progressBar, BorderLayout.CENTER);
|
||||||
|
|
||||||
|
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
|
||||||
|
pauseButton = new JButton("Pause");
|
||||||
|
cancelButton = new JButton("Cancel");
|
||||||
|
|
||||||
|
pauseButton.addActionListener(e -> {
|
||||||
|
paused = !paused;
|
||||||
|
pauseButton.setText(paused ? "Resume" : "Pause");
|
||||||
|
if (!paused) {
|
||||||
|
synchronized(this) {
|
||||||
|
this.notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
cancelButton.addActionListener(e -> {
|
||||||
|
cancelled = true;
|
||||||
|
paused = false;
|
||||||
|
cancelButton.setEnabled(false);
|
||||||
|
statusLabel.setText("Cancelling...");
|
||||||
|
synchronized(this) {
|
||||||
|
this.notifyAll();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
buttonPanel.add(pauseButton);
|
||||||
|
buttonPanel.add(cancelButton);
|
||||||
|
add(buttonPanel, BorderLayout.SOUTH);
|
||||||
|
|
||||||
|
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
|
||||||
|
addWindowListener(new WindowAdapter() {
|
||||||
|
@Override
|
||||||
|
public void windowClosing(WindowEvent e) {
|
||||||
|
cancelled = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
pack();
|
||||||
|
setMinimumSize(new Dimension(450, getHeight()));
|
||||||
|
setLocationRelativeTo(owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
SwingUtilities.invokeLater(() -> {
|
||||||
|
if (total > 0) {
|
||||||
|
progressBar.setIndeterminate(false);
|
||||||
|
int percent = (int) ((double) current / total * 100);
|
||||||
|
progressBar.setValue(percent);
|
||||||
|
if (displayAsBytes) {
|
||||||
|
progressBar.setString(formatSize(current) + " / " + 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 {
|
||||||
|
progressBar.setIndeterminate(true);
|
||||||
|
speedLabel.setText("");
|
||||||
|
}
|
||||||
|
statusLabel.setText(fileName);
|
||||||
|
});
|
||||||
|
|
||||||
|
checkState();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String formatSize(long bytes) {
|
||||||
|
if (bytes < 1024) return bytes + " B";
|
||||||
|
int exp = (int) (Math.log(bytes) / Math.log(1024));
|
||||||
|
char pre = "KMGTPE".charAt(exp - 1);
|
||||||
|
return String.format("%.1f %cB", bytes / Math.pow(1024, exp), pre);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkState() {
|
||||||
|
if (paused && !cancelled) {
|
||||||
|
synchronized(this) {
|
||||||
|
while (paused && !cancelled) {
|
||||||
|
try {
|
||||||
|
this.wait(100);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCancelled() {
|
||||||
|
return cancelled;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user