package io.andrewohara.tinkertime.views.modSelector;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JList;
import javax.swing.ListCellRenderer;
import javax.swing.Timer;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import io.andrewohara.common.Util;
import io.andrewohara.common.content.ImageManager;
import io.andrewohara.common.views.Dialogs;
import io.andrewohara.common.views.ProgressSpinnerPanel;
import io.andrewohara.common.workflows.tasks.TaskCallback;
import io.andrewohara.common.workflows.tasks.WorkflowTask.TaskEvent;
import io.andrewohara.common.workflows.tasks.WorkflowTask.TaskExceptionEvent;
import io.andrewohara.tinkertime.models.mod.Mod;
import thirdParty.CompoundIcon;
/**
* Custom ListCellRenderer for a Mod to be displayed on a JList.
*
* Displays the Mod name, all status icons to the left of it, and the Progress
* Spinner to the right.
*
* @author Andrew O'Hara
*/
@Singleton
public class ModListCellRenderer extends TaskCallback implements ListCellRenderer<Mod> {
private final Map<Mod, ProgressSpinnerPanel> elements = new HashMap<>();
private final ImageManager imageManager;
private Timer frameTimer;
private final Dialogs dialogs;
@Inject
ModListCellRenderer(ImageManager imageManager, Dialogs dialogs){
this.imageManager = imageManager;
this.dialogs = dialogs;
}
protected ImageIcon getEnabledIcon(){
return loadIcon(imageManager, "glyphicons_152_check.png", "Mod Enabled", new Color(70, 210, 70));
}
protected ImageIcon getDisabledIcon(){
return loadIcon(imageManager, "glyphicons_207_remove_2.png", "Mod Disabled", new Color(205, 20, 20));
}
protected ImageIcon getErrorIcon(){
return loadIcon(imageManager, "glyphicons_078_warning_sign.png", "Mod Zip not found. Please update", new Color(215, 160, 0));
}
protected ImageIcon getUpdateIcon(){
return loadIcon(imageManager, "glyphicons_213_up_arrow.png", "Update Available", new Color(255, 200, 0));
}
protected ImageIcon getLocalIcon(){
return loadIcon(imageManager, "glyphicons_410_compressed.png", "Mod added locally. Not updateable", new Color(0, 0, 0));
}
private ImageIcon loadIcon(ImageManager imageManager, String name, String description, Color colour){
BufferedImage image = imageManager.getImage("icon/" + name);
image = colour != null ? imageManager.colorize(image, colour) : image;
return new ImageIcon(image, description);
}
private ImageIcon[] getCurrentIcons(Mod mod){
LinkedList<ImageIcon> icons = new LinkedList<>();
icons.add(mod.isEnabled() ? getEnabledIcon() : getDisabledIcon());
if (mod.isUpdateAvailable() || !mod.isDownloaded()){
icons.add(getUpdateIcon());
}
if (mod.getUrl() == null){
icons.add(getLocalIcon());
}
return icons.toArray(new ImageIcon[0]);
}
@Override
public Component getListCellRendererComponent(final JList<? extends Mod> list,
Mod mod, int index, boolean isSelected, boolean cellHasFocus) {
// Compile list of icons
ImageIcon[] icons = getCurrentIcons(mod);
// Create cell label
String text = mod.getName();
if (mod.getSupportedVersion() != null){
text = String.format("[%s] %s", mod.getSupportedVersion(), text);
}
String tooltipText = String.format("<html>%s</html>", Util.joinStrings(icons, "<br/>"));
if (!elements.containsKey(mod)){
elements.put(mod, ProgressSpinnerPanel.create());
}
ProgressSpinnerPanel ele = elements.get(mod);
ele.setText(text);
ele.setIcon(new CompoundIcon(icons));
ele.setBorder(isSelected ? BorderFactory.createLineBorder(Color.black) : null);
ele.setToolTipText(tooltipText);
if (frameTimer == null){
frameTimer = new Timer(20, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
list.repaint();
}
});
frameTimer.start();
}
return ele;
}
@Override
protected void processTaskEvent(final TaskEvent event) {
Object context = event.getTask().getWorkflow().context;
if (context == null || !elements.containsKey(context)){
return;
}
final ProgressSpinnerPanel element = elements.get(context);
switch(event.getTask().getStatus()){
case Ready:
break; // Ignored
case Running:
// If a new task has begun, show progress spinner
if (!element.isRunning()){
element.start();
new Runnable(){
@Override
public void run(){
element.setMaxProgress(event.getTask().getTargetProgress());
}
}.run();
} else {
element.setProgress(event.getTask().getProgress());
}
break;
case Exception:
dialogs.errorDialog(element, ((TaskExceptionEvent)event).exception);
case Success:
case Failure:
element.reset();
break;
}
}
}