amidstest/src/main/java/amidst/gui/profileselect/ProfileSelectWindow.java

193 lines
6.5 KiB
Java

package amidst.gui.profileselect;
import java.awt.Font;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import amidst.AmidstMetaData;
import amidst.AmidstSettings;
import amidst.Application;
import amidst.documentation.AmidstThread;
import amidst.documentation.CalledOnlyBy;
import amidst.documentation.NotThreadSafe;
import amidst.logging.AmidstLogger;
import amidst.logging.AmidstMessageBox;
import amidst.gameengineabstraction.file.IGameInstallation;
import amidst.gameengineabstraction.file.IUnresolvedLauncherProfile;
import amidst.mojangapi.LauncherProfileRunner;
import amidst.mojangapi.file.VersionListProvider;
import amidst.parsing.FormatException;
import amidst.threading.WorkerExecutor;
import net.miginfocom.swing.MigLayout;
@NotThreadSafe
public class ProfileSelectWindow {
private static final int HEIGHT_IN_PROFILE_COMPONENTS = 13;
private final Application application;
private final AmidstMetaData metadata;
private final WorkerExecutor workerExecutor;
private final VersionListProvider versionListProvider;
private final IGameInstallation gameInstallation;
private final LauncherProfileRunner launcherProfileRunner;
private final AmidstSettings settings;
private final JFrame frame;
private final ProfileSelectPanel profileSelectPanel;
private volatile boolean isDisposed = false;
@CalledOnlyBy(AmidstThread.EDT)
public ProfileSelectWindow(
Application application,
AmidstMetaData metadata,
WorkerExecutor workerExecutor,
VersionListProvider versionListProvider,
IGameInstallation gameInstallation,
LauncherProfileRunner launcherProfileRunner,
AmidstSettings settings) {
this.application = application;
this.metadata = metadata;
this.workerExecutor = workerExecutor;
this.versionListProvider = versionListProvider;
this.gameInstallation = gameInstallation;
this.launcherProfileRunner = launcherProfileRunner;
this.settings = settings;
this.profileSelectPanel = new ProfileSelectPanel(settings.lastProfile, "Scanning...");
this.frame = createFrame();
scanAndLoadProfilesLater();
}
@CalledOnlyBy(AmidstThread.EDT)
private JFrame createFrame() {
JFrame frame = new JFrame("Profile Selector");
frame.setIconImages(metadata.getIcons());
frame.getContentPane().setLayout(new MigLayout());
frame.add(createTitleLabel(), "h 20!,w :400:, growx, pushx, wrap");
frame.add(createScrollPanel(), getScrollPaneLayoutString());
frame.pack();
frame.addKeyListener(profileSelectPanel.createKeyListener());
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
application.exitGracefully();
}
});
frame.setLocation(200, 200);
frame.setVisible(true);
return frame;
}
@CalledOnlyBy(AmidstThread.EDT)
private JLabel createTitleLabel() {
JLabel result = new JLabel("Please select a Minecraft profile:", SwingConstants.CENTER);
result.setFont(new Font("arial", Font.BOLD, 16));
return result;
}
@CalledOnlyBy(AmidstThread.EDT)
private JScrollPane createScrollPanel() {
JScrollPane result = new JScrollPane(profileSelectPanel.getComponent());
result.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
result.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
return result;
}
/**
* The preferred width should be at least a scrollbar-width wider than the
* ProfileComponent's preferredSize width of 500 (so 520?). The preferred
* height should allow the dialog to fit easily on a 720p display, while
* being nicely divisible by ProfileComponent's height of 40 (so 520 again
* then?).
*/
@CalledOnlyBy(AmidstThread.EDT)
private String getScrollPaneLayoutString() {
int scrollBarWidth = (Integer) UIManager.get("ScrollBar.width");
int preferredWidth = ProfileComponent.PREFERRED_WIDTH + scrollBarWidth;
int preferredHeight = ProfileComponent.PREFERRED_HEIGHT * HEIGHT_IN_PROFILE_COMPONENTS;
return "grow, push, w :" + preferredWidth + ":, h 80:" + preferredHeight + ":";
}
@CalledOnlyBy(AmidstThread.EDT)
private void scanAndLoadProfilesLater() {
workerExecutor.run(this::scanAndLoadProfiles, this::displayProfiles, this::scanAndLoadProfilesFailed);
}
@CalledOnlyBy(AmidstThread.WORKER)
private List<IUnresolvedLauncherProfile> scanAndLoadProfiles() throws FormatException, IOException {
AmidstLogger.info("Scanning for profiles.");
List<IUnresolvedLauncherProfile> launcherProfiles = gameInstallation.readLauncherProfiles();
AmidstLogger.info("Successfully loaded profile list.");
return launcherProfiles;
}
@CalledOnlyBy(AmidstThread.EDT)
private void displayProfiles(List<IUnresolvedLauncherProfile> launcherProfiles) {
createProfileComponentsIfNecessary(launcherProfiles);
restoreSelection();
frame.pack();
}
@CalledOnlyBy(AmidstThread.EDT)
private void createProfileComponentsIfNecessary(List<IUnresolvedLauncherProfile> launcherProfiles) {
if (launcherProfiles.isEmpty()) {
AmidstLogger.warn("No profiles found in launcher_profiles.json");
profileSelectPanel.setEmptyMessage("No profiles found");
} else {
createProfileComponents(launcherProfiles);
versionListProvider.onDownloadRemoteFinished(this::resolveAllLater);
profileSelectPanel.resolveAllLater();
}
}
private void resolveAllLater() {
if (!isDisposed) {
profileSelectPanel.resolveAllLater();
}
}
@CalledOnlyBy(AmidstThread.EDT)
private void createProfileComponents(List<IUnresolvedLauncherProfile> launcherProfiles) {
for (IUnresolvedLauncherProfile profile : launcherProfiles) {
profileSelectPanel.addProfile(
new LocalProfileComponent(
application,
workerExecutor,
versionListProvider,
launcherProfileRunner,
profile));
}
}
@CalledOnlyBy(AmidstThread.EDT)
private void restoreSelection() {
String profileName = settings.lastProfile.get();
if (profileName != null && !profileName.isEmpty()) {
profileSelectPanel.select(profileName);
} else {
profileSelectPanel.selectFirst();
}
}
@CalledOnlyBy(AmidstThread.EDT)
private void scanAndLoadProfilesFailed(Exception e) {
AmidstLogger.error(e, "Error reading launcher_profiles.json");
AmidstMessageBox.displayError("Error", e, "Error reading launcher_profiles.json");
profileSelectPanel.setEmptyMessage("Failed loading");
}
@CalledOnlyBy(AmidstThread.EDT)
public void dispose() {
isDisposed = true;
frame.dispose();
}
}