選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

ComponentLocator.java 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. package com.vaadin.terminal.gwt.client;
  2. import java.util.ArrayList;
  3. import java.util.Iterator;
  4. import com.google.gwt.user.client.DOM;
  5. import com.google.gwt.user.client.Element;
  6. import com.google.gwt.user.client.ui.HasWidgets;
  7. import com.google.gwt.user.client.ui.Widget;
  8. import com.vaadin.terminal.gwt.client.ui.VView;
  9. import com.vaadin.terminal.gwt.client.ui.VWindow;
  10. import com.vaadin.terminal.gwt.client.ui.SubPartAware;
  11. /**
  12. * ComponentLocator provides methods for uniquely identifying DOM elements using
  13. * string expressions. This class is EXPERIMENTAL and subject to change.
  14. */
  15. public class ComponentLocator {
  16. /**
  17. * Separator used in the string expression between a parent and a child
  18. * widget.
  19. */
  20. private static final String PARENTCHILD_SEPARATOR = "/";
  21. /**
  22. * Separator used in the string expression between a widget and the widget's
  23. * sub part. NOT CURRENTLY IN USE.
  24. */
  25. private static final String SUBPART_SEPARATOR = "#";
  26. private ApplicationConnection client;
  27. public ComponentLocator(ApplicationConnection client) {
  28. this.client = client;
  29. }
  30. /**
  31. * EXPERIMENTAL.
  32. *
  33. * Generates a string expression (path) which uniquely identifies the target
  34. * element . The getElementByPath method can be used for the inverse
  35. * operation, i.e. locating an element based on the string expression.
  36. *
  37. * @since 5.4
  38. * @param targetElement
  39. * The element to generate a path for.
  40. * @return A string expression uniquely identifying the target element or
  41. * null if a string expression could not be created.
  42. */
  43. public String getPathForElement(Element targetElement) {
  44. String pid = null;
  45. Element e = targetElement;
  46. while (true) {
  47. pid = client.getPid(e);
  48. if (pid != null) {
  49. break;
  50. }
  51. e = DOM.getParent(e);
  52. if (e == null) {
  53. break;
  54. }
  55. }
  56. if (e == null || pid == null) {
  57. // Still test for context menu option
  58. String subPartName = client.getContextMenu().getSubPartName(
  59. targetElement);
  60. if (subPartName != null) {
  61. // VContextMenu, singleton attached directly to rootpanel
  62. return "/VContextMenu[0]" + SUBPART_SEPARATOR + subPartName;
  63. }
  64. return null;
  65. }
  66. Widget w = (Widget) client.getPaintable(pid);
  67. if (w == null) {
  68. return null;
  69. }
  70. // ApplicationConnection.getConsole().log(
  71. // "First parent widget: " + Util.getSimpleName(w));
  72. String path = getPathForWidget(w);
  73. // ApplicationConnection.getConsole().log(
  74. // "getPathFromWidget returned " + path);
  75. if (w.getElement() == targetElement) {
  76. // ApplicationConnection.getConsole().log(
  77. // "Path for " + Util.getSimpleName(w) + ": " + path);
  78. return path;
  79. } else if (w instanceof SubPartAware) {
  80. return path + SUBPART_SEPARATOR
  81. + ((SubPartAware) w).getSubPartName(targetElement);
  82. } else {
  83. path = path + getDOMPathForElement(targetElement, w.getElement());
  84. // ApplicationConnection.getConsole().log(
  85. // "Path with dom addition for " + Util.getSimpleName(w)
  86. // + ": " + path);
  87. return path;
  88. }
  89. }
  90. private Element getElementByDOMPath(Element baseElement, String path) {
  91. String parts[] = path.split(PARENTCHILD_SEPARATOR);
  92. Element element = baseElement;
  93. for (String part : parts) {
  94. if (part.startsWith("domChild[")) {
  95. String childIndexString = part.substring("domChild[".length(),
  96. part.length() - 1);
  97. try {
  98. int childIndex = Integer.parseInt(childIndexString);
  99. element = DOM.getChild(element, childIndex);
  100. } catch (Exception e) {
  101. // ApplicationConnection.getConsole().error(
  102. // "Failed to parse integer in " + childIndexString);
  103. return null;
  104. }
  105. }
  106. }
  107. return element;
  108. }
  109. private String getDOMPathForElement(Element element, Element baseElement) {
  110. Element e = element;
  111. String path = "";
  112. while (true) {
  113. Element parent = DOM.getParent(e);
  114. if (parent == null) {
  115. return "ERROR, baseElement is not a parent to element";
  116. }
  117. int childIndex = -1;
  118. int childCount = DOM.getChildCount(parent);
  119. for (int i = 0; i < childCount; i++) {
  120. if (e == DOM.getChild(parent, i)) {
  121. childIndex = i;
  122. break;
  123. }
  124. }
  125. if (childIndex == -1) {
  126. return "ERROR, baseElement is not a parent to element.";
  127. }
  128. path = PARENTCHILD_SEPARATOR + "domChild[" + childIndex + "]"
  129. + path;
  130. if (parent == baseElement) {
  131. break;
  132. }
  133. e = parent;
  134. }
  135. return path;
  136. }
  137. /**
  138. * EXPERIMENTAL.
  139. *
  140. * Locates an element by using a string expression (path) which uniquely
  141. * identifies the element. The getPathForElement method can be used for the
  142. * inverse operation, i.e. generating a string expression for a target
  143. * element.
  144. *
  145. * @since 5.4
  146. * @param path
  147. * The string expression which uniquely identifies the target
  148. * element.
  149. * @return The DOM element identified by the path or null if the element
  150. * could not be located.
  151. */
  152. public Element getElementByPath(String path) {
  153. // ApplicationConnection.getConsole()
  154. // .log("getElementByPath(" + path + ")");
  155. // Path is of type "PID/componentPart"
  156. String parts[] = path.split(SUBPART_SEPARATOR, 2);
  157. String widgetPath = parts[0];
  158. Widget w = getWidgetFromPath(widgetPath);
  159. if (w == null) {
  160. return null;
  161. }
  162. if (parts.length == 1) {
  163. int pos = widgetPath.indexOf("domChild");
  164. if (pos == -1) {
  165. return w.getElement();
  166. }
  167. // Contains dom reference to a sub element of the widget
  168. String subPath = widgetPath.substring(pos);
  169. return getElementByDOMPath(w.getElement(), subPath);
  170. } else if (parts.length == 2) {
  171. if (w instanceof SubPartAware) {
  172. // ApplicationConnection.getConsole().log(
  173. // "subPartAware: " + parts[1]);
  174. return ((SubPartAware) w).getSubPartElement(parts[1]);
  175. } else {
  176. // ApplicationConnection.getConsole().error(
  177. // "getElementByPath failed because "
  178. // + Util.getSimpleName(w)
  179. // + " is not SubPartAware");
  180. return null;
  181. }
  182. }
  183. return null;
  184. }
  185. private String getPathForWidget(Widget w) {
  186. if (w == null) {
  187. return "";
  188. }
  189. String pid = client.getPid(w.getElement());
  190. if (isStaticPid(pid)) {
  191. return pid;
  192. }
  193. if (w instanceof VView) {
  194. return "";
  195. } else if (w instanceof VWindow) {
  196. VWindow win = (VWindow) w;
  197. ArrayList<VWindow> subWindowList = client.getView()
  198. .getSubWindowList();
  199. int indexOfSubWindow = subWindowList.indexOf(win);
  200. return PARENTCHILD_SEPARATOR + "VWindow[" + indexOfSubWindow + "]";
  201. }
  202. Widget parent = w.getParent();
  203. String basePath = getPathForWidget(parent);
  204. String simpleName = Util.getSimpleName(w);
  205. Iterator<Widget> i = ((HasWidgets) parent).iterator();
  206. int pos = 0;
  207. while (i.hasNext()) {
  208. Object child = i.next();
  209. if (child == w) {
  210. return basePath + PARENTCHILD_SEPARATOR + simpleName + "["
  211. + pos + "]";
  212. }
  213. String simpleName2 = Util.getSimpleName(child);
  214. if (simpleName.equals(simpleName2)) {
  215. pos++;
  216. }
  217. }
  218. return "NOTFOUND";
  219. }
  220. private Widget getWidgetFromPath(String path) {
  221. Widget w = null;
  222. String parts[] = path.split(PARENTCHILD_SEPARATOR);
  223. // ApplicationConnection.getConsole().log(
  224. // "getWidgetFromPath(" + path + ")");
  225. for (String part : parts) {
  226. // ApplicationConnection.getConsole().log("Part: " + part);
  227. // ApplicationConnection.getConsole().log(
  228. // "Widget: " + Util.getSimpleName(w));
  229. if (part.equals("")) {
  230. w = client.getView();
  231. } else if (w == null) {
  232. w = (Widget) client.getPaintable(part);
  233. } else if (part.startsWith("domChild[")) {
  234. break;
  235. } else if (w instanceof HasWidgets) {
  236. HasWidgets parent = (HasWidgets) w;
  237. String[] split = part.split("\\[");
  238. Iterator<? extends Widget> i;
  239. String widgetClassName = split[0];
  240. if (widgetClassName.equals("VWindow")) {
  241. i = client.getView().getSubWindowList().iterator();
  242. } else if (widgetClassName.equals("VContextMenu")) {
  243. return client.getContextMenu();
  244. } else {
  245. i = parent.iterator();
  246. }
  247. boolean ok = false;
  248. int pos = Integer.parseInt(split[1].substring(0, split[1]
  249. .length() - 1));
  250. // ApplicationConnection.getConsole().log(
  251. // "Looking for child " + pos);
  252. while (i.hasNext()) {
  253. // ApplicationConnection.getConsole().log("- child found");
  254. Widget child = i.next();
  255. String simpleName2 = Util.getSimpleName(child);
  256. if (widgetClassName.equals(simpleName2)) {
  257. if (pos == 0) {
  258. w = child;
  259. ok = true;
  260. break;
  261. }
  262. pos--;
  263. }
  264. }
  265. if (!ok) {
  266. // Did not find the child
  267. // ApplicationConnection.getConsole().error(
  268. // "getWidgetFromPath(" + path + ") - did not find '"
  269. // + part + "' for "
  270. // + Util.getSimpleName(parent));
  271. return null;
  272. }
  273. } else {
  274. // ApplicationConnection.getConsole().error(
  275. // "getWidgetFromPath(" + path + ") - failed for '" + part
  276. // + "'");
  277. return null;
  278. }
  279. }
  280. return w;
  281. }
  282. private boolean isStaticPid(String pid) {
  283. if (pid == null) {
  284. return false;
  285. }
  286. return pid.startsWith("PID_S");
  287. }
  288. }