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 java.lang.reflect.Constructor;
import java.util.HashMap;
import org.bukkit.Bukkit;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
@ -33,6 +34,10 @@ abstract public class Gui
*/
private Player player;
/**
* The parent of this GUI (if any).
*/
private Gui parent;
/**
* If the inventory is currently open.
@ -40,14 +45,11 @@ abstract public class Gui
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()
{
setClosed();
}
private boolean immune = false;
/* ===== Public API ===== */
/**
@ -59,6 +61,27 @@ abstract public class Gui
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 ===== */
/**
@ -74,7 +97,7 @@ abstract public class Gui
protected void onAfterUpdate() {}
protected final void setClosed()
protected void onClose()
{
if(open == false) return;
open = false;
@ -94,9 +117,31 @@ abstract public class Gui
/** @return If the GUI is currently open or not. */
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. */
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 ===== */
/**
@ -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.
* @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)
{
close(owner);
((Gui)gui).open(owner);/* JAVA GENERICS Y U NO WORK */
return gui;
return open(owner, gui, null);
}
/**
@ -193,6 +260,7 @@ abstract public class Gui
static public final <T extends Gui> T getOpenGui(HumanEntity entity, Class<T> guiClass)
{
Gui openGui = getOpenGui(entity);
if(openGui == null) return null;
if(!guiClass.isAssignableFrom(openGui.getClass())) return null;
return (T) openGui;
}

View File

@ -112,8 +112,13 @@ abstract public class InventoryGui extends Gui
@Override
public void close()
{
if(!isOpen()) return;
//If close() is called manually, not from InventoryCloseEvent
if(getPlayer().getOpenInventory().equals(inventory))
getPlayer().closeInventory();
super.close();
getPlayer().closeInventory();
}
/**
@ -236,11 +241,16 @@ abstract public class InventoryGui extends Gui
@EventHandler
public void onInventoryClose(InventoryCloseEvent event)
{
Gui openGui = getOpenGui(event.getPlayer());
InventoryGui openGui = getOpenGui(event.getPlayer(), InventoryGui.class);
if(openGui == null) return;
if(!openGui.isOpen());
openGui.setClosed();
if(!event.getInventory().equals(openGui.inventory)) return;
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 java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Location;
@ -46,10 +44,8 @@ public class PromptGui extends Gui
/* ===== Reflection to Sign API ===== */
static private Field fieldSign = null;//CraftSign.sign
static private Field fieldIsEditable = null;//TileEntitySign.isEditable
static private Method methodGetHandle = null;//CraftPlayer.getHandle()
static private Method methodOpenSign = null;//EntityHuman.openSign()
static private Field fieldSignEditor = null;//TileEntitySign.k{EntityHuman}
static private Class classTileEntitySign = null;//CraftBlock.class
static public boolean isAvailable()
@ -60,12 +56,12 @@ public class PromptGui extends Gui
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()
@ -81,10 +77,8 @@ public class PromptGui extends Gui
fieldSign = ReflectionUtils.getField(CraftSign, "sign");
fieldIsEditable = ReflectionUtils.getField(classTileEntitySign, "isEditable");
methodGetHandle = CraftPlayer.getDeclaredMethod("getHandle");
methodOpenSign = EntityHuman.getDeclaredMethod("openSign", classTileEntitySign);
fieldSignEditor = ReflectionUtils.getField(classTileEntitySign, EntityHuman);
}
catch (Exception ex)
{
@ -144,17 +138,17 @@ public class PromptGui extends Gui
}
@Override
public void close()
protected void onClose()
{
Block block = getPlayer().getWorld().getBlockAt(signLocation);
block.setType(Material.AIR);
super.close();
super.onClose();
}
private void validate(String[] 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)

View File

@ -69,12 +69,6 @@ public class ConfirmDeleteMapGui extends ActionGui
*/
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.
*
@ -86,12 +80,10 @@ public class ConfirmDeleteMapGui extends ActionGui
/**
*
* @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.currentPage = currentPage;
}
@Override
@ -165,7 +157,7 @@ public class ConfirmDeleteMapGui extends ActionGui
@GuiAction
protected void action_cancel()
{
Gui.open(getPlayer(), new MapDetailGui(mapToDelete)).setCurrentPageX(currentPage);
close();
}
@GuiAction
@ -184,6 +176,6 @@ public class ConfirmDeleteMapGui extends ActionGui
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);
getPlayer().sendMessage(ChatColor.GRAY + "Map successfuly renamed.");
}
}, map.getName());
}, map.getName(), this);
}
@GuiAction
private void delete()
{
Gui.open(getPlayer(), new ConfirmDeleteMapGui(map, getCurrentPageX()));
Gui.open(getPlayer(), new ConfirmDeleteMapGui(map), this);
}
@Override

View File

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