/* 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;
}
}