Introduced GUI relationships.

* NEW: Gui: can now have a parent. If so, a closing GUI will
  open its parent, like a modal dialog.
* NEW: Gui: can now be immune to the next close event, if needed.
* BUG: Gui: getOpenGui() does not throw an NPE anymore if no open
  GUI was found.
* OPT: PromptGui: removed unneeded fields.
This commit is contained in:
Adrien Prokopowicz 2015-10-05 22:35:59 +02:00
parent 96093898c8
commit c4a1310847
6 changed files with 105 additions and 41 deletions

View File

@ -21,6 +21,7 @@ package fr.moribus.imageonmap.guiproko.core;
import fr.moribus.imageonmap.PluginLogger; import fr.moribus.imageonmap.PluginLogger;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.util.HashMap; import java.util.HashMap;
import org.bukkit.Bukkit;
import org.bukkit.entity.HumanEntity; import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
@ -33,6 +34,10 @@ abstract public class Gui
*/ */
private Player player; private Player player;
/**
* The parent of this GUI (if any).
*/
private Gui parent;
/** /**
* If the inventory is currently open. * If the inventory is currently open.
@ -40,13 +45,10 @@ abstract public class Gui
private boolean open = false; private boolean open = false;
/** /**
* Closes this inventory. * If the GUI is immune to close events.
* Useful to filter out excessive InventoryCloseEvents Bukkit sends ...
*/ */
public void close() private boolean immune = false;
{
setClosed();
}
/* ===== Public API ===== */ /* ===== Public API ===== */
@ -59,6 +61,27 @@ abstract public class Gui
onAfterUpdate(); onAfterUpdate();
} }
/**
* Closes this inventory.
*/
public void close()
{
close(false);
}
/**
* Closes this inventory.
* (Dirty hack edition)
* @param immune if true, the parent of this GUI will be set immune when opened
*/
protected void close(boolean immune)
{
onClose();
if(parent != null)
Gui.open(player, parent).setImmune(immune);
}
/* ===== Protected API ===== */ /* ===== Protected API ===== */
/** /**
@ -74,7 +97,7 @@ abstract public class Gui
protected void onAfterUpdate() {} protected void onAfterUpdate() {}
protected final void setClosed() protected void onClose()
{ {
if(open == false) return; if(open == false) return;
open = false; open = false;
@ -94,9 +117,31 @@ abstract public class Gui
/** @return If the GUI is currently open or not. */ /** @return If the GUI is currently open or not. */
public final boolean isOpen() { return open; } public final boolean isOpen() { return open; }
/** @return The parent of this GUI. */
public final Gui getParent() { return parent; }
private void setParent(Gui parent)
{
if(parent == this)
throw new IllegalArgumentException("A GUI cannot be its own parent.");
this.parent = parent;
}
/** @return The player this Gui instance is associated to. */ /** @return The player this Gui instance is associated to. */
protected final Player getPlayer() { return player; } protected final Player getPlayer() { return player; }
protected boolean checkImmune()
{
if(!immune) return false;
immune = false;
return true;
}
private void setImmune(boolean immune)
{
this.immune = immune;
}
/* ===== Static API ===== */ /* ===== Static API ===== */
/** /**
@ -159,6 +204,31 @@ abstract public class Gui
} }
} }
/**
* Opens a GUI for a player.
* @param <T> A GUI type.
* @param owner The player the GUI will be shown to.
* @param gui The GUI.
* @param parent The parent of the newly created GUI. Can be null.
* @return The opened GUI.
*/
static public final <T extends Gui> T open(final Player owner, final T gui, final Gui parent)
{
Gui openGui = openGuis.get(owner);
if(openGui != null) openGui.onClose();
if(parent != null) ((Gui)gui).setParent(parent);
Bukkit.getScheduler().runTaskLater(plugin, new Runnable() {
@Override
public void run()
{
((Gui)gui).open(owner);/* JAVA GENERICS Y U NO WORK */
}
}, 0);
return gui;
}
/** /**
* Opens a GUI for a player. * Opens a GUI for a player.
* @param <T> A GUI type. * @param <T> A GUI type.
@ -168,10 +238,7 @@ abstract public class Gui
*/ */
static public final <T extends Gui> T open(Player owner, T gui) static public final <T extends Gui> T open(Player owner, T gui)
{ {
close(owner); return open(owner, gui, null);
((Gui)gui).open(owner);/* JAVA GENERICS Y U NO WORK */
return gui;
} }
/** /**
@ -193,6 +260,7 @@ abstract public class Gui
static public final <T extends Gui> T getOpenGui(HumanEntity entity, Class<T> guiClass) static public final <T extends Gui> T getOpenGui(HumanEntity entity, Class<T> guiClass)
{ {
Gui openGui = getOpenGui(entity); Gui openGui = getOpenGui(entity);
if(openGui == null) return null;
if(!guiClass.isAssignableFrom(openGui.getClass())) return null; if(!guiClass.isAssignableFrom(openGui.getClass())) return null;
return (T) openGui; return (T) openGui;
} }

View File

@ -112,8 +112,13 @@ abstract public class InventoryGui extends Gui
@Override @Override
public void close() public void close()
{ {
super.close(); if(!isOpen()) return;
//If close() is called manually, not from InventoryCloseEvent
if(getPlayer().getOpenInventory().equals(inventory))
getPlayer().closeInventory(); getPlayer().closeInventory();
super.close();
} }
/** /**
@ -236,11 +241,16 @@ abstract public class InventoryGui extends Gui
@EventHandler @EventHandler
public void onInventoryClose(InventoryCloseEvent event) public void onInventoryClose(InventoryCloseEvent event)
{ {
Gui openGui = getOpenGui(event.getPlayer()); InventoryGui openGui = getOpenGui(event.getPlayer(), InventoryGui.class);
if(openGui == null) return; if(openGui == null) return;
if(!openGui.isOpen()); if(!event.getInventory().equals(openGui.inventory)) return;
openGui.setClosed();
if(openGui.isOpen())
{
if(openGui.checkImmune()) return;
openGui.close();
}
} }
} }

View File

@ -23,8 +23,6 @@ import fr.moribus.imageonmap.PluginLogger;
import fr.moribus.imageonmap.ReflectionUtils; import fr.moribus.imageonmap.ReflectionUtils;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Chunk; import org.bukkit.Chunk;
import org.bukkit.Location; import org.bukkit.Location;
@ -46,10 +44,8 @@ public class PromptGui extends Gui
/* ===== Reflection to Sign API ===== */ /* ===== Reflection to Sign API ===== */
static private Field fieldSign = null;//CraftSign.sign static private Field fieldSign = null;//CraftSign.sign
static private Field fieldIsEditable = null;//TileEntitySign.isEditable
static private Method methodGetHandle = null;//CraftPlayer.getHandle() static private Method methodGetHandle = null;//CraftPlayer.getHandle()
static private Method methodOpenSign = null;//EntityHuman.openSign() static private Method methodOpenSign = null;//EntityHuman.openSign()
static private Field fieldSignEditor = null;//TileEntitySign.k{EntityHuman}
static private Class classTileEntitySign = null;//CraftBlock.class static private Class classTileEntitySign = null;//CraftBlock.class
static public boolean isAvailable() static public boolean isAvailable()
@ -60,12 +56,12 @@ public class PromptGui extends Gui
static public void prompt(Player owner, Callback<String> callback) static public void prompt(Player owner, Callback<String> callback)
{ {
prompt(owner, callback, ""); prompt(owner, callback, "", null);
} }
static public void prompt(Player owner, Callback<String> callback, String contents) static public void prompt(Player owner, Callback<String> callback, String contents, Gui parent)
{ {
Gui.open(owner, new PromptGui(callback, contents)); Gui.open(owner, new PromptGui(callback, contents), parent);
} }
static private void init() static private void init()
@ -81,10 +77,8 @@ public class PromptGui extends Gui
fieldSign = ReflectionUtils.getField(CraftSign, "sign"); fieldSign = ReflectionUtils.getField(CraftSign, "sign");
fieldIsEditable = ReflectionUtils.getField(classTileEntitySign, "isEditable");
methodGetHandle = CraftPlayer.getDeclaredMethod("getHandle"); methodGetHandle = CraftPlayer.getDeclaredMethod("getHandle");
methodOpenSign = EntityHuman.getDeclaredMethod("openSign", classTileEntitySign); methodOpenSign = EntityHuman.getDeclaredMethod("openSign", classTileEntitySign);
fieldSignEditor = ReflectionUtils.getField(classTileEntitySign, EntityHuman);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -144,17 +138,17 @@ public class PromptGui extends Gui
} }
@Override @Override
public void close() protected void onClose()
{ {
Block block = getPlayer().getWorld().getBlockAt(signLocation); Block block = getPlayer().getWorld().getBlockAt(signLocation);
block.setType(Material.AIR); block.setType(Material.AIR);
super.close(); super.onClose();
} }
private void validate(String[] lines) private void validate(String[] lines)
{ {
callback.call(getSignContents(lines)); callback.call(getSignContents(lines));
this.close(); this.close(true);//Bukkit sends extra InventoryCloseEvents when closing a sign GUI...
} }
static private String getSignContents(String[] lines) static private String getSignContents(String[] lines)

View File

@ -69,12 +69,6 @@ public class ConfirmDeleteMapGui extends ActionGui
*/ */
private final ImageMap mapToDelete; private final ImageMap mapToDelete;
/**
* The previously-viewed page of the list GUI.
* Used to be able to bring the user back to the same page.
*/
private final int currentPage;
/** /**
* A source of randomness. * A source of randomness.
* *
@ -86,12 +80,10 @@ public class ConfirmDeleteMapGui extends ActionGui
/** /**
* *
* @param mapToDelete The map being deleted. * @param mapToDelete The map being deleted.
* @param currentPage The previously-viewed page of the list GUI.
*/ */
public ConfirmDeleteMapGui(ImageMap mapToDelete, int currentPage) public ConfirmDeleteMapGui(ImageMap mapToDelete)
{ {
this.mapToDelete = mapToDelete; this.mapToDelete = mapToDelete;
this.currentPage = currentPage;
} }
@Override @Override
@ -165,7 +157,7 @@ public class ConfirmDeleteMapGui extends ActionGui
@GuiAction @GuiAction
protected void action_cancel() protected void action_cancel()
{ {
Gui.open(getPlayer(), new MapDetailGui(mapToDelete)).setCurrentPageX(currentPage); close();
} }
@GuiAction @GuiAction
@ -184,6 +176,6 @@ public class ConfirmDeleteMapGui extends ActionGui
getPlayer().sendMessage(ChatColor.RED + ex.getMessage()); getPlayer().sendMessage(ChatColor.RED + ex.getMessage());
} }
Gui.open(getPlayer(), new MapListGui(/* currentPage */)); close();
} }
} }

View File

@ -84,13 +84,13 @@ public class MapDetailGui extends ExplorerGui<Void>
map.rename(newName); map.rename(newName);
getPlayer().sendMessage(ChatColor.GRAY + "Map successfuly renamed."); getPlayer().sendMessage(ChatColor.GRAY + "Map successfuly renamed.");
} }
}, map.getName()); }, map.getName(), this);
} }
@GuiAction @GuiAction
private void delete() private void delete()
{ {
Gui.open(getPlayer(), new ConfirmDeleteMapGui(map, getCurrentPageX())); Gui.open(getPlayer(), new ConfirmDeleteMapGui(map), this);
} }
@Override @Override

View File

@ -69,7 +69,7 @@ public class MapListGui extends ExplorerGui<ImageMap>
@Override @Override
protected void onRightClick(ImageMap map) protected void onRightClick(ImageMap map)
{ {
Gui.open(getPlayer(), new MapDetailGui(map)); Gui.open(getPlayer(), new MapDetailGui(map), this);
} }
@Override @Override