1
0
mirror of https://github.com/SKCraft/Launcher.git synced 2025-01-06 19:18:27 +01:00

Refactor controller out of mod management dialog

This commit is contained in:
Henry Le Grys 2021-03-29 22:28:41 +01:00
parent 966205d68a
commit badd91d2b8
7 changed files with 172 additions and 57 deletions

View File

@ -15,7 +15,9 @@ import com.skcraft.launcher.swing.LinedBoxPanel;
import com.skcraft.launcher.swing.SwingHelper;
import com.skcraft.launcher.util.SwingExecutor;
import com.skcraft.plugin.curse.CurseApi;
import com.skcraft.plugin.curse.model.*;
import com.skcraft.plugin.curse.model.AddedMod;
import com.skcraft.plugin.curse.model.CurseProject;
import com.skcraft.plugin.curse.model.ProjectHolder;
import lombok.RequiredArgsConstructor;
import lombok.extern.java.Log;
@ -34,34 +36,28 @@ import static com.skcraft.launcher.util.HttpRequest.url;
@Log
public class CurseModsDialog extends JDialog {
private final CurseSearchResults searchResults = new CurseSearchResults();
private final LoadedModList modList = new LoadedModList();
private final CursePack cursePack;
private final JPanel panel = new JPanel(new BorderLayout(0, 5));
private final JTextField searchBox = new JTextField();
private final JButton searchButton = new JButton("Search");
private final JList<CurseProject> searchPane = new JList<>(searchResults);
private final JList<LoadedMod> selectedPane = new JList<>(modList);
private final JList<CurseProject> searchPane = 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 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 CurseProjectListRenderer projectRenderer = new CurseProjectListRenderer();
private final ListeningExecutorService executor;
private final ObjectMapper mapper;
private final Pack pack;
private final File curseModsDir;
public CurseModsDialog(Window owner, ListeningExecutorService executor, ObjectMapper mapper, Pack pack, List<LoadedMod> currentMods) {
public CurseModsDialog(Window owner, ListeningExecutorService executor, Pack pack, CursePack cursePack) {
super(owner);
this.executor = executor;
this.mapper = mapper;
this.pack = pack;
this.curseModsDir = new File(pack.getDirectory(), "cursemods");
modList.addAll(currentMods);
this.cursePack = cursePack;
initComponents();
setMinimumSize(new Dimension(500, 450));
@ -70,11 +66,13 @@ public class CurseModsDialog extends JDialog {
}
private void initComponents() {
searchPane.setModel(cursePack.getSearchResults());
searchPane.setCellRenderer(projectRenderer);
searchPane.setLayoutOrientation(JList.VERTICAL);
searchPane.setVisibleRowCount(0);
searchPane.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
selectedPane.setModel(cursePack.getModList());
selectedPane.setCellRenderer(projectRenderer);
selectedPane.setLayoutOrientation(JList.VERTICAL);
selectedPane.setVisibleRowCount(0);
@ -107,41 +105,17 @@ public class CurseModsDialog extends JDialog {
searchButton.addActionListener(e -> search());
addMod.addActionListener(e -> {
for (CurseProject project : searchPane.getSelectedValuesList()) {
GameVersionFile forVersion = project.findFileForVersion(pack.getCachedConfig().getGameVersion());
ListenableFuture<Object> future = executor.submit(cursePack.addMany(searchPane.getSelectedValuesList()));
if (forVersion == null) {
SwingHelper.showErrorDialog(
getOwner(),
String.format("Mod %s isn't available for this version.", project.getName()),
"Mod Unavailable"
);
return;
}
LoadedMod loadedMod = project.toLoadedMod(forVersion);
modList.add(loadedMod);
executor.submit(() -> {
File target = loadedMod.getDiskLocation(curseModsDir);
log.info(String.format("Saving mod %s", target.getName()));
mapper.writeValue(target, loadedMod.getMod());
return null;
});
}
// TODO: Update a progress bar built in to the dialog.
SwingHelper.addErrorDialogCallback(getOwner(), future);
});
removeMod.addActionListener(e -> {
for (LoadedMod mod : selectedPane.getSelectedValuesList()) {
modList.remove(mod);
ListenableFuture<Object> future = executor.submit(
cursePack.removeMany(selectedPane.getSelectedValuesList()));
File target = mod.getDiskLocation(curseModsDir);
log.info(String.format("Removing mod %s", target.getName()));
if (!target.delete()) {
SwingHelper.showErrorDialog(getOwner(), String.format("Failed to delete %s", target), "I/O error");
}
}
SwingHelper.addErrorDialogCallback(getOwner(), future);
});
done.addActionListener(e -> dispose());
@ -163,7 +137,7 @@ public class CurseModsDialog extends JDialog {
@Override
public void onSuccess(List<CurseProject> result) {
projectRenderer.clearCacheIfBig();
searchResults.updateResults(result);
cursePack.getSearchResults().updateResults(result);
}
@Override
@ -298,7 +272,10 @@ public class CurseModsDialog extends JDialog {
SwingHelper.addErrorDialogCallback(ctx.getOwner(), future);
future.addListener(() -> {
CurseModsDialog dialog = new CurseModsDialog(ctx.getOwner(), ctx.getExecutor(), mapper, pack, scanner.getResult());
CursePack cursePack = new CursePack(mapper, pack);
cursePack.getModList().addAll(scanner.getResult());
CurseModsDialog dialog = new CurseModsDialog(ctx.getOwner(), ctx.getExecutor(), pack, cursePack);
dialog.setTitle(getTitle());
dialog.setVisible(true);
}, SwingExecutor.INSTANCE);

View File

@ -0,0 +1,127 @@
package com.skcraft.plugin.curse.creator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.skcraft.concurrency.ProgressObservable;
import com.skcraft.concurrency.SettableProgress;
import com.skcraft.launcher.creator.model.creator.Pack;
import com.skcraft.plugin.curse.model.*;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.java.Log;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.Callable;
@Log
public class CursePack {
@Getter private final CurseSearchResults searchResults = new CurseSearchResults();
@Getter private final AddedModList modList = new AddedModList();
private final ObjectMapper mapper;
private final String gameVersion;
private final File curseModsDir;
public CursePack(ObjectMapper mapper, Pack pack) {
this.mapper = mapper;
this.gameVersion = pack.getCachedConfig().getGameVersion();
this.curseModsDir = new File(pack.getDirectory(), "cursemods");
}
public void addMod(CurseProject project) throws IOException, MissingVersionException {
GameVersionFile forVersion = project.findFileForVersion(gameVersion);
if (forVersion == null) {
throw new MissingVersionException("Mod %s isn't available for this version.");
}
AddedMod loadedMod = project.toLoadedMod(forVersion);
modList.add(loadedMod);
File target = loadedMod.getDiskLocation(curseModsDir);
log.info(String.format("Saving mod %s", target.getName()));
mapper.writeValue(target, loadedMod.getMod());
}
public void removeMod(AddedMod mod) throws IOException {
modList.remove(mod);
File target = mod.getDiskLocation(curseModsDir);
log.info(String.format("Removing mod %s", target.getName()));
if (!target.delete()) {
throw new IOException(String.format("Failed to delete %s", target));
}
}
public AddModsCall addMany(List<CurseProject> projects) {
return new AddModsCall(projects);
}
public RemoveModsCall removeMany(List<AddedMod> mods) {
return new RemoveModsCall(mods);
}
@RequiredArgsConstructor
private class AddModsCall implements Callable<Object>, ProgressObservable {
private final List<CurseProject> projects;
private final SettableProgress progress = new SettableProgress("", -1);
@Override
public Object call() throws Exception {
int current = 0;
int total = projects.size();
for (CurseProject project : projects) {
progress.set(String.format("Adding mod %s", project.getName()), 100 * (double) current / total);
addMod(project);
current++;
}
return null;
}
@Override
public double getProgress() {
return progress.getProgress();
}
@Override
public String getStatus() {
return progress.getStatus();
}
}
@RequiredArgsConstructor
private class RemoveModsCall implements Callable<Object>, ProgressObservable {
private final List<AddedMod> mods;
private final SettableProgress progress = new SettableProgress("", -1);
@Override
public Object call() throws Exception {
int current = 0;
int total = mods.size();
for (AddedMod mod : mods) {
progress.set(String.format("Removing mod %s", mod.getProject().getName()),
100 * (double) current / total);
removeMod(mod);
current++;
}
return null;
}
@Override
public double getProgress() {
return progress.getProgress();
}
@Override
public String getStatus() {
return progress.getStatus();
}
}
}

View File

@ -4,9 +4,9 @@ import com.beust.jcommander.internal.Lists;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.skcraft.launcher.builder.DirectoryWalker;
import com.skcraft.plugin.curse.CurseApi;
import com.skcraft.plugin.curse.model.AddedMod;
import com.skcraft.plugin.curse.model.CurseMod;
import com.skcraft.plugin.curse.model.CurseProject;
import com.skcraft.plugin.curse.model.LoadedMod;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
@ -19,7 +19,7 @@ import java.util.List;
public class PackModScanner extends DirectoryWalker {
private final ObjectMapper mapper;
@Getter private final List<LoadedMod> result = Lists.newArrayList();
@Getter private final List<AddedMod> result = Lists.newArrayList();
@Override
@SneakyThrows
@ -27,6 +27,6 @@ public class PackModScanner extends DirectoryWalker {
CurseMod mod = mapper.readValue(file, CurseMod.class);
CurseProject project = CurseApi.getById(mod.getProjectId());
result.add(new LoadedMod(mod, project));
result.add(new AddedMod(mod, project));
}
}

View File

@ -8,7 +8,7 @@ import java.io.File;
* Represents mod metadata cached in-memory for the purpose of rendering the "Add Mods" screen.
*/
@Data
public class LoadedMod implements ProjectHolder {
public class AddedMod implements ProjectHolder {
private final CurseMod mod;
private final CurseProject project;

View File

@ -6,8 +6,8 @@ import javax.swing.*;
import java.util.Collection;
import java.util.List;
public class LoadedModList extends AbstractListModel<LoadedMod> {
private List<LoadedMod> mods = Lists.newArrayList();
public class AddedModList extends AbstractListModel<AddedMod> {
private List<AddedMod> mods = Lists.newArrayList();
@Override
public int getSize() {
@ -15,24 +15,24 @@ public class LoadedModList extends AbstractListModel<LoadedMod> {
}
@Override
public LoadedMod getElementAt(int index) {
public AddedMod getElementAt(int index) {
return mods.get(index);
}
public void addAll(Collection<? extends LoadedMod> other) {
public void addAll(Collection<? extends AddedMod> other) {
int start = mods.size();
mods.addAll(other);
fireIntervalAdded(this, start, start + other.size());
}
public void add(LoadedMod mod) {
public void add(AddedMod mod) {
mods.add(mod);
int idx = mods.size() - 1;
fireIntervalAdded(this, idx, idx);
}
public void remove(LoadedMod mod) {
public void remove(AddedMod mod) {
int index = mods.indexOf(mod);
if (index > -1) {

View File

@ -32,9 +32,9 @@ public class CurseProject implements ProjectHolder {
return null;
}
public LoadedMod toLoadedMod(GameVersionFile versionFile) {
public AddedMod toLoadedMod(GameVersionFile versionFile) {
CurseMod mod = new CurseMod(id, versionFile.getProjectFileId(), null);
return new LoadedMod(mod, this);
return new AddedMod(mod, this);
}
public Attachment getDefaultIcon() {

View File

@ -0,0 +1,11 @@
package com.skcraft.plugin.curse.model;
public class MissingVersionException extends Exception {
public MissingVersionException() {
super();
}
public MissingVersionException(String message) {
super(message);
}
}