1 19 20 package org.netbeans.modules.form.layoutdesign; 21 22 import java.util.*; 23 import org.w3c.dom.*; 24 25 30 class LayoutPersistenceManager implements LayoutConstants { 31 32 private LayoutModel layoutModel; 33 34 private LayoutComponent root; 35 36 private int dimension; 37 38 private Map<String , String > idNameMap; 39 40 private boolean humanReadable; 41 42 private int indent; 43 44 private StringBuffer sb; 45 46 static final String XML_DIMENSION_LAYOUT = "DimensionLayout"; static final String XML_GROUP = "Group"; static final String XML_COMPONENT = "Component"; static final String XML_EMPTY_SPACE = "EmptySpace"; 52 static final String ATTR_DIMENSION_DIM = "dim"; static final String ATTR_GROUP_TYPE = "type"; static final String ATTR_SIZE_MIN = "min"; static final String ATTR_SIZE_PREF = "pref"; static final String ATTR_SIZE_MAX = "max"; static final String ATTR_ALIGNMENT = "alignment"; static final String ATTR_GROUP_ALIGNMENT = "groupAlignment"; static final String ATTR_LINK_SIZE = "linkSize"; static final String ATTR_COMPONENT_ID = "id"; static final String ATTR_ATTRIBUTES = "attributes"; 64 static final String VALUE_DIMENSION_HORIZONTAL = "horizontal"; static final String VALUE_DIMENSION_VERTICAL = "vertical"; static final String VALUE_ALIGNMENT_LEADING = "leading"; static final String VALUE_ALIGNMENT_TRAILING = "trailing"; static final String VALUE_ALIGNMENT_CENTER = "center"; static final String VALUE_ALIGNMENT_BASELINE = "baseline"; static final String VALUE_SIZE_PREFERRED = "$pref"; static final String VALUE_SIZE_MAX = "Short.MAX_VALUE"; static final String VALUE_GROUP_PARALLEL = "parallel"; static final String VALUE_GROUP_SEQUENTIAL = "sequential"; 76 81 LayoutPersistenceManager(LayoutModel layoutModel) { 82 this.layoutModel = layoutModel; 83 } 84 85 94 String saveLayout(int indent, LayoutComponent root, Map idToNameMap, boolean humanReadable) { 95 this.root = root; 96 this.indent = indent; 97 this.idNameMap = idToNameMap; 98 this.humanReadable = humanReadable; 99 sb = new StringBuffer (); 100 for (int i=0; i < DIM_COUNT; i++) { 101 indent().append('<').append(XML_DIMENSION_LAYOUT); 102 sb.append(' ').append(ATTR_DIMENSION_DIM).append("=\""); if (humanReadable) { 104 switch (i) { 105 case HORIZONTAL: sb.append(VALUE_DIMENSION_HORIZONTAL); break; 106 case VERTICAL: sb.append(VALUE_DIMENSION_VERTICAL); break; 107 default: sb.append(i); break; 108 } 109 } else { 110 sb.append(i); 111 } 112 sb.append("\">\n"); LayoutInterval interval = root.getLayoutRoot(i); 114 saveInterval(interval, i); 115 indent().append("</").append(XML_DIMENSION_LAYOUT).append(">\n"); } 117 return sb.toString(); 118 } 119 120 129 String saveIntervalLayout(int indent, LayoutInterval interval, int dimension) { 130 this.indent = indent; 131 humanReadable = true; 132 sb = new StringBuffer (); 133 saveInterval(interval, dimension); 134 return sb.toString(); 135 } 136 137 142 private void saveInterval(LayoutInterval interval, int dimension) { 143 indent++; 144 indent(); 145 if (interval.isGroup()) { 146 sb.append('<').append(XML_GROUP).append(' '); 147 sb.append(ATTR_GROUP_TYPE).append("=\""); if (humanReadable) { 149 sb.append(interval.isParallel() ? VALUE_GROUP_PARALLEL : VALUE_GROUP_SEQUENTIAL); 150 } else { 151 sb.append(interval.getType()); 152 } 153 sb.append("\""); saveAlignment(interval.getRawAlignment(), false); 155 if (interval.isParallel()) { 156 saveAlignment(interval.getGroupAlignment(), true); 157 } 158 saveSize(interval.getMinimumSize(), ATTR_SIZE_MIN); 159 saveSize(interval.getMaximumSize(), ATTR_SIZE_MAX); 160 saveAttributes(interval.getAttributes()); 161 sb.append(">\n"); indent++; 163 Iterator iter = interval.getSubIntervals(); 164 while (iter.hasNext()) { 165 LayoutInterval subInterval = (LayoutInterval)iter.next(); 166 saveInterval(subInterval, dimension); 167 } 168 indent--; 169 indent().append("</").append(XML_GROUP).append(">\n"); } else { 171 if (interval.isComponent()) { 172 String name = interval.getComponent().getId(); 173 if (idNameMap != null) { 174 name = (String )idNameMap.get(name); 175 assert (name != null); 176 } 177 sb.append('<').append(XML_COMPONENT).append(' '); 178 sb.append(ATTR_COMPONENT_ID).append("=\"").append(name).append("\""); saveLinkSize(interval.getComponent().getLinkSizeId(dimension)); 180 saveAlignment(interval.getRawAlignment(), false); 181 } else if (interval.isEmptySpace()) { 182 sb.append('<').append(XML_EMPTY_SPACE); 183 } else { 184 assert false; 185 } 186 saveSize(interval.getMinimumSize(), ATTR_SIZE_MIN); 187 saveSize(interval.getPreferredSize(), ATTR_SIZE_PREF); 188 saveSize(interval.getMaximumSize(), ATTR_SIZE_MAX); 189 saveAttributes(interval.getAttributes()); 190 sb.append("/>\n"); } 192 indent--; 193 } 194 195 200 private void saveLinkSize(int linkSizeId) { 201 if (linkSizeId != NOT_EXPLICITLY_DEFINED) { 202 sb.append(" ").append(ATTR_LINK_SIZE).append("=\"").append(linkSizeId).append("\""); } 204 } 205 206 212 private void saveAlignment(int alignment, boolean group) { 213 String attrPrefix = " " + (group ? ATTR_GROUP_ALIGNMENT : ATTR_ALIGNMENT) + "=\""; if (humanReadable) { 215 if (alignment != DEFAULT) { 216 sb.append(attrPrefix); 217 switch (alignment) { 218 case LEADING: sb.append(VALUE_ALIGNMENT_LEADING); break; 219 case TRAILING: sb.append(VALUE_ALIGNMENT_TRAILING); break; 220 case CENTER: sb.append(VALUE_ALIGNMENT_CENTER); break; 221 case BASELINE: sb.append(VALUE_ALIGNMENT_BASELINE); break; 222 default: assert false; 223 } 224 sb.append("\""); } 226 } else { 227 if (alignment != DEFAULT) { 228 sb.append(attrPrefix).append(alignment).append("\""); } 230 } 231 } 232 233 239 private void saveSize(int size, String attr) { 240 String attrPrefix = " " + attr + "=\""; if (humanReadable) { 242 if (size != NOT_EXPLICITLY_DEFINED) { 243 sb.append(attrPrefix); 244 if (size == USE_PREFERRED_SIZE) { 245 sb.append(VALUE_SIZE_PREFERRED); 246 } else { 247 if (size == Short.MAX_VALUE) { 248 sb.append(VALUE_SIZE_MAX); 249 } else { 250 sb.append(size); 251 } 252 } 253 sb.append("\""); } 255 } else { 256 if (size != NOT_EXPLICITLY_DEFINED) { 257 sb.append(attrPrefix).append(size).append("\""); } 259 } 260 } 261 262 267 private void saveAttributes(int attributes) { 268 if (!humanReadable) 269 attributes &= LayoutInterval.ATTR_PERSISTENT_MASK; 270 sb.append(' ').append(ATTR_ATTRIBUTES).append("=\""); sb.append(attributes).append("\""); } 273 274 279 private StringBuffer indent() { 280 char[] spaces = new char[2*indent]; 281 Arrays.fill(spaces, ' '); 282 return sb.append(spaces); 283 } 284 285 293 void loadModel(String rootId, NodeList dimLayoutList, Map nameToIdMap) 294 throws java.io.IOException 295 { 296 this.idNameMap = nameToIdMap; 297 resetMissingName(); LayoutComponent root = layoutModel.getLayoutComponent(rootId); 299 if (root == null) { 300 root = new LayoutComponent(rootId, true); 301 layoutModel.addRootComponent(root); 302 } 303 this.root = root; 304 305 for (int i=0; i<dimLayoutList.getLength(); i++) { 306 Node dimLayoutNode = dimLayoutList.item(i); 307 if (!(dimLayoutNode instanceof Element)) 308 continue; 309 Node dimAttrNode = dimLayoutNode.getAttributes().getNamedItem(ATTR_DIMENSION_DIM); 310 dimension = integerFromNode(dimAttrNode); 311 LayoutInterval dimLayoutInterval = root.getLayoutRoot(dimension); 312 NodeList childs = dimLayoutNode.getChildNodes(); 313 for (int j=0; j<childs.getLength(); j++) { 314 Node node = childs.item(j); 315 if (node instanceof Element) { 316 loadGroup(dimLayoutInterval, node, dimension); 317 break; 318 } 319 } 320 } 321 322 correctMissingName(); } 324 325 331 private void loadGroup(LayoutInterval group, Node groupNode, int dimension) 332 throws java.io.IOException 333 { 334 NamedNodeMap attrMap = groupNode.getAttributes(); 335 Node alignmentNode = attrMap.getNamedItem(ATTR_ALIGNMENT); 336 Node groupAlignmentNode = attrMap.getNamedItem(ATTR_GROUP_ALIGNMENT); 337 Node minNode = attrMap.getNamedItem(ATTR_SIZE_MIN); 338 Node maxNode = attrMap.getNamedItem(ATTR_SIZE_MAX); 339 int alignment = (alignmentNode == null) ? DEFAULT : integerFromNode(alignmentNode); 340 group.setAlignment(alignment); 341 if (group.isParallel()) { 342 int groupAlignment = (groupAlignmentNode == null) ? DEFAULT : integerFromNode(groupAlignmentNode); 343 if (groupAlignment != DEFAULT) { 344 group.setGroupAlignment(groupAlignment); 345 } 346 } 347 int min = (minNode == null) ? NOT_EXPLICITLY_DEFINED : integerFromNode(minNode); 348 int max = (maxNode == null) ? NOT_EXPLICITLY_DEFINED : integerFromNode(maxNode); 349 group.setMinimumSize(min); 350 group.setMaximumSize(max); 351 loadAttributes(group, attrMap); 352 NodeList subNodes = groupNode.getChildNodes(); 353 for (int i=0; i<subNodes.getLength(); i++) { 354 Node subNode = subNodes.item(i); 355 if (!(subNode instanceof Element)) 356 continue; 357 String nodeName = subNode.getNodeName(); 358 if (XML_GROUP.equals(nodeName)) { 359 Node typeNode = subNode.getAttributes().getNamedItem(ATTR_GROUP_TYPE); 360 int type = integerFromNode(typeNode); 361 LayoutInterval subGroup = new LayoutInterval(type); 362 group.add(subGroup, -1); 363 loadGroup(subGroup, subNode, dimension); 364 } else if (XML_EMPTY_SPACE.equals(nodeName)) { 365 loadEmptySpace(group, subNode); 366 } else { 367 assert XML_COMPONENT.equals(nodeName); 368 loadComponent(group, subNode, dimension); 369 } 370 } 371 if (dimension == VERTICAL) 372 checkAndFixGroup(group); 373 } 374 375 381 private void loadEmptySpace(LayoutInterval parent, Node spaceNode) { 382 LayoutInterval space = new LayoutInterval(SINGLE); 383 NamedNodeMap attrMap = spaceNode.getAttributes(); 384 loadSizes(space, attrMap); 385 loadAttributes(space, attrMap); 386 parent.add(space, -1); 387 } 388 389 396 private void loadComponent(LayoutInterval parent, Node componentNode, int dimension) 397 throws java.io.IOException 398 { 399 NamedNodeMap attrMap = componentNode.getAttributes(); 400 String name = attrMap.getNamedItem(ATTR_COMPONENT_ID).getNodeValue(); 401 Node linkSizeId = attrMap.getNamedItem(ATTR_LINK_SIZE); 402 String id = (String )idNameMap.get(name); 403 if (id == null) { id = useTemporaryId(name); 405 } 406 Node alignmentNode = attrMap.getNamedItem(ATTR_ALIGNMENT); 407 int alignment = (alignmentNode == null) ? DEFAULT : integerFromNode(alignmentNode); 408 LayoutComponent layoutComponent = layoutModel.getLayoutComponent(id); 409 if (layoutComponent == null) { 410 layoutComponent = new LayoutComponent(id, false ); 411 } 412 if (layoutComponent.getParent() == null) { 413 layoutModel.addComponent(layoutComponent, root, -1); 414 } 415 LayoutInterval interval = layoutComponent.getLayoutInterval(dimension); 416 interval.setAlignment(alignment); 417 if (linkSizeId != null) { 418 layoutModel.addComponentToLinkSizedGroup(integerFromNode(linkSizeId), layoutComponent.getId(), dimension); 419 } 420 loadSizes(interval, attrMap); 421 loadAttributes(interval, attrMap); 422 parent.add(interval, -1); 423 } 424 425 431 private void loadSizes(LayoutInterval interval, org.w3c.dom.NamedNodeMap attrMap) { 432 Node minNode = attrMap.getNamedItem(ATTR_SIZE_MIN); 433 Node prefNode = attrMap.getNamedItem(ATTR_SIZE_PREF); 434 Node maxNode = attrMap.getNamedItem(ATTR_SIZE_MAX); 435 int min = (minNode == null) ? NOT_EXPLICITLY_DEFINED : integerFromNode(minNode); 436 int pref = (prefNode == null) ? NOT_EXPLICITLY_DEFINED : integerFromNode(prefNode); 437 int max = (maxNode == null) ? NOT_EXPLICITLY_DEFINED : integerFromNode(maxNode); 438 interval.setSizes(min, pref, max); 439 } 440 441 447 private void loadAttributes(LayoutInterval interval, org.w3c.dom.NamedNodeMap attrMap) { 448 Node attributesNode = attrMap.getNamedItem(ATTR_ATTRIBUTES); 449 int attributes = 0; 450 if (attributesNode != null) { 451 attributes = integerFromNode(attributesNode); 452 attributes &= LayoutInterval.ATTR_PERSISTENT_MASK; 453 } 454 interval.setAttributes(attributes); 455 } 456 457 463 private static int integerFromNode(Node node) { 464 String nodeStr = node.getNodeValue(); 465 return Integer.parseInt(nodeStr); 466 } 467 468 471 484 void checkAndFixGroup(LayoutInterval group) { 485 if (group.isParallel()) { 486 int groupAlign = group.getGroupAlignment(); 487 int baselineCount = 0; 488 489 Iterator iter = group.getSubIntervals(); 490 while (iter.hasNext()) { 491 LayoutInterval subInterval = (LayoutInterval)iter.next(); 492 if (subInterval.getAlignment() == BASELINE) { 493 if (!subInterval.isComponent()) { 494 subInterval.setAlignment(groupAlign == BASELINE ? LEADING : DEFAULT); 495 layoutModel.setCorrected(); 496 System.err.println("WARNING: Invalid use of BASELINE [1], corrected automatically"); } 498 else baselineCount++; 499 } 500 } 501 502 if (baselineCount > 0) { 503 if (baselineCount < group.getSubIntervalCount()) { 504 LayoutInterval subGroup = new LayoutInterval(PARALLEL); 506 subGroup.setGroupAlignment(BASELINE); 507 for (int i=0; i < group.getSubIntervalCount(); ) { 508 LayoutInterval subInterval = group.getSubInterval(i); 509 if (subInterval.getAlignment() == BASELINE) { 510 group.remove(i); 511 subGroup.add(subInterval, -1); 512 } 513 else i++; 514 } 515 if (groupAlign == BASELINE) { 516 group.setGroupAlignment(LEADING); 517 } 518 group.add(subGroup, -1); 519 layoutModel.setCorrected(); 520 System.err.println("WARNING: Invalid use of BASELINE [2], corrected automatically"); } 522 else if (groupAlign != BASELINE) { 523 group.setGroupAlignment(BASELINE); 524 layoutModel.setCorrected(); 525 System.err.println("WARNING: Invalid use of BASELINE [3], corrected automatically"); } 527 } 528 else if (groupAlign == BASELINE && group.getSubIntervalCount() > 0) { 529 group.setGroupAlignment(LEADING); 530 layoutModel.setCorrected(); 531 System.err.println("WARNING: Invalid use of BASELINE [4], corrected automatically"); } 533 } 534 } 535 536 543 private final String TEMPORARY_ID = "<temp_id>"; private String missingNameH; 545 private String missingNameV; 546 547 private void resetMissingName() { 548 missingNameH = missingNameV = null; 549 } 550 551 private String useTemporaryId(String name) throws java.io.IOException { 552 if (dimension == HORIZONTAL) { 553 if (missingNameH == null && (missingNameV == null || missingNameV.equals(name))) { 554 missingNameH = name; 555 return TEMPORARY_ID; 556 } 557 } 558 else if (dimension == VERTICAL) { 559 if (missingNameV == null && (missingNameH == null || missingNameH.equals(name))) { 560 missingNameV = name; 561 return TEMPORARY_ID; 562 } 563 } 564 throw new java.io.IOException ("Undefined component referenced in layout: "+name); } 566 567 private void correctMissingName() throws java.io.IOException { 568 if (missingNameH == null && missingNameV == null) 569 return; 571 if (missingNameH != null && missingNameV != null && missingNameH.equals(missingNameV) 572 && idNameMap.size() == root.getSubComponentCount()) 573 { for (Map.Entry<String , String > e : idNameMap.entrySet()) { String id = e.getValue(); 576 LayoutComponent comp = layoutModel.getLayoutComponent(id); 577 if (comp == null) { comp = layoutModel.getLayoutComponent(TEMPORARY_ID); 579 layoutModel.changeComponentId(comp, id); 580 } 581 else if (comp.getParent() == null) { LayoutComponent tempComp = layoutModel.getLayoutComponent(TEMPORARY_ID); 584 layoutModel.replaceComponent(tempComp, comp); 585 } 586 else continue; 587 588 layoutModel.setCorrected(); 589 System.err.println("WARNING: Invalid component name in layout: "+missingNameH +", corrected automatically to: "+e.getKey()); resetMissingName(); 592 return; 593 } 594 } 595 596 layoutModel.removeComponent(TEMPORARY_ID, true); 597 resetMissingName(); 598 throw new java.io.IOException ("Undefined component referenced in layout: " + (missingNameH != null ? missingNameH : missingNameV)); 600 } 601 } 602 | Popular Tags |