403 lines
14 KiB
Java
403 lines
14 KiB
Java
/*
|
|
* 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.dialog;
|
|
|
|
import com.skcraft.concurrency.ObservableFuture;
|
|
import com.skcraft.launcher.Instance;
|
|
import com.skcraft.launcher.InstanceList;
|
|
import com.skcraft.launcher.Launcher;
|
|
import com.skcraft.launcher.launch.LaunchListener;
|
|
import com.skcraft.launcher.launch.LaunchOptions;
|
|
import com.skcraft.launcher.launch.LaunchOptions.UpdatePolicy;
|
|
import com.skcraft.launcher.swing.*;
|
|
import com.skcraft.launcher.util.SharedLocale;
|
|
import com.skcraft.launcher.util.SwingExecutor;
|
|
import lombok.Getter;
|
|
import lombok.NonNull;
|
|
import lombok.extern.java.Log;
|
|
import net.miginfocom.swing.MigLayout;
|
|
|
|
import javax.swing.*;
|
|
import javax.swing.event.TableModelEvent;
|
|
import javax.swing.event.TableModelListener;
|
|
import java.awt.*;
|
|
import java.awt.event.ActionEvent;
|
|
import java.awt.event.ActionListener;
|
|
import java.awt.event.MouseEvent;
|
|
import java.beans.PropertyChangeEvent;
|
|
import java.beans.PropertyChangeListener;
|
|
import java.io.File;
|
|
import java.lang.ref.WeakReference;
|
|
|
|
import static com.skcraft.launcher.util.SharedLocale.tr;
|
|
|
|
/**
|
|
* The main launcher frame.
|
|
*/
|
|
@Log
|
|
public class LauncherFrame extends JFrame {
|
|
|
|
private final Launcher launcher;
|
|
|
|
@Getter
|
|
private final InstanceTable instancesTable = new InstanceTable();
|
|
private final InstanceTableModel instancesModel;
|
|
@Getter
|
|
private final JScrollPane instanceScroll = new JScrollPane(instancesTable);
|
|
private WebpagePanel webView;
|
|
private JSplitPane splitPane;
|
|
private final JButton launchButton = new JButton(SharedLocale.tr("launcher.launch"));
|
|
private final JButton refreshButton = new JButton(SharedLocale.tr("launcher.checkForUpdates"));
|
|
private final JButton optionsButton = new JButton(SharedLocale.tr("launcher.options"));
|
|
private final JButton selfUpdateButton = new JButton(SharedLocale.tr("launcher.updateLauncher"));
|
|
private final JCheckBox updateCheck = new JCheckBox(SharedLocale.tr("launcher.downloadUpdates"));
|
|
|
|
/**
|
|
* Create a new frame.
|
|
*
|
|
* @param launcher the launcher
|
|
*/
|
|
public LauncherFrame(@NonNull Launcher launcher) {
|
|
super(tr("launcher.title", launcher.getVersion()));
|
|
|
|
this.launcher = launcher;
|
|
instancesModel = new InstanceTableModel(launcher.getInstances());
|
|
|
|
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
|
|
setMinimumSize(new Dimension(400, 300));
|
|
initComponents();
|
|
pack();
|
|
setLocationRelativeTo(null);
|
|
|
|
SwingHelper.setFrameIcon(this, Launcher.class, "icon.png");
|
|
|
|
SwingUtilities.invokeLater(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
loadInstances();
|
|
}
|
|
});
|
|
}
|
|
|
|
private void initComponents() {
|
|
JPanel container = createContainerPanel();
|
|
container.setLayout(new MigLayout("fill, insets dialog", "[][]push[][]", "[grow][]"));
|
|
|
|
webView = createNewsPanel();
|
|
splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, instanceScroll, webView);
|
|
selfUpdateButton.setVisible(launcher.getUpdateManager().getPendingUpdate());
|
|
|
|
launcher.getUpdateManager().addPropertyChangeListener(new PropertyChangeListener() {
|
|
@Override
|
|
public void propertyChange(PropertyChangeEvent evt) {
|
|
if (evt.getPropertyName().equals("pendingUpdate")) {
|
|
selfUpdateButton.setVisible((Boolean) evt.getNewValue());
|
|
|
|
}
|
|
}
|
|
});
|
|
|
|
updateCheck.setSelected(true);
|
|
instancesTable.setModel(instancesModel);
|
|
launchButton.setFont(launchButton.getFont().deriveFont(Font.BOLD));
|
|
splitPane.setDividerLocation(200);
|
|
splitPane.setDividerSize(4);
|
|
splitPane.setOpaque(false);
|
|
container.add(splitPane, "grow, wrap, span 5, gapbottom unrel, w null:680, h null:350");
|
|
SwingHelper.flattenJSplitPane(splitPane);
|
|
container.add(refreshButton);
|
|
container.add(updateCheck);
|
|
container.add(selfUpdateButton);
|
|
container.add(optionsButton);
|
|
container.add(launchButton);
|
|
|
|
add(container, BorderLayout.CENTER);
|
|
|
|
instancesModel.addTableModelListener(new TableModelListener() {
|
|
@Override
|
|
public void tableChanged(TableModelEvent e) {
|
|
if (instancesTable.getRowCount() > 0) {
|
|
instancesTable.setRowSelectionInterval(0, 0);
|
|
}
|
|
}
|
|
});
|
|
|
|
instancesTable.addMouseListener(new DoubleClickToButtonAdapter(launchButton));
|
|
|
|
refreshButton.addActionListener(new ActionListener() {
|
|
@Override
|
|
public void actionPerformed(ActionEvent e) {
|
|
loadInstances();
|
|
launcher.getUpdateManager().checkForUpdate(LauncherFrame.this);
|
|
webView.browse(launcher.getNewsURL(), false);
|
|
}
|
|
});
|
|
|
|
selfUpdateButton.addActionListener(new ActionListener() {
|
|
@Override
|
|
public void actionPerformed(ActionEvent e) {
|
|
launcher.getUpdateManager().performUpdate(LauncherFrame.this);
|
|
}
|
|
});
|
|
|
|
optionsButton.addActionListener(new ActionListener() {
|
|
@Override
|
|
public void actionPerformed(ActionEvent e) {
|
|
showOptions();
|
|
}
|
|
});
|
|
|
|
launchButton.addActionListener(new ActionListener() {
|
|
@Override
|
|
public void actionPerformed(ActionEvent e) {
|
|
launch();
|
|
}
|
|
});
|
|
|
|
instancesTable.addMouseListener(new PopupMouseAdapter() {
|
|
@Override
|
|
protected void showPopup(MouseEvent e) {
|
|
int index = instancesTable.rowAtPoint(e.getPoint());
|
|
Instance selected = null;
|
|
if (index >= 0) {
|
|
instancesTable.setRowSelectionInterval(index, index);
|
|
selected = launcher.getInstances().get(index);
|
|
}
|
|
popupInstanceMenu(e.getComponent(), e.getX(), e.getY(), selected);
|
|
}
|
|
});
|
|
}
|
|
|
|
protected JPanel createContainerPanel() {
|
|
return new JPanel();
|
|
}
|
|
|
|
/**
|
|
* Return the news panel.
|
|
*
|
|
* @return the news panel
|
|
*/
|
|
protected WebpagePanel createNewsPanel() {
|
|
return WebpagePanel.forURL(launcher.getNewsURL(), false);
|
|
}
|
|
|
|
/**
|
|
* Popup the menu for the instances.
|
|
*
|
|
* @param component the component
|
|
* @param x mouse X
|
|
* @param y mouse Y
|
|
* @param selected the selected instance, possibly null
|
|
*/
|
|
private void popupInstanceMenu(Component component, int x, int y, final Instance selected) {
|
|
JPopupMenu popup = new JPopupMenu();
|
|
JMenuItem menuItem;
|
|
|
|
if (selected != null) {
|
|
menuItem = new JMenuItem(!selected.isLocal() ? tr("instance.install") : tr("instance.launch"));
|
|
menuItem.addActionListener(new ActionListener() {
|
|
@Override
|
|
public void actionPerformed(ActionEvent e) {
|
|
launch();
|
|
}
|
|
});
|
|
popup.add(menuItem);
|
|
|
|
if (selected.isLocal()) {
|
|
popup.addSeparator();
|
|
|
|
menuItem = new JMenuItem(SharedLocale.tr("instance.openFolder"));
|
|
menuItem.addActionListener(ActionListeners.browseDir(
|
|
LauncherFrame.this, selected.getContentDir(), true));
|
|
popup.add(menuItem);
|
|
|
|
menuItem = new JMenuItem(SharedLocale.tr("instance.openSaves"));
|
|
menuItem.addActionListener(ActionListeners.browseDir(
|
|
LauncherFrame.this, new File(selected.getContentDir(), "saves"), true));
|
|
popup.add(menuItem);
|
|
|
|
menuItem = new JMenuItem(SharedLocale.tr("instance.openResourcePacks"));
|
|
menuItem.addActionListener(ActionListeners.browseDir(
|
|
LauncherFrame.this, new File(selected.getContentDir(), "resourcepacks"), true));
|
|
popup.add(menuItem);
|
|
|
|
menuItem = new JMenuItem(SharedLocale.tr("instance.openScreenshots"));
|
|
menuItem.addActionListener(ActionListeners.browseDir(
|
|
LauncherFrame.this, new File(selected.getContentDir(), "screenshots"), true));
|
|
popup.add(menuItem);
|
|
|
|
menuItem = new JMenuItem(SharedLocale.tr("instance.copyAsPath"));
|
|
menuItem.addActionListener(new ActionListener() {
|
|
@Override
|
|
public void actionPerformed(ActionEvent e) {
|
|
File dir = selected.getContentDir();
|
|
dir.mkdirs();
|
|
SwingHelper.setClipboard(dir.getAbsolutePath());
|
|
}
|
|
});
|
|
popup.add(menuItem);
|
|
|
|
menuItem = new JMenuItem(SharedLocale.tr("instance.openSettings"));
|
|
menuItem.addActionListener(e -> {
|
|
InstanceSettingsDialog.open(this, selected);
|
|
});
|
|
popup.add(menuItem);
|
|
|
|
popup.addSeparator();
|
|
|
|
if (!selected.isUpdatePending()) {
|
|
menuItem = new JMenuItem(SharedLocale.tr("instance.forceUpdate"));
|
|
menuItem.addActionListener(new ActionListener() {
|
|
@Override
|
|
public void actionPerformed(ActionEvent e) {
|
|
selected.setUpdatePending(true);
|
|
launch();
|
|
instancesModel.update();
|
|
}
|
|
});
|
|
popup.add(menuItem);
|
|
}
|
|
|
|
menuItem = new JMenuItem(SharedLocale.tr("instance.hardForceUpdate"));
|
|
menuItem.addActionListener(new ActionListener() {
|
|
@Override
|
|
public void actionPerformed(ActionEvent e) {
|
|
confirmHardUpdate(selected);
|
|
}
|
|
});
|
|
popup.add(menuItem);
|
|
|
|
menuItem = new JMenuItem(SharedLocale.tr("instance.deleteFiles"));
|
|
menuItem.addActionListener(new ActionListener() {
|
|
@Override
|
|
public void actionPerformed(ActionEvent e) {
|
|
confirmDelete(selected);
|
|
}
|
|
});
|
|
popup.add(menuItem);
|
|
}
|
|
|
|
popup.addSeparator();
|
|
}
|
|
|
|
menuItem = new JMenuItem(SharedLocale.tr("launcher.refreshList"));
|
|
menuItem.addActionListener(new ActionListener() {
|
|
@Override
|
|
public void actionPerformed(ActionEvent e) {
|
|
loadInstances();
|
|
}
|
|
});
|
|
popup.add(menuItem);
|
|
|
|
popup.show(component, x, y);
|
|
|
|
}
|
|
|
|
private void confirmDelete(Instance instance) {
|
|
if (!SwingHelper.confirmDialog(this,
|
|
tr("instance.confirmDelete", instance.getTitle()), SharedLocale.tr("confirmTitle"))) {
|
|
return;
|
|
}
|
|
|
|
ObservableFuture<Instance> future = launcher.getInstanceTasks().delete(this, instance);
|
|
|
|
// Update the list of instances after updating
|
|
future.addListener(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
loadInstances();
|
|
}
|
|
}, SwingExecutor.INSTANCE);
|
|
}
|
|
|
|
private void confirmHardUpdate(Instance instance) {
|
|
if (!SwingHelper.confirmDialog(this, SharedLocale.tr("instance.confirmHardUpdate"), SharedLocale.tr("confirmTitle"))) {
|
|
return;
|
|
}
|
|
|
|
ObservableFuture<Instance> future = launcher.getInstanceTasks().hardUpdate(this, instance);
|
|
|
|
// Update the list of instances after updating
|
|
future.addListener(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
launch();
|
|
instancesModel.update();
|
|
}
|
|
}, SwingExecutor.INSTANCE);
|
|
}
|
|
|
|
private void loadInstances() {
|
|
ObservableFuture<InstanceList> future = launcher.getInstanceTasks().reloadInstances(this);
|
|
|
|
future.addListener(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
instancesModel.update();
|
|
if (instancesTable.getRowCount() > 0) {
|
|
instancesTable.setRowSelectionInterval(0, 0);
|
|
}
|
|
requestFocus();
|
|
}
|
|
}, SwingExecutor.INSTANCE);
|
|
|
|
ProgressDialog.showProgress(this, future, SharedLocale.tr("launcher.checkingTitle"), SharedLocale.tr("launcher.checkingStatus"));
|
|
SwingHelper.addErrorDialogCallback(this, future);
|
|
}
|
|
|
|
private void showOptions() {
|
|
ConfigurationDialog configDialog = new ConfigurationDialog(this, launcher);
|
|
configDialog.setVisible(true);
|
|
}
|
|
|
|
private void launch() {
|
|
boolean permitUpdate = updateCheck.isSelected();
|
|
Instance instance = launcher.getInstances().get(instancesTable.getSelectedRow());
|
|
|
|
LaunchOptions options = new LaunchOptions.Builder()
|
|
.setInstance(instance)
|
|
.setListener(new LaunchListenerImpl(this))
|
|
.setUpdatePolicy(permitUpdate ? UpdatePolicy.UPDATE_IF_SESSION_ONLINE : UpdatePolicy.NO_UPDATE)
|
|
.setWindow(this)
|
|
.build();
|
|
launcher.getLaunchSupervisor().launch(options);
|
|
}
|
|
|
|
private static class LaunchListenerImpl implements LaunchListener {
|
|
private final WeakReference<LauncherFrame> frameRef;
|
|
private final Launcher launcher;
|
|
|
|
private LaunchListenerImpl(LauncherFrame frame) {
|
|
this.frameRef = new WeakReference<LauncherFrame>(frame);
|
|
this.launcher = frame.launcher;
|
|
}
|
|
|
|
@Override
|
|
public void instancesUpdated() {
|
|
LauncherFrame frame = frameRef.get();
|
|
if (frame != null) {
|
|
frame.instancesModel.update();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void gameStarted() {
|
|
LauncherFrame frame = frameRef.get();
|
|
if (frame != null) {
|
|
frame.dispose();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void gameClosed() {
|
|
Window newLauncherWindow = launcher.showLauncherWindow();
|
|
launcher.getUpdateManager().checkForUpdate(newLauncherWindow);
|
|
}
|
|
}
|
|
|
|
}
|