/* * This file is part of Technic Launcher Core. * Copyright ©2015 Syndicate, LLC * * Technic Launcher Core is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Technic Launcher Core is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License, * as well as a copy of the GNU Lesser General Public License, * along with Technic Launcher Core. If not, see <http://www.gnu.org/licenses/>. */ package net.technicpack.launchercore.modpacks; import net.technicpack.launchercore.install.LauncherDirectories; import net.technicpack.launchercore.modpacks.sources.IAuthoritativePackSource; import net.technicpack.launchercore.modpacks.sources.IInstalledPackRepository; import net.technicpack.launchercore.modpacks.sources.IModpackTagBuilder; import net.technicpack.launchercore.modpacks.sources.IPackSource; import net.technicpack.rest.io.PackInfo; import java.awt.*; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; public class PackLoadJob implements Runnable { private LauncherDirectories directories; private IModpackTagBuilder tagBuilder; private IAuthoritativePackSource authoritativeSource; private IInstalledPackRepository packRepository; private Collection<IPackSource> packSources; private IModpackContainer container; private boolean doLoadRepository; private Map<String, ModpackModel> processedModpacks = new HashMap<String, ModpackModel>(); private boolean isCancelled = false; public PackLoadJob(LauncherDirectories directories, IInstalledPackRepository packRepository, IAuthoritativePackSource authoritativeSource, Collection<IPackSource> packSources, IModpackContainer container, IModpackTagBuilder tagBuilder, boolean doLoadRepository) { this.packRepository = packRepository; this.authoritativeSource = authoritativeSource; this.packSources = packSources; this.container = container; this.tagBuilder = tagBuilder; this.directories = directories; this.doLoadRepository = doLoadRepository; container.clear(); } //Stop adding & updating packs from this job. Used for instance in the search bar: if the user types out 3 letters //we want to search for what they typed, but if they keep typing we want to cancel the created job and make a new one //This method forces the cancel to occur on the dispatch thread, since addPack always takes place on the dispatch thread, //so we don't have to worry about an addPack being halfway through completion if this object is saying it's cancelled public void cancel() { if (EventQueue.isDispatchThread()) { isCancelled = true; } else { EventQueue.invokeLater(new Runnable() { @Override public void run() { cancel(); } }); } } public boolean isCancelled() { return isCancelled; } @Override public void run() { int threadCount = 0; if (doLoadRepository) threadCount++; if (packSources != null) threadCount += packSources.size(); Collection<Thread> threads = new ArrayList<Thread>(threadCount); if (doLoadRepository) { for (final String packName : packRepository.getPackNames()) { InstalledPack pack = packRepository.getInstalledPacks().get(packName); addPackThreadSafe(pack, null, -1); } } if (packSources != null) { for (final IPackSource packSource : packSources) { Thread packSourceThread = new Thread(packSource.getSourceName() + " Loading Thread") { @Override public void run() { for (PackInfo info : packSource.getPublicPacks()) { addPackThreadSafe(null, info, packSource.getPriority(info)); } } }; threads.add(packSourceThread); packSourceThread.start(); } } for (Thread thread : threads) { try { thread.join(); } catch (InterruptedException ex) { } } refreshCompleteThreadSafe(); } protected void refreshCompleteThreadSafe() { EventQueue.invokeLater(new Runnable() { @Override public void run() { container.refreshComplete(); } }); } protected void addPackThreadSafe(final InstalledPack pack, final PackInfo packInfo, final int priority) { EventQueue.invokeLater(new Runnable() { @Override public void run() { addPack(pack, packInfo, priority); } }); } protected void addPack(final InstalledPack pack, final PackInfo packInfo, final int priority) { if (pack == null && packInfo == null || isCancelled) return; String name = (pack != null) ? pack.getName() : packInfo.getName(); ModpackModel modpack = null; boolean newModpackModel = true; if (processedModpacks.containsKey(name)) { modpack = processedModpacks.get(name); newModpackModel = false; if (modpack.getInstalledPack() == null && pack != null) { modpack.setInstalledPack(pack, packRepository); } if (packInfo != null) { modpack.setPackInfo(packInfo); modpack.updatePriority(priority); } } else { modpack = new ModpackModel(pack, packInfo, packRepository, directories); modpack.updatePriority(priority); if (packInfo == null) modpack.setIsPlatform(false); processedModpacks.put(name, modpack); } if (modpack.getInstalledPack() == null && !doLoadRepository && packRepository.getInstalledPacks().containsKey(modpack.getName())) { modpack.setInstalledPack(packRepository.getInstalledPacks().get(modpack.getName()), packRepository); } Runnable fillDataMethod = null; if (modpack.getPackInfo() == null) { fillDataMethod = new Runnable() { @Override public void run() { PackInfo completeInfo = authoritativeSource.getPackInfo(pack); if (completeInfo != null) { addPackThreadSafe(null, completeInfo, priority); } } }; } else if (!modpack.getPackInfo().isComplete()) { fillDataMethod = new Runnable() { @Override public void run() { PackInfo completeInfo = authoritativeSource.getCompletePackInfo(packInfo); if (completeInfo != null) { addPackThreadSafe(null, completeInfo, priority); } } }; } if (fillDataMethod != null) { Thread thread = new Thread(fillDataMethod); thread.start(); } if (modpack != null && tagBuilder != null) modpack.updateTags(tagBuilder); if (newModpackModel) container.addModpackToContainer(modpack); else container.replaceModpackInContainer(modpack); } }