/* Path.java Purpose: Description: History: Thu Jan 19 14:07:44 2006, Created by tomyeh Copyright (C) 2006 Potix Corporation. All Rights Reserved. {{IS_RIGHT This program is distributed under LGPL Version 2.1 in the hope that it will be useful, but WITHOUT ANY WARRANTY. }}IS_RIGHT */ package org.zkoss.zk.ui; import org.zkoss.io.Files; import org.zkoss.zk.ui.sys.ExecutionCtrl; /** * A representation of a component path. * <p>There are three formats: * //page-id/comp-id/comp-id<br/> * /comp-id/comp-id<br/> * comp-id/comp-id * * <p>Alternatively, you could use {@link Component#query} * or {@link Component#queryAll} instead. * * @author tomyeh */ public class Path { private final String _path; public Path() { this((String) null); } public Path(String path) { _path = Files.normalize(path); } public Path(String parent, String child) { this(parent == null || parent.length() == 0 ? child : child == null || child.length() == 0 ? parent : parent + '/' + child); } public Path(Path parent, String child) { this(parent != null ? parent.getPath() : null, child); } /** Returns the path of the specified component. */ public Path(Component comp) { this(getPath(comp)); } /** Returns the path (after normalized). */ public String getPath() { return _path; } /** Returns the path of the specified component. */ public static final String getPath(Component comp) { final StringBuffer sb = new StringBuffer(64); for (;;) { if (sb.length() > 0) sb.insert(0, '/'); final String compId = comp.getId(); if (compId.length() == 0) throw new UiException("ID required: " + comp); sb.insert(0, compId); IdSpace is = comp.getSpaceOwner(); if (is instanceof Page) break; //done if (is == comp) { final Component p = ((Component) is).getParent(); if (p == null) break; //topmost is = p.getSpaceOwner(); if (is instanceof Page) break; //done } comp = (Component) is; } sb.insert(0, '/'); return sb.toString(); } /** Returns the component with this path, or null if no such component. */ public Component getComponent() { return getComponent0(null, _path); } /** Returns the component of the specified path, or null if no such component. */ public static final Component getComponent(String path) { return getComponent0(null, Files.normalize(path)); } /** Returns the component of the specified path which is related * to the specified ID space, or null if no such component. * * @param is the current ID space. It is required only if path is related * (in other words, not starting with / or //). */ public static final Component getComponent(IdSpace is, String path) { return getComponent0(is, Files.normalize(path)); } private static final Component getComponent0(IdSpace is, String path) { Component found = null; for (int j = 0, k;; j = k + 1) { k = path.indexOf('/', j); if (k == 0) { //starts with / final Execution exec = Executions.getCurrent(); final Desktop desktop = exec.getDesktop(); Page page = ((ExecutionCtrl) exec).getCurrentPage(); if (page == null) { page = desktop.getFirstPage(); if (page == null) return null; } if (path.length() == 1) // "/" only return page.getFirstRoot(); //the first root assumed if (path.charAt(1) == '/') { //starts with // k = path.indexOf('/', 2); if (k < 0) return null; //page is not component final String nm = path.substring(2, k); is = desktop.getPageIfAny(nm); if (is == null) return null; //no such page } else { is = page; } continue; } final String nm = k >= 0 ? path.substring(j, k) : path.substring(j); if ("..".equals(nm)) { if (!(is instanceof Component)) return null; final Component c = (Component) is; final Component p = c.getParent(); is = p != null ? p.getSpaceOwner() : c.getPage(); if (k < 0) { return (is instanceof Component) ? (Component) is : null; } continue; } if (is == null) return null; final Component c = is.getFellowIfAny(nm); if (k < 0 || c == null) return c; if (!(c instanceof IdSpace)) return null; is = (IdSpace) c; } } //--Object--// public boolean equals(Object o) { if (this == o) return true; return o instanceof Path && ((Path) o)._path.equals(_path); } public int hashCode() { return _path.hashCode(); } public String toString() { return _path; } }