1 19 20 package org.netbeans.modules.xml.xdm.xam; 21 22 import java.beans.PropertyChangeEvent ; 23 import java.beans.PropertyChangeListener ; 24 import java.io.IOException ; 25 import java.util.ArrayList ; 26 import java.util.HashMap ; 27 import java.util.List ; 28 import java.util.Map ; 29 import org.netbeans.modules.xml.xam.Component; 30 import org.netbeans.modules.xml.xam.Model; 31 import org.netbeans.modules.xml.xam.dom.AbstractDocumentComponent; 32 import org.netbeans.modules.xml.xam.dom.AbstractDocumentModel; 33 import org.netbeans.modules.xml.xam.dom.ChangeInfo; 34 import org.netbeans.modules.xml.xam.dom.DocumentComponent; 35 import org.netbeans.modules.xml.xam.dom.SyncUnit; 36 import org.netbeans.modules.xml.xdm.XDMModel; 37 import org.netbeans.modules.xml.xdm.diff.NodeInfo; 38 import org.netbeans.modules.xml.xdm.nodes.Node; 39 import org.netbeans.modules.xml.xdm.nodes.Element; 40 import org.netbeans.modules.xml.xdm.nodes.Document; 41 42 46 public class XDMListener implements PropertyChangeListener { 47 48 private AbstractDocumentModel model; 49 private boolean inSync; 50 private Document oldDocument; 51 52 53 public XDMListener(AbstractDocumentModel model) { 54 this.model = model; 55 } 56 57 private XDMModel getXDMModel() { 58 return ((XDMAccess) model.getAccess()).getXDMModel(); 59 } 60 61 void startSync() { 62 inSync = true; 63 syncUnits.clear(); 64 oldDocument = getXDMModel().getCurrentDocument(); 65 getXDMModel().addPropertyChangeListener(this); 66 } 67 68 Document getOldDocument() { 69 return oldDocument; 70 } 71 72 void endSync() { 73 endSync(true); 74 } 75 76 void endSync(boolean processing) { 77 getXDMModel().removePropertyChangeListener(this); 78 try { 79 if (processing) { 80 for (SyncUnit unit : syncUnits.values()) { 81 model.processSyncUnit(unit); 82 } 83 } 84 } finally { 85 syncUnits.clear(); 86 inSync = false; 87 } 88 } 89 90 private Map <Integer , SyncUnit> syncUnits = new HashMap <Integer , SyncUnit>(); 91 private static Integer getID(ChangeInfo change) { 92 if (change.getParent() == null) { 93 return Integer.valueOf(0); 94 } else { 95 Element parent = (Element) change.getParent(); 96 return Integer.valueOf(parent.getId()); 97 } 98 } 99 private static Integer getID(DocumentComponent c) { 100 if (c == null) { 101 return Integer.valueOf(0); 102 } 103 Element xdmElement = (Element) ((AbstractDocumentComponent)c).getPeer(); 104 return Integer.valueOf(xdmElement.getId()); 105 } 106 107 protected void processChange(ChangeInfo change) { 108 Integer unitID = getID(change); 109 SyncUnit existing = syncUnits.get(unitID); 110 SyncUnit su = model.prepareSyncUnit(change, existing); 111 if (su == null) { 112 return; 113 } 114 Integer reviewedID = getID(su.getTarget()); 115 existing = syncUnits.get(reviewedID); 116 if (existing == null) { 117 if (unitID.equals(reviewedID)) { 118 syncUnits.put(reviewedID, su); 120 } else { 121 existing = syncUnits.get(reviewedID); 122 if (existing != null) { 123 existing.merge(su); 124 } else { 125 syncUnits.put(reviewedID, su); 126 } 127 } 128 } else { 129 if (existing != su) { 130 if (unitID.equals(reviewedID)) { 131 existing.merge(su); 132 } else { 133 syncUnits.remove(unitID); 135 existing = syncUnits.get(reviewedID); 136 if (existing != null) { 137 existing.merge(su); 138 } else { 139 syncUnits.put(reviewedID, su); 140 } 141 } 142 } 143 } 144 } 145 146 protected void processEvent(Node eventNode, List <Node> pathToRoot, boolean isAdded) { 147 if (pathToRoot.size() == 1) { 148 assert pathToRoot.get(0) instanceof Document; 149 if (! (eventNode instanceof Element)) { 150 return; 151 } 152 if (! isAdded) { 154 return; 155 } 156 Component rootComponent = null; 157 String errorMessage = null; 158 try { 159 rootComponent = model.createRootComponent((Element) eventNode); 160 } catch(IllegalArgumentException e) { 161 errorMessage = e.getMessage(); 162 } 163 if (rootComponent == null) { 164 errorMessage = errorMessage != null ? errorMessage : 165 "Unexpected root element "+AbstractDocumentComponent.getQName(eventNode); 166 throw new IllegalArgumentException (new IOException (errorMessage)); 167 } 168 model.firePropertyChangeEvent(new PropertyChangeEvent (model, 169 Model.STATE_PROPERTY, Model.State.NOT_SYNCED, Model.State.VALID)); 170 } else { 171 if (eventNode.getId() == pathToRoot.get(0).getId()) { 172 throw new IllegalArgumentException ("Event node has same id as parent"); 173 } 174 pathToRoot = new ArrayList (pathToRoot); 175 pathToRoot.add(0, eventNode); 176 ChangeInfo change = model.prepareChangeInfo(toDomNodes(pathToRoot)); 177 change.setAdded(isAdded); 178 processChange(change); 179 } 180 } 181 182 public void propertyChange(PropertyChangeEvent event) { 183 if (!inSync) return; 184 185 NodeInfo oldInfo = (NodeInfo) event.getOldValue(); 186 NodeInfo newInfo = (NodeInfo) event.getNewValue(); 187 188 Node old = oldInfo!=null?(Node) oldInfo.getNode():null; 189 Node now = newInfo!=null?(Node) newInfo.getNode():null; 190 191 if (old != null) { 192 processEvent(old, oldInfo.getNewAncestors(), false); 193 } 194 195 if (now != null) { 196 processEvent(now, newInfo.getNewAncestors(), true); 197 } 198 } 199 200 static List <org.w3c.dom.Node > toDomNodes(List <Node> nodes) { 201 List <org.w3c.dom.Node > domNodes = new ArrayList <org.w3c.dom.Node >(); 202 for (Node n : nodes) { 203 domNodes.add((org.w3c.dom.Node ) n); 204 } 205 return domNodes; 206 } 207 } 208 209 | Popular Tags |