/** * Set the behavior of the current editing component to display the specified lines of formatted * text when the client hovers over the text. * * <p>Tooltips do not inherit display characteristics, such as color and styles, from the message * component on which they are applied. * * @param lines The lines of formatted text which will be displayed to the client upon hovering. * @return This builder instance. */ public FancyMessage formattedTooltip(FancyMessage... lines) { if (lines.length < 1) { onHover(null, null); // Clear tooltip return this; } FancyMessage result = new FancyMessage(); result.messageParts .clear(); // Remove the one existing text component that exists by default, which // destabilizes the object for (int i = 0; i < lines.length; i++) { try { for (MessagePart component : lines[i]) { if (component.clickActionData != null && component.clickActionName != null) { throw new IllegalArgumentException("The tooltip text cannot have click data."); } else if (component.hoverActionData != null && component.hoverActionName != null) { throw new IllegalArgumentException("The tooltip text cannot have a tooltip."); } if (component.hasText()) { result.messageParts.add(component.clone()); } } if (i != lines.length - 1) { result.messageParts.add(new MessagePart(rawText("\n"))); } } catch (CloneNotSupportedException e) { Bukkit.getLogger().log(Level.WARNING, "Failed to clone object", e); return this; } } return formattedTooltip( result.messageParts.isEmpty() ? null : result); // Throws NPE if size is 0, intended }
@Override public void writeJson(JsonWriter writer) throws IOException { if (messageParts.size() == 1) { latest().writeJson(writer); } else { writer.beginObject().name("text").value("").name("extra").beginArray(); for (final MessagePart part : this) { part.writeJson(writer); } writer.endArray().endObject(); } }
@Override @SuppressWarnings("unchecked") public MessagePart clone() throws CloneNotSupportedException { MessagePart obj = (MessagePart) super.clone(); obj.styles = (ArrayList<ChatColor>) this.styles.clone(); if (this.hoverActionData instanceof JsonString) { obj.hoverActionData = new JsonString(((JsonString) this.hoverActionData).getValue()); } else if (this.hoverActionData instanceof FancyMessage) { obj.hoverActionData = ((FancyMessage) this.hoverActionData).clone(); } obj.translationReplacements = (ArrayList<JsonRepresentedObject>) this.translationReplacements.clone(); return obj; }
@SuppressWarnings("unchecked") public static MessagePart deserialize(Map<String, Object> serialized) { MessagePart part = new MessagePart((TextualComponent) serialized.get("text")); part.styles = (ArrayList<ChatColor>) serialized.get("styles"); part.color = ChatColor.getByChar(serialized.get("color").toString()); part.hoverActionName = (String) serialized.get("hoverActionName"); part.hoverActionData = (JsonRepresentedObject) serialized.get("hoverActionData"); part.clickActionName = (String) serialized.get("clickActionName"); part.clickActionData = (String) serialized.get("clickActionData"); part.insertionData = (String) serialized.get("insertion"); part.translationReplacements = (ArrayList<JsonRepresentedObject>) serialized.get("translationReplacements"); return part; }
/** * Deserializes a fancy message from its JSON representation. This JSON representation is of the * format of that returned by {@link #toJSONString()}, and is compatible with vanilla inputs. * * @param json The JSON string which represents a fancy message. * @return A {@code FancyMessage} representing the parameterized JSON message. */ public static FancyMessage deserialize(String json) { JsonObject serialized = _stringParser.parse(json).getAsJsonObject(); JsonArray extra = serialized.getAsJsonArray("extra"); // Get the extra component FancyMessage returnVal = new FancyMessage(); returnVal.messageParts.clear(); for (JsonElement mPrt : extra) { MessagePart component = new MessagePart(); JsonObject messagePart = mPrt.getAsJsonObject(); for (Map.Entry<String, JsonElement> entry : messagePart.entrySet()) { // Deserialize text if (TextualComponent.isTextKey(entry.getKey())) { // The map mimics the YAML serialization, which has a "key" field and one or more "value" // fields Map<String, Object> serializedMapForm = new HashMap< String, Object>(); // Must be object due to Bukkit serializer API compliance serializedMapForm.put("key", entry.getKey()); if (entry.getValue().isJsonPrimitive()) { // Assume string serializedMapForm.put("value", entry.getValue().getAsString()); } else { // Composite object, but we assume each element is a string for (Map.Entry<String, JsonElement> compositeNestedElement : entry.getValue().getAsJsonObject().entrySet()) { serializedMapForm.put( "value." + compositeNestedElement.getKey(), compositeNestedElement.getValue().getAsString()); } } component.text = TextualComponent.deserialize(serializedMapForm); } else if (MessagePart.stylesToNames.inverse().containsKey(entry.getKey())) { if (entry.getValue().getAsBoolean()) { component.styles.add(MessagePart.stylesToNames.inverse().get(entry.getKey())); } } else if (entry.getKey().equals("color")) { component.color = ChatColor.valueOf(entry.getValue().getAsString().toUpperCase()); } else if (entry.getKey().equals("clickEvent")) { JsonObject object = entry.getValue().getAsJsonObject(); component.clickActionName = object.get("action").getAsString(); component.clickActionData = object.get("value").getAsString(); } else if (entry.getKey().equals("hoverEvent")) { JsonObject object = entry.getValue().getAsJsonObject(); component.hoverActionName = object.get("action").getAsString(); if (object.get("value").isJsonPrimitive()) { // Assume string component.hoverActionData = new JsonString(object.get("value").getAsString()); } else { // Assume composite type // The only composite type we currently store is another FancyMessage // Therefore, recursion time! component.hoverActionData = deserialize( object .get("value") .toString() /* This should properly serialize the JSON object as a JSON string */); } } else if (entry.getKey().equals("insertion")) { component.insertionData = entry.getValue().getAsString(); } else if (entry.getKey().equals("with")) { for (JsonElement object : entry.getValue().getAsJsonArray()) { if (object.isJsonPrimitive()) { component.translationReplacements.add(new JsonString(object.getAsString())); } else { // Only composite type stored in this array is - again - FancyMessages // Recurse within this function to parse this as a translation replacement component.translationReplacements.add(deserialize(object.toString())); } } } } returnVal.messageParts.add(component); } return returnVal; }
private void onHover(final String name, final JsonRepresentedObject data) { final MessagePart latest = latest(); latest.hoverActionName = name; latest.hoverActionData = data; dirty = true; }
private void onClick(final String name, final String data) { final MessagePart latest = latest(); latest.clickActionName = name; latest.clickActionData = data; dirty = true; }
/** * Sets the text of the current editing component to a value. * * @param text The new text of the current editing component. * @return This builder instance. */ public FancyMessage text(TextualComponent text) { MessagePart latest = latest(); latest.text = text; dirty = true; return this; }
/** * Sets the text of the current editing component to a value. * * @param text The new text of the current editing component. * @return This builder instance. */ public FancyMessage text(String text) { MessagePart latest = latest(); latest.text = rawText(text); dirty = true; return this; }