/*
* ATLauncher - https://github.com/ATLauncher/ATLauncher
* Copyright (C) 2013 ATLauncher
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.atlauncher.gui.card;
import com.atlauncher.App;
import com.atlauncher.LogManager;
import com.atlauncher.data.Instance;
import com.atlauncher.data.Language;
import com.atlauncher.evnt.listener.RelocalizationListener;
import com.atlauncher.evnt.manager.RelocalizationManager;
import com.atlauncher.gui.components.CollapsiblePanel;
import com.atlauncher.gui.components.ImagePanel;
import com.atlauncher.gui.dialogs.BackupDialog;
import com.atlauncher.gui.dialogs.EditModsDialog;
import com.atlauncher.gui.dialogs.InstanceInstallerDialog;
import com.atlauncher.gui.dialogs.ProgressDialog;
import com.atlauncher.gui.dialogs.RenameInstanceDialog;
import com.atlauncher.utils.Utils;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.Dialog.ModalityType;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.sql.Timestamp;
import java.util.Date;
/**
* <p/>
* Class for displaying instances in the Instance Tab
*
* @author Ryan
*/
public class InstanceCard extends CollapsiblePanel implements RelocalizationListener {
private final JSplitPane splitter = new JSplitPane();
private final Instance instance;
private final JPanel rightPanel = new JPanel();
private final JTextArea descArea = new JTextArea();
private final ImagePanel image;
private final JButton playButton = new JButton(Language.INSTANCE.localize("common.play"));
private final JButton reinstallButton = new JButton(Language.INSTANCE.localize("common.reinstall"));
private final JButton updateButton = new JButton(Language.INSTANCE.localize("common.update"));
private final JButton renameButton = new JButton(Language.INSTANCE.localize("common.rename"));
private final JButton backupButton = new JButton(Language.INSTANCE.localize("common.backup"));
private final JButton cloneButton = new JButton(Language.INSTANCE.localize("instance.clone"));
private final JButton deleteButton = new JButton(Language.INSTANCE.localize("common.delete"));
private final JButton editButton = new JButton(Language.INSTANCE.localize("common.editmods"));
private final JButton openButton = new JButton(Language.INSTANCE.localize("common.openfolder"));
public InstanceCard(Instance instance) {
super(instance);
this.instance = instance;
this.image = new ImagePanel(instance.getImage().getImage());
this.splitter.setLeftComponent(this.image);
this.splitter.setRightComponent(this.rightPanel);
this.splitter.setEnabled(false);
this.descArea.setText(instance.getPackDescription());
this.descArea.setBorder(BorderFactory.createEmptyBorder());
this.descArea.setEditable(false);
this.descArea.setHighlighter(null);
this.descArea.setLineWrap(true);
this.descArea.setWrapStyleWord(true);
this.descArea.setEditable(false);
JPanel top = new JPanel(new FlowLayout());
JPanel bottom = new JPanel(new FlowLayout());
JSplitPane as = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
as.setEnabled(false);
as.setTopComponent(top);
as.setBottomComponent(bottom);
top.add(this.playButton);
top.add(this.reinstallButton);
top.add(this.updateButton);
top.add(this.renameButton);
top.add(this.backupButton);
bottom.add(this.cloneButton);
bottom.add(this.deleteButton);
bottom.add(this.editButton);
bottom.add(this.openButton);
this.rightPanel.setLayout(new BorderLayout());
this.rightPanel.setPreferredSize(new Dimension(this.rightPanel.getPreferredSize().width, 180));
this.rightPanel.add(new JScrollPane(this.descArea, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER), BorderLayout.CENTER);
this.rightPanel.add(as, BorderLayout.SOUTH);
this.getContentPane().setLayout(new BorderLayout());
this.getContentPane().add(this.splitter, BorderLayout.CENTER);
RelocalizationManager.addListener(this);
if (!instance.hasUpdate()) {
this.updateButton.setVisible(false);
}
this.addActionListeners();
this.addMouseListeners();
this.validatePlayable();
}
private void validatePlayable() {
if (!instance.isPlayable()) {
for (ActionListener al : playButton.getActionListeners()) {
playButton.removeActionListener(al);
}
playButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String[] options = {Language.INSTANCE.localize("common.ok")};
JOptionPane.showOptionDialog(App.settings.getParent(), Language.INSTANCE.localize("instance" + "" +
".corruptplay"), Language.INSTANCE.localize("instance.corrupt"),
JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE, null, options, options[0]);
}
});
for (ActionListener al : backupButton.getActionListeners()) {
backupButton.removeActionListener(al);
}
backupButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String[] options = {Language.INSTANCE.localize("common.ok")};
JOptionPane.showOptionDialog(App.settings.getParent(), Language.INSTANCE.localize("instance" + "" +
".corruptbackup"), Language.INSTANCE.localize("instance.corrupt"),
JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE, null, options, options[0]);
}
});
for (ActionListener al : cloneButton.getActionListeners()) {
cloneButton.removeActionListener(al);
}
cloneButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String[] options = {Language.INSTANCE.localize("common.ok")};
JOptionPane.showOptionDialog(App.settings.getParent(), Language.INSTANCE.localize("instance" + "" +
".corruptclone"), Language.INSTANCE.localize("instance.corrupt"),
JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE, null, options, options[0]);
}
});
}
}
private void addActionListeners() {
this.playButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (instance.hasUpdate() && !instance.hasUpdateBeenIgnored(instance.getLatestVersion()) && !instance
.isDev()) {
String[] options = {Language.INSTANCE.localize("common.yes"), Language.INSTANCE.localize("common"
+ ".no"), Language.INSTANCE.localize("instance.dontremindmeagain")};
int ret = JOptionPane.showOptionDialog(App.settings.getParent(),
"<html><p align=\"center\">" + Language.INSTANCE.localizeWithReplace("instance" + "" +
".updatenow", "<br/><br/>") + "</p></html>",
Language.INSTANCE.localize("instance" + "" +
".updateavailable"), JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE, null,
options, options[0]);
if (ret == 0) {
if (App.settings.getAccount() == null) {
String[] optionss = {Language.INSTANCE.localize("common.ok")};
JOptionPane.showOptionDialog(App.settings.getParent(),
Language.INSTANCE.localize("instance.cantupdate"),
Language.INSTANCE.localize("instance.noaccountselected"),
JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE, null, optionss, optionss[0]);
} else {
new InstanceInstallerDialog(instance, true, false);
}
} else if (ret == 1 || ret == JOptionPane.CLOSED_OPTION) {
if (!App.settings.isMinecraftLaunched()) {
if (instance.launch()) {
App.settings.setMinecraftLaunched(true);
}
}
} else if (ret == 2) {
instance.ignoreUpdate();
if (!App.settings.isMinecraftLaunched()) {
if (instance.launch()) {
App.settings.setMinecraftLaunched(true);
}
}
}
} else {
if (!App.settings.isMinecraftLaunched()) {
if (instance.launch()) {
App.settings.setMinecraftLaunched(true);
}
}
}
}
});
this.reinstallButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (App.settings.getAccount() == null) {
String[] options = {Language.INSTANCE.localize("common.ok")};
JOptionPane.showOptionDialog(App.settings.getParent(), Language.INSTANCE.localize("instance" + "" +
".cantreinstall"), Language.INSTANCE.localize("instance.noaccountselected"),
JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE, null, options, options[0]);
} else {
new InstanceInstallerDialog(instance);
}
}
});
this.updateButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (App.settings.getAccount() == null) {
String[] options = {Language.INSTANCE.localize("common.ok")};
JOptionPane.showOptionDialog(App.settings.getParent(), Language.INSTANCE.localize("instance" + "" +
".cantupdate"), Language.INSTANCE.localize("instance.noaccountselected"),
JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE, null, options, options[0]);
} else {
new InstanceInstallerDialog(instance, true, false);
}
}
});
this.renameButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
new RenameInstanceDialog(instance);
}
});
this.backupButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (App.settings.isAdvancedBackupsEnabled()) {
new BackupDialog(instance).setVisible(true);
} else {
if (instance.getSavesDirectory().exists()) {
int ret = JOptionPane.showConfirmDialog(App.settings.getParent(),
"<html><p align=\"center\">" + Language.INSTANCE.localizeWithReplace("backup.sure",
"<br/><br/>") + "</p></html>", Language.INSTANCE.localize("backup" + "" +
".backingup", instance.getName()), JOptionPane.YES_NO_OPTION);
if (ret == JOptionPane.YES_OPTION) {
final JDialog dialog = new JDialog(App.settings.getParent(),
Language.INSTANCE.localizeWithReplace("backup.backingup", instance.getName()),
ModalityType.APPLICATION_MODAL);
dialog.setSize(300, 100);
dialog.setLocationRelativeTo(App.settings.getParent());
dialog.setResizable(false);
JPanel topPanel = new JPanel();
topPanel.setLayout(new BorderLayout());
JLabel doing = new JLabel(Language.INSTANCE.localizeWithReplace("backup.backingup",
instance.getName()));
doing.setHorizontalAlignment(JLabel.CENTER);
doing.setVerticalAlignment(JLabel.TOP);
topPanel.add(doing);
JPanel bottomPanel = new JPanel();
bottomPanel.setLayout(new BorderLayout());
JProgressBar progressBar = new JProgressBar();
bottomPanel.add(progressBar, BorderLayout.NORTH);
progressBar.setIndeterminate(true);
dialog.add(topPanel, BorderLayout.CENTER);
dialog.add(bottomPanel, BorderLayout.SOUTH);
final Thread backupThread = new Thread() {
public void run() {
Timestamp timestamp = new Timestamp(new Date().getTime());
String time = timestamp.toString().replaceAll("[^0-9]", "_");
String filename = instance.getSafeName() + "-" + time.substring(0,
time.lastIndexOf("_")) + ".zip";
Utils.zip(instance.getSavesDirectory(), new File(App.settings.getBackupsDir(),
filename));
dialog.dispose();
App.TOASTER.pop(Language.INSTANCE.localizeWithReplace("backup.backupcomplete",
" " + filename));
}
};
backupThread.start();
dialog.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
backupThread.interrupt();
dialog.dispose();
}
});
dialog.setVisible(true);
}
} else {
String[] options = {Language.INSTANCE.localize("common.ok")};
JOptionPane.showOptionDialog(App.settings.getParent(), Language.INSTANCE.localize("backup" +
".nosaves"), Language.INSTANCE.localize("backup.nosavestitle"),
JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE, null, options, options[0]);
}
}
}
});
this.editButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
new EditModsDialog(instance);
}
});
this.openButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Utils.openExplorer(instance.getRootDirectory());
}
});
this.cloneButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String clonedName = JOptionPane.showInputDialog(App.settings.getParent(),
Language.INSTANCE.localize("instance.cloneenter"), Language.INSTANCE.localize("instance" + "" +
".clonetitle"), JOptionPane.INFORMATION_MESSAGE);
if (clonedName != null && clonedName.length() >= 1 && App.settings.getInstanceByName(clonedName) ==
null && App.settings.getInstanceBySafeName(clonedName.replaceAll("[^A-Za-z0-9]",
"")) == null && clonedName.replaceAll("[^A-Za-z0-9]", "").length() >= 1) {
final String newName = clonedName;
final ProgressDialog dialog = new ProgressDialog(Language.INSTANCE.localize("instance" + "" +
".clonetitle"), 0, Language.INSTANCE.localize("instance.cloninginstance"), null);
dialog.addThread(new Thread() {
@Override
public void run() {
App.settings.cloneInstance(instance, newName);
dialog.close();
App.TOASTER.pop(Language.INSTANCE.localizeWithReplace("instance.clonedsuccessfully",
instance.getName()));
}
});
dialog.start();
} else if (clonedName == null || clonedName.equals("")) {
LogManager.error("Error Occured While Cloning Instance! Dialog Closed/Cancelled!");
JOptionPane.showMessageDialog(App.settings.getParent(), "<html><p align=\"center\">" + Language
.INSTANCE.localizeWithReplace("instance.errorclone", instance.getName() + "<br/><br/>") +
"</p></html>", Language.INSTANCE.localize("common.error"), JOptionPane.ERROR_MESSAGE);
} else if (clonedName.replaceAll("[^A-Za-z0-9]", "").length() == 0) {
LogManager.error("Error Occured While Cloning Instance! Invalid Name!");
JOptionPane.showMessageDialog(App.settings.getParent(), "<html><p align=\"center\">" + Language
.INSTANCE.localizeWithReplace("instance.errorclone", instance.getName() + "<br/><br/>") +
"</p></html>", Language.INSTANCE.localize("common.error"), JOptionPane.ERROR_MESSAGE);
} else {
LogManager.error("Error Occured While Cloning Instance! Instance With That Name Already Exists!");
JOptionPane.showMessageDialog(App.settings.getParent(), "<html><p align=\"center\">" + Language
.INSTANCE.localizeWithReplace("instance.errorclone", instance.getName() + "<br/><br/>") +
"</p></html>", Language.INSTANCE.localize("common.error"), JOptionPane.ERROR_MESSAGE);
}
}
});
this.deleteButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int response = JOptionPane.showConfirmDialog(App.settings.getParent(),
Language.INSTANCE.localize("instance.deletesure"), Language.INSTANCE.localize("instance" + "" +
".deleteinstance"), JOptionPane.YES_NO_OPTION);
if (response == JOptionPane.YES_OPTION) {
final ProgressDialog dialog = new ProgressDialog(Language.INSTANCE.localize("instance" + "" +
".deletetitle"), 0, Language.INSTANCE.localize("instance.deletinginstance"), null);
dialog.addThread(new Thread() {
@Override
public void run() {
App.settings.removeInstance(instance);
dialog.close();
App.TOASTER.pop(Language.INSTANCE.localizeWithReplace("instance.deletedsuccessfully",
instance.getName()));
}
});
dialog.start();
}
}
});
}
private void addMouseListeners() {
this.image.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() >= 2) {
if (instance.hasUpdate() && !instance.hasUpdateBeenIgnored(instance.getLatestVersion()) &&
!instance.isDev()) {
String[] options = {Language.INSTANCE.localize("common.yes"),
Language.INSTANCE.localize("common.no"), Language.INSTANCE.localize("instance" + "" +
".dontremindmeagain")};
int ret = JOptionPane.showOptionDialog(App.settings.getParent(),
"<html><p align=\"center\">" + Language.INSTANCE.localizeWithReplace("instance" + "" +
".updatenow", "<br/><br/>") + "</p></html>",
Language.INSTANCE.localize("instance.updateavailable"), JOptionPane.DEFAULT_OPTION,
JOptionPane.ERROR_MESSAGE, null, options, options[0]);
if (ret == 0) {
if (App.settings.getAccount() == null) {
String[] optionss = {Language.INSTANCE.localize("common.ok")};
JOptionPane.showOptionDialog(App.settings.getParent(),
Language.INSTANCE.localize("instance.cantupdate"),
Language.INSTANCE.localize("instance.noaccountselected"),
JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE, null, optionss,
optionss[0]);
} else {
new InstanceInstallerDialog(instance, true, false);
}
} else if (ret == 1 || ret == JOptionPane.CLOSED_OPTION) {
if (!App.settings.isMinecraftLaunched()) {
if (instance.launch()) {
App.settings.setMinecraftLaunched(true);
}
}
} else if (ret == 2) {
instance.ignoreUpdate();
if (!App.settings.isMinecraftLaunched()) {
if (instance.launch()) {
App.settings.setMinecraftLaunched(true);
}
}
}
} else {
if (!App.settings.isMinecraftLaunched()) {
if (instance.launch()) {
App.settings.setMinecraftLaunched(true);
}
}
}
} else if (e.getButton() == MouseEvent.BUTTON3) {
JPopupMenu rightClickMenu = new JPopupMenu();
JMenuItem changeImageItem = new JMenuItem(Language.INSTANCE.localize("instance.changeimage"));
JMenuItem updateItem = new JMenuItem("Update Instance");
rightClickMenu.add(changeImageItem);
rightClickMenu.add(updateItem);
rightClickMenu.show(image, e.getX(), e.getY());
changeImageItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JFileChooser chooser = new JFileChooser();
chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
chooser.setAcceptAllFileFilterUsed(false);
chooser.setFileFilter(new FileNameExtensionFilter("PNG Files", "png"));
int ret = chooser.showOpenDialog(App.settings.getParent());
if (ret == JFileChooser.APPROVE_OPTION) {
File img = chooser.getSelectedFile();
if (img.getAbsolutePath().endsWith(".png")) {
try {
Utils.safeCopy(img, new File(instance.getRootDirectory(), "instance.png"));
image.setImage(instance.getImage().getImage());
instance.save();
} catch (IOException e1) {
e1.printStackTrace(System.err);
}
}
}
}
});
updateItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (instance.hasUpdate() && !instance.hasUpdateBeenIgnored(instance.getLatestVersion()) &&
!instance.isDev()) {
String[] options = {Language.INSTANCE.localize("common.yes"),
Language.INSTANCE.localize("common.no"),
Language.INSTANCE.localize("instance" + "" +
".dontremindmeagain")};
int ret = JOptionPane.showOptionDialog(App.settings.getParent(),
"<html><p align=\"center\">" + Language.INSTANCE.localize("instance" + "" +
".updatenow", "<br/><br/>") + "</p></html>",
Language.INSTANCE.localize("instance" + "" +
".updateavailable"), JOptionPane.DEFAULT_OPTION,
JOptionPane.ERROR_MESSAGE, null, options, options[0]);
if (ret == 0) {
if (App.settings.getAccount() == null) {
String[] optionss = {Language.INSTANCE.localize("common.ok")};
JOptionPane.showOptionDialog(App.settings.getParent(),
Language.INSTANCE.localize("instance.cantupdate"),
Language.INSTANCE.localize("instance.noaccountselected"),
JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE, null,
optionss, optionss[0]);
} else {
new InstanceInstallerDialog(instance, true, false);
}
} else if (ret == 1 || ret == JOptionPane.CLOSED_OPTION) {
if (!App.settings.isMinecraftLaunched()) {
if (instance.launch()) {
App.settings.setMinecraftLaunched(true);
}
}
} else if (ret == 2) {
instance.ignoreUpdate();
if (!App.settings.isMinecraftLaunched()) {
if (instance.launch()) {
App.settings.setMinecraftLaunched(true);
}
}
}
} else {
if (!App.settings.isMinecraftLaunched()) {
if (instance.launch()) {
App.settings.setMinecraftLaunched(true);
}
}
}
}
});
}
}
@Override
public void mouseEntered(MouseEvent e) {
super.mouseEntered(e);
setCursor(new Cursor(Cursor.HAND_CURSOR));
}
@Override
public void mouseExited(MouseEvent e) {
super.mouseExited(e);
setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
});
}
@Override
public void onRelocalization() {
this.playButton.setText(Language.INSTANCE.localize("common.play"));
this.reinstallButton.setText(Language.INSTANCE.localize("common.reinstall"));
this.updateButton.setText(Language.INSTANCE.localize("common.update"));
this.renameButton.setText(Language.INSTANCE.localize("instance.rename"));
this.backupButton.setText(Language.INSTANCE.localize("common.backup"));
this.cloneButton.setText(Language.INSTANCE.localize("instance.clone"));
this.deleteButton.setText(Language.INSTANCE.localize("common.delete"));
this.editButton.setText(Language.INSTANCE.localize("common.editmods"));
this.openButton.setText(Language.INSTANCE.localize("common.openfolder"));
}
}