mirror of
https://github.com/SKCraft/Launcher.git
synced 2024-11-27 12:46:22 +01:00
Add progress bars
This commit is contained in:
parent
badd91d2b8
commit
9640cd8dcf
@ -6,6 +6,7 @@ import com.google.common.util.concurrent.Futures;
|
|||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||||
import com.skcraft.concurrency.DefaultProgress;
|
import com.skcraft.concurrency.DefaultProgress;
|
||||||
|
import com.skcraft.concurrency.ObservableFuture;
|
||||||
import com.skcraft.launcher.creator.model.creator.Pack;
|
import com.skcraft.launcher.creator.model.creator.Pack;
|
||||||
import com.skcraft.launcher.creator.plugin.MenuContext;
|
import com.skcraft.launcher.creator.plugin.MenuContext;
|
||||||
import com.skcraft.launcher.creator.plugin.PluginMenu;
|
import com.skcraft.launcher.creator.plugin.PluginMenu;
|
||||||
@ -28,6 +29,7 @@ import java.awt.event.ActionEvent;
|
|||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
@ -39,14 +41,17 @@ public class CurseModsDialog extends JDialog {
|
|||||||
private final CursePack cursePack;
|
private final CursePack cursePack;
|
||||||
|
|
||||||
private final JPanel panel = new JPanel(new BorderLayout(0, 5));
|
private final JPanel panel = new JPanel(new BorderLayout(0, 5));
|
||||||
|
private final JLabel title = new JLabel("Search for mods on CurseForge:");
|
||||||
private final JTextField searchBox = new JTextField();
|
private final JTextField searchBox = new JTextField();
|
||||||
private final JButton searchButton = new JButton("Search");
|
private final JButton searchButton = new JButton("Search");
|
||||||
|
private final JProgressBar progressBar = new JProgressBar(0, 1000);
|
||||||
private final JList<CurseProject> searchPane = new JList<>();
|
private final JList<CurseProject> searchPane = new JList<>();
|
||||||
private final JList<AddedMod> selectedPane = new JList<>();
|
private final JList<AddedMod> selectedPane = new JList<>();
|
||||||
private final JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, new JScrollPane(searchPane), new JScrollPane(selectedPane));
|
private final JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, new JScrollPane(searchPane), new JScrollPane(selectedPane));
|
||||||
private final JButton addMod = new JButton("Add Mods >>");
|
private final JButton addMod = new JButton("Add Mods >>");
|
||||||
private final JButton removeMod = new JButton("<< Remove Mods");
|
private final JButton removeMod = new JButton("<< Remove Mods");
|
||||||
private final JButton done = new JButton("Done");
|
private final JButton done = new JButton("Done");
|
||||||
|
private Timer activeTimer;
|
||||||
|
|
||||||
private final CurseProjectListRenderer projectRenderer = new CurseProjectListRenderer();
|
private final CurseProjectListRenderer projectRenderer = new CurseProjectListRenderer();
|
||||||
|
|
||||||
@ -94,10 +99,17 @@ public class CurseModsDialog extends JDialog {
|
|||||||
buttonsPanel.addElement(removeMod);
|
buttonsPanel.addElement(removeMod);
|
||||||
buttonsPanel.setAlignmentX(CENTER_ALIGNMENT);
|
buttonsPanel.setAlignmentX(CENTER_ALIGNMENT);
|
||||||
|
|
||||||
panel.add(searchBarPanel, BorderLayout.NORTH);
|
LinedBoxPanel topPanel = new LinedBoxPanel(false);
|
||||||
|
topPanel.addElement(title);
|
||||||
|
topPanel.addElement(searchBarPanel);
|
||||||
|
topPanel.addElement(progressBar);
|
||||||
|
topPanel.setAlignmentX(CENTER_ALIGNMENT);
|
||||||
|
|
||||||
|
panel.add(topPanel, BorderLayout.NORTH);
|
||||||
panel.add(Box.createVerticalStrut(5));
|
panel.add(Box.createVerticalStrut(5));
|
||||||
panel.add(splitPane, BorderLayout.CENTER);
|
panel.add(splitPane, BorderLayout.CENTER);
|
||||||
panel.add(buttonsPanel, BorderLayout.SOUTH);
|
panel.add(buttonsPanel, BorderLayout.SOUTH);
|
||||||
|
panel.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0));
|
||||||
|
|
||||||
add(panel);
|
add(panel);
|
||||||
|
|
||||||
@ -105,24 +117,41 @@ public class CurseModsDialog extends JDialog {
|
|||||||
searchButton.addActionListener(e -> search());
|
searchButton.addActionListener(e -> search());
|
||||||
|
|
||||||
addMod.addActionListener(e -> {
|
addMod.addActionListener(e -> {
|
||||||
ListenableFuture<Object> future = executor.submit(cursePack.addMany(searchPane.getSelectedValuesList()));
|
CursePack.AddModsCall call = cursePack.addMany(searchPane.getSelectedValuesList());
|
||||||
|
ListenableFuture<Object> future = executor.submit(call);
|
||||||
|
|
||||||
// TODO: Update a progress bar built in to the dialog.
|
setProgressItem(new ObservableFuture<>(future, call));
|
||||||
SwingHelper.addErrorDialogCallback(getOwner(), future);
|
SwingHelper.addErrorDialogCallback(getOwner(), future);
|
||||||
});
|
});
|
||||||
|
|
||||||
removeMod.addActionListener(e -> {
|
removeMod.addActionListener(e -> {
|
||||||
ListenableFuture<Object> future = executor.submit(
|
CursePack.RemoveModsCall call = cursePack.removeMany(selectedPane.getSelectedValuesList());
|
||||||
cursePack.removeMany(selectedPane.getSelectedValuesList()));
|
ListenableFuture<Object> future = executor.submit(call);
|
||||||
|
|
||||||
|
setProgressItem(new ObservableFuture<>(future, call));
|
||||||
SwingHelper.addErrorDialogCallback(getOwner(), future);
|
SwingHelper.addErrorDialogCallback(getOwner(), future);
|
||||||
});
|
});
|
||||||
|
|
||||||
done.addActionListener(e -> dispose());
|
done.addActionListener(e -> dispose());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setProgressItem(ObservableFuture<?> observable) {
|
||||||
|
if (activeTimer != null) {
|
||||||
|
activeTimer.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
activeTimer = new Timer(400, e -> progressBar.setValue((int) (1000 * observable.getProgress())));
|
||||||
|
activeTimer.setInitialDelay(0);
|
||||||
|
activeTimer.start();
|
||||||
|
|
||||||
|
observable.addListener(() -> activeTimer.stop(), SwingExecutor.INSTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
|
if (activeTimer != null) {
|
||||||
|
activeTimer.stop();
|
||||||
|
}
|
||||||
// Let's make sure the image cache is emptied
|
// Let's make sure the image cache is emptied
|
||||||
projectRenderer.clearCache();
|
projectRenderer.clearCache();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
@ -173,16 +202,24 @@ public class CurseModsDialog extends JDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static class CurseProjectListRenderer extends JLabel implements ListCellRenderer<ProjectHolder> {
|
private static class CurseProjectListRenderer extends JLabel implements ListCellRenderer<ProjectHolder> {
|
||||||
private HashMap<String, BufferedImage> cache;
|
private final HashMap<String, BufferedImage> cache;
|
||||||
|
private final HashSet<String> pending;
|
||||||
|
|
||||||
public CurseProjectListRenderer() {
|
public CurseProjectListRenderer() {
|
||||||
this.cache = new HashMap<>();
|
this.cache = new HashMap<>();
|
||||||
|
this.pending = new HashSet<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private BufferedImage getCachedIcon(String imgUrl, Runnable cb) {
|
private BufferedImage getCachedIcon(String imgUrl, Runnable cb) {
|
||||||
if (!cache.containsKey(imgUrl)) {
|
if (!cache.containsKey(imgUrl)) {
|
||||||
|
if (pending.contains(imgUrl)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
pending.add(imgUrl);
|
||||||
ImageWorker.downloadImage(imgUrl, img -> {
|
ImageWorker.downloadImage(imgUrl, img -> {
|
||||||
cache.put(imgUrl, img);
|
cache.put(imgUrl, img);
|
||||||
|
pending.remove(imgUrl);
|
||||||
cb.run();
|
cb.run();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -261,9 +298,11 @@ public class CurseModsDialog extends JDialog {
|
|||||||
ListenableFuture<?> future = ctx.getExecutor().submit(() -> {
|
ListenableFuture<?> future = ctx.getExecutor().submit(() -> {
|
||||||
File target = new File(pack.getDirectory(), "cursemods");
|
File target = new File(pack.getDirectory(), "cursemods");
|
||||||
|
|
||||||
if (target.isDirectory()) {
|
if (!target.isDirectory()) {
|
||||||
scanner.walk(target);
|
target.mkdirs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scanner.walk(target);
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package com.skcraft.plugin.curse.creator;
|
package com.skcraft.plugin.curse.creator;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectWriter;
|
||||||
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
import com.skcraft.concurrency.ProgressObservable;
|
import com.skcraft.concurrency.ProgressObservable;
|
||||||
import com.skcraft.concurrency.SettableProgress;
|
import com.skcraft.concurrency.SettableProgress;
|
||||||
import com.skcraft.launcher.creator.model.creator.Pack;
|
import com.skcraft.launcher.creator.model.creator.Pack;
|
||||||
@ -18,13 +20,13 @@ import java.util.concurrent.Callable;
|
|||||||
public class CursePack {
|
public class CursePack {
|
||||||
@Getter private final CurseSearchResults searchResults = new CurseSearchResults();
|
@Getter private final CurseSearchResults searchResults = new CurseSearchResults();
|
||||||
@Getter private final AddedModList modList = new AddedModList();
|
@Getter private final AddedModList modList = new AddedModList();
|
||||||
private final ObjectMapper mapper;
|
private final ObjectWriter writer;
|
||||||
|
|
||||||
private final String gameVersion;
|
private final String gameVersion;
|
||||||
private final File curseModsDir;
|
private final File curseModsDir;
|
||||||
|
|
||||||
public CursePack(ObjectMapper mapper, Pack pack) {
|
public CursePack(ObjectMapper mapper, Pack pack) {
|
||||||
this.mapper = mapper;
|
this.writer = mapper.writerWithDefaultPrettyPrinter().without(SerializationFeature.WRITE_NULL_MAP_VALUES);
|
||||||
this.gameVersion = pack.getCachedConfig().getGameVersion();
|
this.gameVersion = pack.getCachedConfig().getGameVersion();
|
||||||
this.curseModsDir = new File(pack.getDirectory(), "cursemods");
|
this.curseModsDir = new File(pack.getDirectory(), "cursemods");
|
||||||
}
|
}
|
||||||
@ -41,7 +43,7 @@ public class CursePack {
|
|||||||
|
|
||||||
File target = loadedMod.getDiskLocation(curseModsDir);
|
File target = loadedMod.getDiskLocation(curseModsDir);
|
||||||
log.info(String.format("Saving mod %s", target.getName()));
|
log.info(String.format("Saving mod %s", target.getName()));
|
||||||
mapper.writeValue(target, loadedMod.getMod());
|
writer.writeValue(target, loadedMod.getMod());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeMod(AddedMod mod) throws IOException {
|
public void removeMod(AddedMod mod) throws IOException {
|
||||||
@ -63,7 +65,7 @@ public class CursePack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
private class AddModsCall implements Callable<Object>, ProgressObservable {
|
class AddModsCall implements Callable<Object>, ProgressObservable {
|
||||||
private final List<CurseProject> projects;
|
private final List<CurseProject> projects;
|
||||||
private final SettableProgress progress = new SettableProgress("", -1);
|
private final SettableProgress progress = new SettableProgress("", -1);
|
||||||
|
|
||||||
@ -73,7 +75,7 @@ public class CursePack {
|
|||||||
int total = projects.size();
|
int total = projects.size();
|
||||||
|
|
||||||
for (CurseProject project : projects) {
|
for (CurseProject project : projects) {
|
||||||
progress.set(String.format("Adding mod %s", project.getName()), 100 * (double) current / total);
|
progress.set(String.format("Adding mod %s", project.getName()), (double) current / total);
|
||||||
|
|
||||||
addMod(project);
|
addMod(project);
|
||||||
current++;
|
current++;
|
||||||
@ -94,7 +96,7 @@ public class CursePack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
private class RemoveModsCall implements Callable<Object>, ProgressObservable {
|
class RemoveModsCall implements Callable<Object>, ProgressObservable {
|
||||||
private final List<AddedMod> mods;
|
private final List<AddedMod> mods;
|
||||||
private final SettableProgress progress = new SettableProgress("", -1);
|
private final SettableProgress progress = new SettableProgress("", -1);
|
||||||
|
|
||||||
@ -105,7 +107,7 @@ public class CursePack {
|
|||||||
|
|
||||||
for (AddedMod mod : mods) {
|
for (AddedMod mod : mods) {
|
||||||
progress.set(String.format("Removing mod %s", mod.getProject().getName()),
|
progress.set(String.format("Removing mod %s", mod.getProject().getName()),
|
||||||
100 * (double) current / total);
|
(double) current / total);
|
||||||
|
|
||||||
removeMod(mod);
|
removeMod(mod);
|
||||||
current++;
|
current++;
|
||||||
|
Loading…
Reference in New Issue
Block a user