/* * SK's Minecraft Launcher * Copyright (C) 2010-2014 Albert Pham <http://www.sk89q.com> and contributors * Please see LICENSE.txt for license information. */ package com.skcraft.launcher.creator.controller; import com.google.common.collect.Lists; import com.google.common.util.concurrent.ListeningExecutorService; import com.skcraft.concurrency.Deferred; import com.skcraft.concurrency.Deferreds; import com.skcraft.concurrency.SettableProgress; import com.skcraft.launcher.creator.controller.task.DirectoryWalker; import com.skcraft.launcher.creator.dialog.VersionCheckDialog; import com.skcraft.launcher.creator.model.creator.ModFile; import com.skcraft.launcher.creator.model.swing.ModFileTableModel; import com.skcraft.launcher.creator.util.ModInfoReader; import com.skcraft.launcher.creator.util.ModInfoReader.ModInfo; import com.skcraft.launcher.creator.util.NemModList; import com.skcraft.launcher.creator.util.NemModList.ModEntry; import com.skcraft.launcher.dialog.ProgressDialog; import com.skcraft.launcher.swing.SwingHelper; import com.skcraft.launcher.util.SwingExecutor; import javax.annotation.Nullable; import javax.swing.*; import java.awt.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.List; public class VersionCheckController { private final VersionCheckDialog dialog; private final ListeningExecutorService executor; public VersionCheckController(VersionCheckDialog dialog, ListeningExecutorService executor) { this.dialog = dialog; this.executor = executor; } public void showUpdates(File dir, String gameVersion, Window parentWindow) { initListeners(); DirectoryWalker walker = new DirectoryWalker(dir); walker.setRecursive(false); walker.setFileFilter(pathname -> pathname.getName().endsWith(".jar")); ModInfoReader binaryInspector = new ModInfoReader(); NemModList nemModList = new NemModList(); SettableProgress progress = new SettableProgress("Retrieving mod information...", -1); Deferred<?> deferred = Deferreds.makeDeferred(executor.submit(walker), executor) .thenTap(() -> progress.set("Querying NotEnoughMods for version data...", -1)) .thenTap(() -> { try { nemModList.load(gameVersion); } catch (IOException | InterruptedException e) { throw new RuntimeException("Failed to retrieve mod information from NotEnoughMods. Perhaps NEM doesn't support your pack's MC version.", e); } }) .thenTap(() -> progress.set("Scanning mod files for manifests...", -1)) .thenApply(files -> { List<ModFile> mods = Lists.newArrayList(); for (File file : files) { ModFile mod = new ModFile(); mod.setGameVersion(gameVersion); mod.setFile(file); List<? extends ModInfo> infoList = binaryInspector.detectMods(file); if (!infoList.isEmpty()) { ModInfo info = infoList.get(0); mod.setModId(info.getModId()); mod.setName(info.getName()); mod.setVersion(info.getVersion()); if (info.getUrl() != null) { mod.setUrl(getFirstUrl(info.getUrl(), "http://" + info.getUrl())); } } if (mod.getModId() != null) { ModEntry entry = nemModList.get(mod.getModId()); if (entry != null) { mod.setLatestVersion(entry.getLatestVersion()); mod.setLatestDevVersion(entry.getLatestDevVersion()); if (entry.getUrl() != null) { mod.setUrl(entry.getUrl()); } } } mods.add(mod); } return mods; }) .handleAsync(mods -> { List<ModFile> known = Lists.newArrayList(); List<ModFile> unknown = Lists.newArrayList(); for (ModFile mod : mods) { if (mod.getVersion() != null && mod.getLatestVersion() != null) { if (!mod.getCleanVersion().equals(mod.getLatestVersion()) && !mod.getCleanVersion().equals(mod.getLatestDevVersion())) { known.add(mod); } } else { unknown.add(mod); } } dialog.getKnownModsTable().setModel(new ModFileTableModel(known)); dialog.getUnknownModsTable().setModel(new ModFileTableModel(unknown)); dialog.getKnownModsTable().getRowSorter().toggleSortOrder(1); dialog.getUnknownModsTable().getRowSorter().toggleSortOrder(1); dialog.setVisible(true); }, ex -> { }, SwingExecutor.INSTANCE); ProgressDialog.showProgress(parentWindow, deferred, progress, "Checking for mod updates...", "Checking for mod updates..."); SwingHelper.addErrorDialogCallback(parentWindow, deferred); } private void initListeners() { dialog.getCloseButton().addActionListener(e -> dialog.dispose()); ModTableMouseListener mouseListener = new ModTableMouseListener(); dialog.getKnownModsTable().addMouseListener(mouseListener); dialog.getUnknownModsTable().addMouseListener(mouseListener); } @Nullable private static URL getFirstUrl(String... options) { for (String option : options) { try { return new URL(option); } catch (MalformedURLException ignored) { } } return null; } private class ModTableMouseListener extends MouseAdapter { public void mousePressed(MouseEvent e) { if (e.getClickCount() == 2) { JTable table = (JTable) e.getSource(); Point point = e.getPoint(); int selectedIndex = table.rowAtPoint(point); if (selectedIndex >= 0) { selectedIndex = table.convertRowIndexToModel(selectedIndex); ModFile mod = ((ModFileTableModel) table.getModel()).getMod(selectedIndex); if (mod != null && mod.getUrl() != null) { SwingHelper.openURL(mod.getUrl(), dialog); } } } } } }