* @return The Widget identified by the String locator or null if the widget
* could not be identified.
*/
@SuppressWarnings("unchecked")
private Widget getWidgetFromPath(String path, Widget baseWidget) {
Widget w = baseWidget;
String parts[] = path.split(PARENTCHILD_SEPARATOR);
for (int i = 0; i < parts.length; i++) {
String part = parts[i];
if (part.equals(ROOT_ID)) {
w = RootPanel.get();
} else if (part.equals("")) {
if (w == null) {
w = client.getUIConnector().getWidget();
}
} else if (w == null) {
String id = part;
// Must be old static pid (PID_S*)
ServerConnector connector = ConnectorMap.get(client)
.getConnector(id);
if (connector == null) {
// Lookup by component id
// TODO Optimize this
connector = findConnectorById(client.getUIConnector(),
id.substring(5));
}
if (connector instanceof ComponentConnector) {
w = ((ComponentConnector) connector).getWidget();
} else {
// Not found
return null;
}
} else if (part.startsWith("domChild[")) {
// The target widget has been found and the rest identifies the
// element
break;
} else if (w instanceof Iterable) {
// W identifies a widget that contains other widgets, as it
// should. Try to locate the child
Iterable<?> parent = (Iterable<?>) w;
// Part is of type "VVerticalLayout[0]", split this into
// VVerticalLayout and 0
String[] split = part.split("\\[", 2);
String widgetClassName = split[0];
String indexString = split[1].substring(0,
split[1].length() - 1);
int widgetPosition;
try {
widgetPosition = Integer.parseInt(indexString);
} catch (NumberFormatException e) {
// We've probably been fed a new-style Vaadin locator with a
// string-form predicate, that doesn't match anything in the
// search space.
return null;
}
// AbsolutePanel in GridLayout has been removed -> skip it
if (w instanceof VGridLayout
&& "AbsolutePanel".equals(widgetClassName)) {
continue;
}
// FlowPane in CSSLayout has been removed -> skip it
if (w instanceof VCssLayout
&& "VCssLayout$FlowPane".equals(widgetClassName)) {
continue;
}
// ChildComponentContainer and VOrderedLayout$Slot have been
// replaced with Slot
if (w instanceof VAbstractOrderedLayout
&& ("ChildComponentContainer".equals(widgetClassName) || "VOrderedLayout$Slot"
.equals(widgetClassName))) {
widgetClassName = "Slot";
}
if (w instanceof VTabsheetPanel && widgetPosition != 0) {
// TabSheetPanel now only contains 1 connector => the index
// is always 0 which indicates the widget in the active tab
widgetPosition = 0;
}
if (w instanceof VOverlay
&& "VCalendarPanel".equals(widgetClassName)) {
// Vaadin 7.1 adds a wrapper for datefield popups
parent = (Iterable<?>) ((Iterable<?>) parent).iterator()
.next();
}
/*
* The new grid and ordered layouts do not contain
* ChildComponentContainer widgets. This is instead simulated by
* constructing a path step that would find the desired widget
* from the layout and injecting it as the next search step
* (which would originally have found the widget inside the
* ChildComponentContainer)
*/
if ((w instanceof VGridLayout)
&& "ChildComponentContainer".equals(widgetClassName)
&& i + 1 < parts.length) {
HasWidgets layout = (HasWidgets) w;
String nextPart = parts[i + 1];
String[] nextSplit = nextPart.split("\\[", 2);
String nextWidgetClassName = nextSplit[0];
// Find the n:th child and count the number of children with
// the same type before it
int nextIndex = 0;
for (Widget child : layout) {
boolean matchingType = nextWidgetClassName.equals(Util
.getSimpleName(child));
if (matchingType && widgetPosition == 0) {
// This is the n:th child that we looked for
break;
} else if (widgetPosition < 0) {
// Error if we're past the desired position without
// a match
return null;
} else if (matchingType) {
// If this was another child of the expected type,
// increase the count for the next step
nextIndex++;
}
// Don't count captions
if (!(child instanceof VCaption)) {
widgetPosition--;
}
}
// Advance to the next step, this time checking for the
// actual child widget
parts[i + 1] = nextWidgetClassName + '[' + nextIndex + ']';
continue;
}
// Locate the child
Iterator<? extends Widget> iterator;
/*
* VWindow and VContextMenu workarounds for backwards
* compatibility
*/
if (widgetClassName.equals("VWindow")) {
List<WindowConnector> windows = client.getUIConnector()
.getSubWindows();
List<VWindow> windowWidgets = new ArrayList<VWindow>(
windows.size());
for (WindowConnector wc : windows) {
windowWidgets.add(wc.getWidget());
}
iterator = windowWidgets.iterator();
} else if (widgetClassName.equals("VContextMenu")) {
return client.getContextMenu();
} else {
iterator = (Iterator<? extends Widget>) parent.iterator();
}
boolean ok = false;
// Find the widgetPosition:th child of type "widgetClassName"
while (iterator.hasNext()) {
Widget child = iterator.next();
String simpleName2 = Util.getSimpleName(child);
if (!widgetClassName.equals(simpleName2)
&& child instanceof Slot) {
/*