package com.giftoftheembalmer.gotefarm.client; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.event.dom.client.KeyPressEvent; import com.google.gwt.event.dom.client.KeyPressHandler; import com.google.gwt.event.logical.shared.ValueChangeEvent; import com.google.gwt.event.logical.shared.ValueChangeHandler; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.DeferredCommand; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.FlexTable; import com.google.gwt.user.client.ui.Grid; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.HasHorizontalAlignment; import com.google.gwt.user.client.ui.HasValue; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.PopupPanel; import com.google.gwt.user.client.ui.RadioButton; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.HTMLTable.CellFormatter; import com.google.gwt.xml.client.Document; import com.google.gwt.xml.client.NamedNodeMap; import com.google.gwt.xml.client.Node; import com.google.gwt.xml.client.NodeList; import com.google.gwt.xml.client.XMLParser; import java.util.ArrayList; import java.util.List; public class Characters extends Composite implements HasValue<List<JSCharacter>>, ValueChangeHandler<JSGuild> { VerticalPanel vpanel = new VerticalPanel(); VerticalPanel chrpanel = new VerticalPanel(); private List<JSCharacter> characters = new ArrayList<JSCharacter>(); private List<JSRole> roles = new ArrayList<JSRole>(); private List<JSBadge> badges = new ArrayList<JSBadge>(); private JSGuild current_guild; public void addCharacter(JSCharacter chr) { characters.add(chr); chrpanel.add(new Character(chr)); fireCharacterChangedEvent(); } public void replaceCharacter(JSCharacter oldchr, JSCharacter newchr) { int idx = characters.indexOf(oldchr); if (idx > -1) { characters.set(idx, newchr); fireCharacterChangedEvent(); } } private void fireCharacterChangedEvent() { // Send out a copy of the list so our copy is still // safe to change. List<JSCharacter> c = new ArrayList<JSCharacter>(characters.size()); c.addAll(characters); ValueChangeEvent.fire(this, c); } public class Character extends Composite { JSCharacter chr = null; VerticalPanel vpanel = new VerticalPanel(); HorizontalPanel hpanel = new HorizontalPanel(); VerticalPanel attr_vpanel = new VerticalPanel(); HorizontalPanel role_and_badge_panel = new HorizontalPanel(); RoleAndBadgeEditor role_editor = new RoleAndBadgeEditor("Roles"); RoleAndBadgeEditor badge_editor = new RoleAndBadgeEditor("Badges"); private final RadioButton name_check = new RadioButton("main_chr"); private final static String MAIN_TOOLTIP = "This is your \"main\" " + "character, you will be identified to other users as this " + "character."; private final static String NOT_MAIN_TOOLTIP = "Click to make this " + "your \"main\" character."; public Character(final JSCharacter chr) { this.chr = chr; vpanel.setSpacing(10); hpanel.setSpacing(2); hpanel.add(attr_vpanel); name_check.addValueChangeHandler(new ValueChangeHandler<Boolean>() { public void onValueChange(ValueChangeEvent<Boolean> event) { if (event.getValue() == false) { // losing main status return; } // inform the server GoteFarm.goteService.setMainCharacter(current_guild.key, chr.key, new AsyncCallback<Void>() { public void onSuccess(Void v) { // worked! update our cached JSCharacters Characters.this.setMainCharacter(chr.key); } public void onFailure(Throwable caught) { // need to revert the UI Characters.this.revertMainCharacter(); // TODO: display error message somewhere } }); } }); name_check.setText(chr.name); setMain(chr.main); attr_vpanel.add(name_check); attr_vpanel.add(new Label(chr.race)); attr_vpanel.add(new Label(chr.clazz)); attr_vpanel.add(new Label("Level " + chr.level)); try { Document xml = XMLParser.parse(chr.characterxml); NodeList items = xml.getElementsByTagName("items"); if (items != null) { for (int i = 0; i < items.getLength(); ++i) { Node node = items.item(i); NodeList subitems = node.getChildNodes(); for (int j = 0; j < subitems.getLength(); ++j) { Node subitem = subitems.item(j); if (!subitem.getNodeName().equals("item")) { continue; } NamedNodeMap attribs = subitem.getAttributes(); if (attribs != null) { Node id = attribs.getNamedItem("id"); Node icon = attribs.getNamedItem("icon"); HTML link = new HTML("<a target=\"_blank\" href=\"http://www.wowhead.com/?item=" + id + "\"><img src=\"http://static.wowhead.com/images/icons/medium/" + icon + ".jpg\"/></a>"); hpanel.add(link); } } } } NodeList characters = xml.getElementsByTagName("character"); if (characters != null) { Node character = characters.item(0); NamedNodeMap attribs = character.getAttributes(); Node updated = attribs.getNamedItem("lastModified"); attr_vpanel.add(new Label("Armory updated: " + updated)); } } catch (Throwable e) { attr_vpanel.add(new Label( "Error parsing XML: " + e.getMessage())); } updateRoles(); updateBadges(); vpanel.add(hpanel); role_and_badge_panel.setWidth("100%"); role_and_badge_panel.add(role_editor); role_and_badge_panel.add(badge_editor); vpanel.add(role_and_badge_panel); initWidget(vpanel); setStyleName("Character"); } class RoleClickHandler extends BadgeAndRoleClickHandler { public RoleClickHandler(String flavor1, FlexTable flex, int row, ChrBadgeAndRole role) { super(flavor1, flex, row, role); } public void updateCharacterRole(boolean adding) { GoteFarm.goteService.updateCharacterRole(chr.key, role.getKey(), adding, new AsyncCallback<JSCharacter>() { public void onSuccess(JSCharacter result) { replaceCharacter(Character.this.chr, result); Character.this.chr = result; } public void onFailure(Throwable caught) { } }); } } class RoleClickHandlerFactory extends BadgeAndRoleClickHandlerFactory { public BadgeAndRoleClickHandler newClickHandler(FlexTable flex, int row, ChrBadgeAndRole role) { return new RoleClickHandler("role", flex, row, role); } } class BadgeClickHandler extends BadgeAndRoleClickHandler { public BadgeClickHandler(String flavor1, FlexTable flex, int row, ChrBadgeAndRole role) { super(flavor1, flex, row, role); } public void updateCharacterRole(boolean adding) { GoteFarm.goteService.updateCharacterBadge(chr.key, role.getKey(), adding, new AsyncCallback<JSCharacter>() { public void onSuccess(JSCharacter result) { replaceCharacter(Character.this.chr, result); Character.this.chr = result; } public void onFailure(Throwable caught) { } }); } } class BadgeClickHandlerFactory extends BadgeAndRoleClickHandlerFactory { public BadgeAndRoleClickHandler newClickHandler(FlexTable flex, int row, ChrBadgeAndRole role) { return new BadgeClickHandler("badge", flex, row, role); } } public void updateRoles() { role_editor.update(roles, chr.roles, new RoleClickHandlerFactory()); } public void updateBadges() { badge_editor.update(badges, chr.badges, new BadgeClickHandlerFactory()); } public boolean isMain() { return chr.main; } public void setMain(boolean main) { chr.main = main; if (chr.main) { name_check.setValue(main); name_check.setTitle(MAIN_TOOLTIP); } else { name_check.setTitle(NOT_MAIN_TOOLTIP); } } public JSCharacter getCharacter() { return chr; } } public class NewCharPanel extends PopupPanel { TextBox character = new TextBox(); Label errmsg = new Label(); public NewCharPanel() { super(false); VerticalPanel vpanel = new VerticalPanel(); Grid grid = new Grid(1, 2); grid.setWidth("100%"); CellFormatter cf = grid.getCellFormatter(); // right align field labels cf.setHorizontalAlignment(0, 0, HasHorizontalAlignment.ALIGN_RIGHT); grid.setText(0, 0, "Character Name:"); grid.setWidget(0, 1, character); vpanel.add(grid); vpanel.add(errmsg); errmsg.addStyleName(errmsg.getStylePrimaryName() + "-error"); HorizontalPanel hpanel = new HorizontalPanel(); hpanel.setWidth("100%"); character.addKeyPressHandler(new KeyPressHandler() { public void onKeyPress(KeyPressEvent event) { if (event.getCharCode() == KeyCodes.KEY_ENTER) { addCharacter(); } } }); hpanel.add(new Button("Submit", new ClickHandler() { public void onClick(ClickEvent event) { addCharacter(); } })); hpanel.add(new Button("Cancel", new ClickHandler() { public void onClick(ClickEvent event) { hide(); } })); vpanel.add(hpanel); DeferredCommand.addCommand(new Command() { public void execute() { character.setFocus(true); } }); setWidget(vpanel); } public void addCharacter() { errmsg.setText(""); GoteFarm.goteService.newCharacter( current_guild.key, character.getText(), new AsyncCallback<JSCharacter>() { public void onSuccess(JSCharacter chr) { Characters.this.addCharacter(chr); hide(); } public void onFailure(Throwable caught) { try { throw caught; } catch (AlreadyExistsError e) { errmsg.setText("Character already enrolled."); } catch (NotFoundError e) { errmsg.setText("Character not found on Armory."); } catch (Throwable e) { errmsg.setText(e.toString()); } } }); } } Button enrollbtn = null; public Characters() { vpanel.setWidth("100%"); chrpanel.setSpacing(20); vpanel.add(chrpanel); enrollbtn = new Button("Enroll Character", new ClickHandler() { public void onClick(ClickEvent event) { final NewCharPanel popup = new NewCharPanel(); popup.setPopupPositionAndShow(new NewCharPanel.PositionCallback() { public void setPosition(int offsetWidth, int offsetHeight) { int left = (Window.getClientWidth() - offsetWidth) / 3; int top = (Window.getClientHeight() - offsetHeight) / 3; popup.setPopupPosition(left, top); } }); } }); vpanel.add(enrollbtn); loadCharacters(); initWidget(vpanel); setStyleName("Characters"); } protected void revertMainCharacter() { for (Character c : character_widgets) { if (c.isMain()) { c.setMain(true); break; } } } protected void setMainCharacter(String key) { for (Character c : character_widgets) { // touch every Character so all JSCharacters are updated c.setMain(c.getCharacter().key.equals(key)); } } private List<Character> character_widgets = new ArrayList<Character>(); public void loadCharacters() { chrpanel.clear(); if (current_guild == null) { chrpanel.add(new Label("Loading...")); enrollbtn.setEnabled(false); return; } else if (current_guild.key == null) { chrpanel.add(new Label("Select a guild before managing characters.")); enrollbtn.setEnabled(false); return; } enrollbtn.setEnabled(true); GoteFarm.goteService.getCharacters( current_guild.key, new AsyncCallback<List<JSCharacter>>() { public void onSuccess(List<JSCharacter> result) { setValue(result, true); character_widgets.clear(); for (JSCharacter c : result) { Character nc = new Character(c); character_widgets.add(nc); chrpanel.add(nc); } } public void onFailure(Throwable caught) { } }); GoteFarm.goteService.getRoles(current_guild.key, new AsyncCallback<List<JSRole>>() { public void onSuccess(List<JSRole> result) { roles = result; for (Character c : character_widgets) { c.updateRoles(); } } public void onFailure(Throwable caught) { } }); GoteFarm.goteService.getBadges(current_guild.key, new AsyncCallback<List<JSBadge>>() { public void onSuccess(List<JSBadge> result) { badges = result; for (Character c : character_widgets) { c.updateBadges(); } } public void onFailure(Throwable caught) { } }); } public List<JSCharacter> getValue() { return characters; } public void setValue(List<JSCharacter> value) { setValue(value, false); } public void setValue(List<JSCharacter> value, boolean fireEvents) { if (value == null) { throw new IllegalArgumentException("value must not be null"); } if (value.equals(characters)) { return; } characters = value; if (fireEvents) { fireCharacterChangedEvent(); } } public HandlerRegistration addValueChangeHandler( ValueChangeHandler<List<JSCharacter>> handler) { return addHandler(handler, ValueChangeEvent.getType()); } public void onValueChange(ValueChangeEvent<JSGuild> event) { // need to fetch the characters enrolled for this guild current_guild = event.getValue(); loadCharacters(); } }