package com.iambookmaster.client.paragraph; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.Image; import com.google.gwt.user.client.ui.MenuBar; import com.google.gwt.user.client.ui.PopupPanel; import com.google.gwt.user.client.ui.Widget; import com.iambookmaster.client.Images; import com.iambookmaster.client.Styles; import com.iambookmaster.client.beans.Paragraph; import com.iambookmaster.client.beans.ParagraphConnection; import com.iambookmaster.client.common.ColorProvider; import com.iambookmaster.client.common.EditorTab; import com.iambookmaster.client.common.MaskPanel; import com.iambookmaster.client.editor.MapEditor; import com.iambookmaster.client.locale.AppConstants; import com.iambookmaster.client.locale.AppLocale; import com.iambookmaster.client.model.Model; import com.iambookmaster.client.model.ParagraphConnectionListener; import com.iambookmaster.client.model.ParagraphListener; import com.iambookmaster.client.model.SettingsListener; import com.iambookmaster.client.paragraph.PathFinder.GameState; public class ParagraphsMapEditor extends MapEditor implements EditorTab{ private final AppConstants appConstants = AppLocale.getAppConstants(); private Model model; private Map<Paragraph,ParagraphWidget> locations = new HashMap<Paragraph,ParagraphWidget>(); private Map<ParagraphConnection,LocationConnectionWidget> connections = new HashMap<ParagraphConnection,LocationConnectionWidget>(); private ParagraphListener locationListener; private ParagraphConnectionListener locationConnectionListener; private LocationMenuPanel locationMenuPanel; private NewConnectionPanel newConnectionPanel; private ParagraphWidget selectedWidget; private ParagraphWidget selectedWidget2; private boolean active; private HashSet<Paragraph> updataParagraphs = new HashSet<Paragraph>(); private HashSet<ParagraphConnection> updataConnections = new HashSet<ParagraphConnection>(); private boolean updateAll; private SettingsListener settingsListener; private boolean showParagraphNumbers; private Timer updateTimer; public void activate() { if (selectedWidget != null) { selectedWidget.hightlight(false); } if (updateAll) { updateAll = false; updataConnections.clear(); updataParagraphs.clear(); updateAllConnections(); } else { if (updataParagraphs.size()>0) { for (Iterator<Paragraph> iter = updataParagraphs.iterator(); iter.hasNext();) { Paragraph paragraph = iter.next(); ParagraphWidget widget = locations.get(paragraph); if (widget != null) { widget.updateParagraph(paragraph); } } updataParagraphs.clear(); } if (updataConnections.size()>0) { for (Iterator<ParagraphConnection> iter = updataConnections.iterator(); iter.hasNext();) { ParagraphConnection connection = iter.next(); LocationConnectionWidget widget = connections.get(connection); if (widget != null) { widget.updateConnection(connection); } } updataConnections.clear(); } } selectedWidget = locations.get(model.getCurrentParagraph()); if (selectedWidget != null) { selectedWidget.hightlight(true); } active = true; } public void deactivate() { active = false; } public ParagraphsMapEditor(Model mod) { super(mod.getSettings().getMaxDimensionX(),mod.getSettings().getMaxDimensionY()); // DOM.setStyleAttribute(getElement(), "border", "2px solid green"); this.model = mod; locationListener = new ParagraphListener(){ public void addNewParagraph(Paragraph location) { if (location.getX()==0 && location.getY()==0) { location.setX(getSelectedPositionX()+20); location.setY(getSelectedPositionY()+20); } new ParagraphWidget(location); } public void refreshAll() { refreshLocations(); } public void select(Paragraph location) { // // System.out.println("select.active="+active); // selectedWidget = locations.get(location); if (active && selectedWidget != null) { selectedWidget.hightlight(true); ensureVisible(selectedWidget); } } public void unselect(Paragraph location) { ParagraphWidget widget = locations.get(location); if (widget != null) { widget.hightlight(false); } selectedWidget = null; } public void update(Paragraph location) { // // System.out.println("update.active="+active); // ParagraphWidget widget = locations.get(location); if (widget != null) { if (active) { widget.updateParagraph(location); } else { updataParagraphs.add(location); } } } public void edit(Paragraph location) { //not our task } public void remove(Paragraph location) { ParagraphWidget widget = locations.get(location); if (widget != null) { widget.delete(); } } }; model.addParagraphListener(locationListener); showParagraphNumbers = model.getSettings().isShowParagraphNumbers(); settingsListener = new SettingsListener() { public void settingsWereUpated() { if (showParagraphNumbers != model.getSettings().isShowParagraphNumbers()) { showParagraphNumbers = model.getSettings().isShowParagraphNumbers(); //TODO refreshLocations(); } applyMapSize(model.getSettings().getMaxDimensionX(),model.getSettings().getMaxDimensionY()); } }; model.addSettingsListener(settingsListener); locationConnectionListener = new ParagraphConnectionListener() { public void refreshAll() { } public void select(ParagraphConnection connection) { LocationConnectionWidget connectionWidget = connections.get(connection); if (connectionWidget != null) { selectWidget(null,connectionWidget); } } public void unselect(ParagraphConnection connection) { LocationConnectionWidget connectionWidget = connections.get(connection); if (connectionWidget != null) { selectWidget(null,null); } } public void update(ParagraphConnection connection) { LocationConnectionWidget connectionWidget = connections.get(connection); if (connectionWidget != null) { System.out.println("connection.update.active="+active); if (active) { connectionWidget.updateConnection(connection); } else { updataConnections.add(connection); } } } public void remove(ParagraphConnection connection) { LocationConnectionWidget connectionWidget = connections.get(connection); if (connectionWidget != null) { connectionWidget.remove(); } } public void addNew(ParagraphConnection connection) { ParagraphWidget widget1 = locations.get(connection.getFrom()); ParagraphWidget widget2 = locations.get(connection.getTo()); if (widget1 != null && widget2 != null) { connections.put(connection,new LocationConnectionWidget(connection,widget1,widget2)); System.out.println("connection.addNew.active="+active); if (active==false) { updataConnections.add(connection); } } } }; model.addParagraphConnectionListener(locationConnectionListener); locationMenuPanel = new LocationMenuPanel(); newConnectionPanel = new NewConnectionPanel(); } public void refreshLocations() { if (active) { updateAllConnections(); } else { updateAll = true; } } protected void updateAllConnections() { if (updateTimer != null) { return; } MaskPanel.show(); clear(); connections.clear(); updateTimer = new Timer() { private ArrayList<Paragraph> list = new ArrayList<Paragraph>(model.getParagraphs()); private Iterator<Paragraph> iteratorParagraph = list.iterator(); private ArrayList<ParagraphConnection> listConnections = new ArrayList<ParagraphConnection>(model.getParagraphConnections()); private Iterator<ParagraphConnection> iteratorConnection = listConnections.iterator(); private HashMap<Paragraph, ParagraphWidget>map = new HashMap<Paragraph, ParagraphWidget>(list.size()); private int first; @Override public void run() { if (first==0) { first = 1; int w = getOffsetWidth(); int h = getOffsetHeight(); //add visible paragraphs while (iteratorParagraph.hasNext()) { Paragraph paragraph = iteratorParagraph.next(); if (w>=paragraph.getX() && h >=paragraph.getY()) { //visible now, draw now map.put(paragraph, new ParagraphWidget(paragraph)); iteratorParagraph.remove(); } } //add visible connections while (iteratorConnection.hasNext()) { ParagraphConnection connection = iteratorConnection.next(); ParagraphWidget widget1 = map.get(connection.getFrom()); ParagraphWidget widget2 = map.get(connection.getTo()); if (widget1==null && widget2 != null) { //only one of widget exists list.remove(connection.getFrom()); map.put(connection.getFrom(), new ParagraphWidget(connection.getFrom())); } else if (widget1 != null && widget2 == null) { //only one of widget exists list.remove(connection.getTo()); map.put(connection.getTo(), new ParagraphWidget(connection.getTo())); } } iteratorConnection = listConnections.iterator(); iteratorParagraph = list.iterator(); return; } else if (first==1) { first = 2; //add visible connections while (iteratorConnection.hasNext()) { ParagraphConnection connection = iteratorConnection.next(); ParagraphWidget widget1 = map.get(connection.getFrom()); ParagraphWidget widget2 = map.get(connection.getTo()); if (widget1 !=null && widget2 != null) { connections.put(connection,new LocationConnectionWidget(connection,widget1,widget2)); iteratorConnection.remove(); } } iteratorConnection = listConnections.iterator(); //remove mask and add other paragraphs in shadow MaskPanel.hide(); return; } //add other staff int count=50; if (iteratorParagraph.hasNext()) { while (iteratorParagraph.hasNext()) { Paragraph location = iteratorParagraph.next(); map.put(location, new ParagraphWidget(location)); if (count--<0) { return; } } //pause between last paragraph and first connection return; } while (iteratorConnection.hasNext()) { ParagraphConnection connection = iteratorConnection.next(); ParagraphWidget widget1 = map.get(connection.getFrom()); ParagraphWidget widget2 = map.get(connection.getTo()); if (widget1 != null && widget2 != null) { connections.put(connection,new LocationConnectionWidget(connection,widget1,widget2)); } if (count--<0) { return; } } updateTimer = null; cancel(); MaskPanel.hide(); } }; updateTimer.scheduleRepeating(50); } public class ParagraphWidget extends MapWidget { private Paragraph location; private Image typeImage; public ParagraphWidget(Paragraph location) { this.location = location; locations.put(location,this); applyTitleStyle(); draw(location.getX(),location.getY()); } //usually is called externally public void updateParagraph(Paragraph location) { this.location = location; //usually - useless, it should be the same applyTypeToImage(); applyTitleStyle(); redraw(location.getX(),location.getY()); } private void applyTitleStyle() { String style = "paragraph_map_prop"; switch (location.getStatus()) { case Model.STATUS_DRAFT: style = "paragraph_map_draft"; break; case Model.STATUS_FINAL: style = "paragraph_map_final"; break; } // if (location.getBattle() != null) { // style = style + " paragraph_map_battle"; // } setTitleStyle(style); } public String getFullName() { if (model.getSettings().isShowParagraphNumbers() && location.getNumber()>0) { return String.valueOf(location.getNumber())+". "+location.getName(); } else { return location.getName(); } } public String getName() { return location.getName() ; } public void connectTo(MapWidget mapWidget) { if (mapWidget instanceof ParagraphWidget) { selectedWidget2 = (ParagraphWidget) mapWidget; if (this==selectedWidget2) { //useless return; } if (model.getSettings().isOneWayConnectionsOnly()) { //one way connection only addNewConnection(this,selectedWidget2,false); } else { selectedWidget = this; int x = getAbsoluteLeft(); int y = getAbsoluteTop(); newConnectionPanel.setPopupPosition(x,y); newConnectionPanel.show(); } } else { Window.alert(appConstants.cannotConnectParagraphToNonParagraph()); } } protected void updatePosition(int x, int y) { location.setX(x); location.setY(y); model.updateParagraph(location,locationListener); } public Widget getQuickWidget() { typeImage = new Image(); typeImage.setStyleName(Styles.CLICKABLE); typeImage.setTitle(appConstants.titleContextMenu()); typeImage.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { selectedWidget = ParagraphWidget.this; int w= Window.getClientWidth()-220; int h = Window.getClientHeight()-230; int l = typeImage.getAbsoluteLeft(); int t = typeImage.getAbsoluteTop(); if (w<l) { l = w; } if (h<t) { t = h; } if (l<0) { l = 0; } if (t<0) { t = 0; } locationMenuPanel.setPopupPosition(l,t); locationMenuPanel.show(); } }); applyTypeToImage(); return typeImage; } private void applyTypeToImage() { typeImage.setUrl(getParagraphTypeURL(location)); } public void select() { model.selectParagraph(location,locationListener); } public void onNameChanged(String name) { location.setName(name); model.updateParagraph(location, locationListener); redraw(location.getX(), location.getY()); } public void unselect() { model.unselectParagraph(location,locationListener); } } public class LocationConnectionWidget extends MapConnector { private ParagraphConnection connection; public LocationConnectionWidget(ParagraphConnection connection,ParagraphWidget widget1, ParagraphWidget widget2) { super(widget1, widget2,connection.isBothDirections(),connection.getType()== ParagraphConnection.TYPE_NORMAL && connection.getObject()==null ? MapEditor.STYLE_NORMAL : MapEditor.STYLE_CONDITIONAL,ColorProvider.getColorName(connection.getColor()),connection.getCorrectionX(),connection.getCorrectionY()); this.connection = connection; update(); applySource(); } public void updateConnection(ParagraphConnection connection) { this.connection = connection; if (this.connection==null) { this.connection = connection; } int style; if (connection.getType()== ParagraphConnection.TYPE_NORMAL && connection.getObject()==null) { style = MapEditor.STYLE_NORMAL; } else { style = MapEditor.STYLE_CONDITIONAL; } applySource(); if (style != getStyle() || !getColor().equals(ColorProvider.getColorName(connection.getColor()))) { setStyle(style); setColor(ColorProvider.getColorName(connection.getColor())); update(); } } private void applySource() { if (getSourceImage() != null) { if (connection.getStrictness()==ParagraphConnection.STRICTNESS_MUST) { getSourceImage().setUrl(Images.SOURCE_MUST); } else { getSourceImage().setUrl(Images.SOURCE); } } } public void select() { if (this.connection==null) { this.connection = null; } model.selectParagraphConnection(connection,locationConnectionListener); } public void unselect() { model.unselectParagraphConnection(connection,locationConnectionListener); } @Override public void updateCorrection(int x, int y) { connection.setCorrectionX(x); connection.setCorrectionY(y); } } public class LocationMenuPanel extends PopupPanel { private MenuBar locationMenu; public LocationMenuPanel() { super(true,true); locationMenu = new MenuBar(true); locationMenu.addItem(appConstants.buttonRename(),new Command() { public void execute() { LocationMenuPanel.this.hide(); selectedWidget.editTitle(); } }); locationMenu.addItem(appConstants.buttonEdit(),new Command() { public void execute() { model.editParagraph(selectedWidget.location,locationListener); LocationMenuPanel.this.hide(); } }); locationMenu.addItem(appConstants.buttonCheckAvailability(),new Command() { public void execute() { LocationMenuPanel.this.hide(); PathFinder finder = new PathFinder(model); if (model.getStartParagraph()==null) { Window.alert(appConstants.modelStartParagraphNotSet()); return; } GameState objects = finder.new GameState(); if (finder.findWays(model.getStartParagraph(), selectedWidget.location, objects, null, null, PathFinder.FIND_ONE)==null) { Window.alert(appConstants.modelCannotReachParagraph()); } else { Window.alert(appConstants.modelCanReachParagraph()); } } }); locationMenu.addSeparator(); locationMenu.addItem(appConstants.buttonMakeParagraphNormal(),new Command() { public void execute() { LocationMenuPanel.this.hide(); model.makeParagraphAsNormal(selectedWidget.location); } }); locationMenu.addItem(appConstants.buttonMakeParagraphStart(),new Command() { public void execute() { LocationMenuPanel.this.hide(); model.makeParagraphAsStart(selectedWidget.location); } }); locationMenu.addItem(appConstants.buttonMakeParagraphFail(),new Command() { public void execute() { LocationMenuPanel.this.hide(); model.makeParagraphAsFail(selectedWidget.location); } }); locationMenu.addItem(appConstants.buttonMakeParagraphSuccess(),new Command() { public void execute() { LocationMenuPanel.this.hide(); model.makeParagraphAsSuccess(selectedWidget.location); } }); locationMenu.addItem(appConstants.importMakeCommecial(),new Command() { public void execute() { LocationMenuPanel.this.hide(); model.makeParagraphAsCommercial(selectedWidget.location); } }); add(locationMenu); } } public class NewConnectionPanel extends PopupPanel { private MenuBar newConnectionMenu; public NewConnectionPanel() { super(true,true); newConnectionMenu = new MenuBar(true); newConnectionMenu.addItem(appConstants.modelBiDirection(),new Command() { public void execute() { addNewConnection(selectedWidget,selectedWidget2,true); NewConnectionPanel.this.hide(); } }); newConnectionMenu.addItem(appConstants.modelToHere(),new Command() { public void execute() { addNewConnection(selectedWidget,selectedWidget2,false); NewConnectionPanel.this.hide(); } }); newConnectionMenu.addItem(appConstants.modelFromHere(),new Command() { public void execute() { addNewConnection(selectedWidget2,selectedWidget,false); NewConnectionPanel.this.hide(); } }); add(newConnectionMenu); } } private void addNewConnection(ParagraphWidget from,ParagraphWidget to, boolean bothDirections) { ParagraphConnection connection = new ParagraphConnection(); connection.setBothDirections(bothDirections); connection.setFrom(from.location); connection.setTo(to.location); connections.put(connection,new LocationConnectionWidget(connection,from,to)); model.addParagraphConnection(connection,locationConnectionListener); } public static String getParagraphTypeURL(Paragraph paragraph) { switch (paragraph.getType()) { case Paragraph.TYPE_FAIL: return Images.LOCATION_FAIL; case Paragraph.TYPE_START: return Images.LOCATION_START; case Paragraph.TYPE_SUCCESS: return Images.LOCATION_SUCCESS; case Paragraph.TYPE_COMMERCIAL: return Images.COMMERCIAL; default: if (paragraph.getBattle()==null) { if (paragraph.getGotObjects().size()+paragraph.getLostObjects().size()==0) { return Images.LOCATION_NORMAL; } else { return Images.LOCATION_NORMAL_OBJECT; } } else { return Images.NPC_ICON; } } } public void close() { model.removeParagraphConnectionListener(locationConnectionListener); model.removeParagraphListener(locationListener); model.removeSettingsListener(settingsListener); } }