summaryrefslogtreecommitdiff
path: root/library/main/src/com
diff options
context:
space:
mode:
Diffstat (limited to 'library/main/src/com')
-rw-r--r--library/main/src/com/android/setupwizardlib/SetupWizardItemsLayout.java9
-rw-r--r--library/main/src/com/android/setupwizardlib/items/AbstractItem.java53
-rw-r--r--library/main/src/com/android/setupwizardlib/items/AbstractItemHierarchy.java67
-rw-r--r--library/main/src/com/android/setupwizardlib/items/GenericInflater.java2
-rw-r--r--library/main/src/com/android/setupwizardlib/items/IItem.java48
-rw-r--r--library/main/src/com/android/setupwizardlib/items/Item.java18
-rw-r--r--library/main/src/com/android/setupwizardlib/items/ItemAdapter.java53
-rw-r--r--library/main/src/com/android/setupwizardlib/items/ItemGroup.java185
-rw-r--r--library/main/src/com/android/setupwizardlib/items/ItemHierarchy.java75
-rw-r--r--library/main/src/com/android/setupwizardlib/items/ItemInflater.java4
10 files changed, 475 insertions, 39 deletions
diff --git a/library/main/src/com/android/setupwizardlib/SetupWizardItemsLayout.java b/library/main/src/com/android/setupwizardlib/SetupWizardItemsLayout.java
index fbf6618..0a03878 100644
--- a/library/main/src/com/android/setupwizardlib/SetupWizardItemsLayout.java
+++ b/library/main/src/com/android/setupwizardlib/SetupWizardItemsLayout.java
@@ -26,6 +26,8 @@ import com.android.setupwizardlib.items.ItemInflater;
public class SetupWizardItemsLayout extends SetupWizardListLayout {
+ private ItemAdapter mAdapter;
+
public SetupWizardItemsLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0);
@@ -42,8 +44,13 @@ public class SetupWizardItemsLayout extends SetupWizardListLayout {
int xml = a.getResourceId(R.styleable.SuwSetupWizardItemsLayout_android_entries, 0);
if (xml != 0) {
ItemGroup inflated = (ItemGroup) new ItemInflater(context).inflate(xml);
- setAdapter(ItemAdapter.create(inflated));
+ mAdapter = new ItemAdapter(inflated);
+ setAdapter(mAdapter);
}
a.recycle();
}
+
+ public ItemAdapter getAdapter() {
+ return mAdapter;
+ }
}
diff --git a/library/main/src/com/android/setupwizardlib/items/AbstractItem.java b/library/main/src/com/android/setupwizardlib/items/AbstractItem.java
new file mode 100644
index 0000000..047d18a
--- /dev/null
+++ b/library/main/src/com/android/setupwizardlib/items/AbstractItem.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.setupwizardlib.items;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+/**
+ * Abstract implementation of an item, which implements {@link IItem} and takes care of implementing
+ * methods for {@link ItemHierarchy} for items representing itself.
+ */
+public abstract class AbstractItem extends AbstractItemHierarchy implements IItem {
+
+ public AbstractItem() {
+ super();
+ }
+
+ public AbstractItem(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public int getCount() {
+ return 1;
+ }
+
+ @Override
+ public IItem getItemAt(int position) {
+ return this;
+ }
+
+ @Override
+ public ItemHierarchy findItemById(int id) {
+ if (id == getId()) {
+ return this;
+ }
+ return null;
+ }
+}
diff --git a/library/main/src/com/android/setupwizardlib/items/AbstractItemHierarchy.java b/library/main/src/com/android/setupwizardlib/items/AbstractItemHierarchy.java
new file mode 100644
index 0000000..c56e3bc
--- /dev/null
+++ b/library/main/src/com/android/setupwizardlib/items/AbstractItemHierarchy.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.setupwizardlib.items;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+
+import com.android.setupwizardlib.R;
+
+import java.util.ArrayList;
+
+/**
+ * An abstract item hierarchy; provides default implementation for ID and observers.
+ */
+public abstract class AbstractItemHierarchy implements ItemHierarchy {
+
+ private ArrayList<Observer> mObservers = new ArrayList<>();
+ private int mId = 0;
+
+ public AbstractItemHierarchy() {
+ }
+
+ public AbstractItemHierarchy(Context context, AttributeSet attrs) {
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SuwAbstractItem);
+ mId = a.getResourceId(R.styleable.SuwAbstractItem_android_id, 0);
+ a.recycle();
+ }
+
+ public void setId(int id) {
+ mId = id;
+ }
+
+ public int getId() {
+ return mId;
+ }
+
+ @Override
+ public void registerObserver(Observer observer) {
+ mObservers.add(observer);
+ }
+
+ @Override
+ public void unregisterObserver(Observer observer) {
+ mObservers.remove(observer);
+ }
+
+ public void notifyChanged() {
+ for (Observer observer : mObservers) {
+ observer.onChanged(this);
+ }
+ }
+}
diff --git a/library/main/src/com/android/setupwizardlib/items/GenericInflater.java b/library/main/src/com/android/setupwizardlib/items/GenericInflater.java
index af4ffcc..f3b6e19 100644
--- a/library/main/src/com/android/setupwizardlib/items/GenericInflater.java
+++ b/library/main/src/com/android/setupwizardlib/items/GenericInflater.java
@@ -39,8 +39,6 @@ import android.view.InflateException;
* implementing {@link #onAddChildItem(Object, Object)}.
*
* @param <T> Type of the items to inflate
- *
- * Modified from android.preference.GenericInflater
*/
public abstract class GenericInflater<T> {
diff --git a/library/main/src/com/android/setupwizardlib/items/IItem.java b/library/main/src/com/android/setupwizardlib/items/IItem.java
new file mode 100644
index 0000000..26391dc
--- /dev/null
+++ b/library/main/src/com/android/setupwizardlib/items/IItem.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.setupwizardlib.items;
+
+import android.view.View;
+
+/**
+ * Representation of an item in an {@link ItemHierarchy}.
+ */
+public interface IItem {
+
+ /**
+ * Get the Android resource ID for locating the layout for this item.
+ *
+ * @return Resource ID for the layout of this item. This layout will be used to inflate the View
+ * passed to {@link #onBindView(android.view.View)}.
+ */
+ int getLayoutResource();
+
+ /**
+ * Called by items framework to display the data specified by this item. This method should
+ * update {@code view} to reflect its data.
+ *
+ * @param view A view inflated from {@link #getLayoutResource()}, which should be updated to
+ * display data from this item. This view may be recycled from other items with the
+ * same layout resource.
+ */
+ void onBindView(View view);
+
+ /**
+ * @return True if this item is enabled.
+ */
+ boolean isEnabled();
+}
diff --git a/library/main/src/com/android/setupwizardlib/items/Item.java b/library/main/src/com/android/setupwizardlib/items/Item.java
index 63baa11..e208848 100644
--- a/library/main/src/com/android/setupwizardlib/items/Item.java
+++ b/library/main/src/com/android/setupwizardlib/items/Item.java
@@ -30,24 +30,24 @@ import com.android.setupwizardlib.R;
* Definition of an item in SetupWizardItemsLayout. An item is usually defined in XML and inflated
* using {@link ItemInflater}.
*/
-public class Item {
+public class Item extends AbstractItem {
private boolean mEnabled = true;
private Drawable mIcon;
- private int mId = 0;
private int mLayoutRes;
private CharSequence mSummary;
private CharSequence mTitle;
public Item() {
+ super();
mLayoutRes = getDefaultLayoutResource();
}
public Item(Context context, AttributeSet attrs) {
+ super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SuwItem);
mEnabled = a.getBoolean(R.styleable.SuwItem_android_enabled, true);
mIcon = a.getDrawable(R.styleable.SuwItem_android_icon);
- mId = a.getResourceId(R.styleable.SuwItem_android_id, 0);
mTitle = a.getText(R.styleable.SuwItem_android_title);
mSummary = a.getText(R.styleable.SuwItem_android_summary);
mLayoutRes = a.getResourceId(R.styleable.SuwItem_android_layout,
@@ -63,6 +63,7 @@ public class Item {
mEnabled = enabled;
}
+ @Override
public boolean isEnabled() {
return mEnabled;
}
@@ -75,18 +76,11 @@ public class Item {
return mIcon;
}
- public void setId(int id) {
- mId = id;
- }
-
- public int getId() {
- return mId;
- }
-
public void setLayoutResource(int layoutResource) {
mLayoutRes = layoutResource;
}
+ @Override
public int getLayoutResource() {
return mLayoutRes;
}
@@ -107,6 +101,7 @@ public class Item {
return mTitle;
}
+ @Override
public void onBindView(View view) {
TextView label = (TextView) view.findViewById(R.id.suw_items_title);
label.setText(getTitle());
@@ -124,6 +119,7 @@ public class Item {
final Drawable icon = getIcon();
if (icon != null) {
final ImageView iconView = (ImageView) view.findViewById(R.id.suw_items_icon);
+ iconView.setImageState(icon.getState(), false /* merge */);
iconView.setImageLevel(icon.getLevel());
iconView.setImageDrawable(icon);
iconContainer.setVisibility(View.VISIBLE);
diff --git a/library/main/src/com/android/setupwizardlib/items/ItemAdapter.java b/library/main/src/com/android/setupwizardlib/items/ItemAdapter.java
index 3fad091..669d104 100644
--- a/library/main/src/com/android/setupwizardlib/items/ItemAdapter.java
+++ b/library/main/src/com/android/setupwizardlib/items/ItemAdapter.java
@@ -23,31 +23,29 @@ import android.view.ViewGroup;
import android.widget.BaseAdapter;
/**
- * An adapter typically used with ListView to display a list of Items. The list of items used to
- * create this adapter can be inflated by {@link ItemInflater} from XML.
+ * An adapter typically used with ListView to display an
+ * {@link com.android.setupwizardlib.items.ItemHierarchy}. The item hierarchy used to create this
+ * adapter can be inflated by {@link ItemInflater} from XML.
*/
-public class ItemAdapter extends BaseAdapter {
+public class ItemAdapter extends BaseAdapter implements ItemHierarchy.Observer {
- private final Item[] mItems;
+ private final ItemHierarchy mItemHierarchy;
private ViewTypes mViewTypes = new ViewTypes();
- public static ItemAdapter create(ItemGroup items) {
- return new ItemAdapter(items.getChildren());
- }
-
- public ItemAdapter(Item[] items) {
- mItems = items;
+ public ItemAdapter(ItemHierarchy hierarchy) {
+ mItemHierarchy = hierarchy;
+ mItemHierarchy.registerObserver(this);
refreshViewTypes();
}
@Override
public int getCount() {
- return mItems.length;
+ return mItemHierarchy.getCount();
}
@Override
- public Item getItem(int position) {
- return mItems[position];
+ public IItem getItem(int position) {
+ return mItemHierarchy.getItemAt(position);
}
@Override
@@ -57,7 +55,8 @@ public class ItemAdapter extends BaseAdapter {
@Override
public int getItemViewType(int position) {
- int layoutRes = getItem(position).getLayoutResource();
+ IItem item = getItem(position);
+ int layoutRes = item.getLayoutResource();
return mViewTypes.get(layoutRes);
}
@@ -66,15 +65,16 @@ public class ItemAdapter extends BaseAdapter {
return mViewTypes.size();
}
- public void refreshViewTypes() {
- for (Item item : mItems) {
+ private void refreshViewTypes() {
+ for (int i = 0; i < getCount(); i++) {
+ IItem item = getItem(i);
mViewTypes.add(item.getLayoutResource());
}
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
- Item item = getItem(position);
+ IItem item = getItem(position);
if (convertView == null) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
convertView = inflater.inflate(item.getLayoutResource(), parent, false);
@@ -83,6 +83,25 @@ public class ItemAdapter extends BaseAdapter {
return convertView;
}
+ @Override
+ public void onChanged(ItemHierarchy hierarchy) {
+ refreshViewTypes();
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public boolean isEnabled(int position) {
+ return getItem(position).isEnabled();
+ }
+
+ public ItemHierarchy findItemById(int id) {
+ return mItemHierarchy.findItemById(id);
+ }
+
+ public ItemHierarchy getRootItemHierarchy() {
+ return mItemHierarchy;
+ }
+
/**
* A helper class to pack a sparse set of integers (e.g. resource IDs) to a contiguous list of
* integers (e.g. adapter positions), providing mapping to retrieve the original ID from a given
diff --git a/library/main/src/com/android/setupwizardlib/items/ItemGroup.java b/library/main/src/com/android/setupwizardlib/items/ItemGroup.java
index 3752e68..3e500bb 100644
--- a/library/main/src/com/android/setupwizardlib/items/ItemGroup.java
+++ b/library/main/src/com/android/setupwizardlib/items/ItemGroup.java
@@ -18,23 +18,196 @@ package com.android.setupwizardlib.items;
import android.content.Context;
import android.util.AttributeSet;
+import android.util.SparseIntArray;
import java.util.ArrayList;
import java.util.List;
-public class ItemGroup extends Item {
+public class ItemGroup extends AbstractItemHierarchy implements ItemHierarchy.Observer {
- private List<Item> mItems = new ArrayList<>();
+ /* static section */
+
+ /**
+ * Binary search for the closest value that's smaller than or equal to {@code value}, and
+ * return the corresponding key.
+ */
+ private static int binarySearch(SparseIntArray array, int value) {
+ final int size = array.size();
+ int lo = 0;
+ int hi = size - 1;
+
+ while (lo <= hi) {
+ final int mid = (lo + hi) >>> 1;
+ final int midVal = array.valueAt(mid);
+
+ if (midVal < value) {
+ lo = mid + 1;
+ } else if (midVal > value) {
+ hi = mid - 1;
+ } else {
+ return array.keyAt(mid); // value found
+ }
+ }
+ // Value not found. Return the last item before our search range, which is the closest
+ // value smaller than the value we are looking for.
+ return array.keyAt(lo - 1);
+ }
+
+ /* non-static section */
+
+ private List<ItemHierarchy> mChildren = new ArrayList<>();
+
+ /**
+ * A mapping from the index of an item hierarchy in mChildren, to the first position in which
+ * the corresponding child hierarchy represents. For example:
+ *
+ * ItemHierarchy Item Item Position
+ * Index
+ *
+ * 0 [ Wi-Fi AP 1 ] 0
+ * | Wi-Fi AP 2 | 1
+ * | Wi-Fi AP 3 | 2
+ * | Wi-Fi AP 4 | 3
+ * [ Wi-Fi AP 5 ] 4
+ *
+ * 1 [ <Empty Item Hierarchy> ]
+ *
+ * 2 [ Use cellular data ] 5
+ *
+ * 3 [ Don't connect ] 6
+ *
+ * For this example of Wi-Fi screen, the following mapping will be produced:
+ * [ 0 -> 0 | 2 -> 5 | 3 -> 6 ]
+ *
+ * Also note how ItemHierarchy index 1 is not present in the map, because it is empty.
+ *
+ * ItemGroup uses this map to look for which ItemHierarchy an item at a given position belongs
+ * to.
+ */
+ private SparseIntArray mHierarchyStart = new SparseIntArray();
+
+ private int mCount = 0;
+ private boolean mDirty = false;
+
+ public ItemGroup() {
+ super();
+ }
public ItemGroup(Context context, AttributeSet attrs) {
+ // Constructor for XML inflation
super(context, attrs);
}
- public void addChild(Item child) {
- mItems.add(child);
+ /**
+ * Add a child hierarchy to this item group.
+ */
+ public void addChild(ItemHierarchy child) {
+ mChildren.add(child);
+ child.registerObserver(this);
+ onHierarchyChanged();
+ }
+
+ /**
+ * Remove a previously added child from this item group.
+ *
+ * @return True if there is a match for the child and it is removed. False if the child could
+ * not be found in our list of child hierarchies.
+ */
+ public boolean removeChild(ItemHierarchy child) {
+ if (mChildren.remove(child)) {
+ child.unregisterObserver(this);
+ onHierarchyChanged();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Remove all children from this hierarchy.
+ */
+ public void clear() {
+ if (mChildren.size() == 0) {
+ return;
+ }
+
+ for (ItemHierarchy item : mChildren) {
+ item.unregisterObserver(this);
+ }
+ mChildren.clear();
+ onHierarchyChanged();
+ }
+
+ @Override
+ public int getCount() {
+ updateDataIfNeeded();
+ return mCount;
+ }
+
+ @Override
+ public IItem getItemAt(int position) {
+ int itemIndex = getItemIndex(position);
+ ItemHierarchy item = mChildren.get(itemIndex);
+ int subpos = position - mHierarchyStart.get(itemIndex);
+ return item.getItemAt(subpos);
+ }
+
+ @Override
+ public void onChanged(ItemHierarchy hierarchy) {
+ // Need to set dirty, because our children may have gotten more items.
+ mDirty = true;
+ notifyChanged();
+ }
+
+ private void onHierarchyChanged() {
+ onChanged(null);
+ }
+
+ @Override
+ public ItemHierarchy findItemById(int id) {
+ if (id == getId()) {
+ return this;
+ }
+ for (ItemHierarchy child : mChildren) {
+ ItemHierarchy childFindItem = child.findItemById(id);
+ if (childFindItem != null) {
+ return childFindItem;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * If dirty, this method will recalculate the number of items and mHierarchyStart.
+ */
+ private void updateDataIfNeeded() {
+ if (mDirty) {
+ mCount = 0;
+ mHierarchyStart.clear();
+ for (int itemIndex = 0; itemIndex < mChildren.size(); itemIndex++) {
+ ItemHierarchy item = mChildren.get(itemIndex);
+ if (item.getCount() > 0) {
+ mHierarchyStart.put(itemIndex, mCount);
+ }
+ mCount += item.getCount();
+ }
+ mDirty = false;
+ }
}
- public Item[] getChildren() {
- return mItems.toArray(new Item[mItems.size()]);
+ /**
+ * Use binary search to locate the item hierarchy a position is contained in.
+ *
+ * @return Index of the item hierarchy which is responsible for the item at {@code position}.
+ */
+ private int getItemIndex(int position) {
+ updateDataIfNeeded();
+ if (position < 0 || position >= mCount) {
+ throw new IndexOutOfBoundsException("size=" + mCount + "; index=" + position);
+ }
+ int result = binarySearch(mHierarchyStart, position);
+ if (result < 0) {
+ throw new IllegalStateException("Cannot have item start index < 0");
+ }
+ return result;
}
}
diff --git a/library/main/src/com/android/setupwizardlib/items/ItemHierarchy.java b/library/main/src/com/android/setupwizardlib/items/ItemHierarchy.java
new file mode 100644
index 0000000..40a56d5
--- /dev/null
+++ b/library/main/src/com/android/setupwizardlib/items/ItemHierarchy.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.setupwizardlib.items;
+
+/**
+ * Representation of zero or more items in a list. Each instance of ItemHierarchy should be capable
+ * of being wrapped in ItemAdapter and be displayed.
+ *
+ * For example, {@link com.android.setupwizardlib.items.Item} is a representation of a single item,
+ * typically with data provided from XML. {@link com.android.setupwizardlib.items.ItemGroup}
+ * represents a list of child item hierarchies it contains, but itself does not do any display.
+ */
+public interface ItemHierarchy {
+
+ /**
+ * Observer for any changes in this hierarchy. If anything updated that causes this hierarchy to
+ * show different content, this observer should be called.
+ */
+ interface Observer {
+ /**
+ * Called when an underlying data update that can cause this hierarchy to show different
+ * content has occurred.
+ */
+ void onChanged(ItemHierarchy itemHierarchy);
+ }
+
+ /**
+ * Register an observer to observe changes for this item hierarchy.
+ */
+ void registerObserver(Observer observer);
+
+ /**
+ * Unregister a previously registered observer.
+ */
+ void unregisterObserver(Observer observer);
+
+ /**
+ * @return the number of items this item hierarchy represent.
+ */
+ int getCount();
+
+ /**
+ * Get the item at position.
+ *
+ * @param position An integer from 0 to {@link #getCount()}}, which indicates the position in
+ * this item hierarchy to get the child item.
+ * @return A representation of the item at {@code position}. Must not be {@code null}.
+ */
+ IItem getItemAt(int position);
+
+ /**
+ * Find an item hierarchy within this hierarchy which has the given ID. Or null if no match is
+ * found. This hierarchy will be returned if our ID matches. Same restrictions for Android
+ * resource IDs apply to this ID. In fact, typically this ID is a resource ID generated from
+ * XML.
+ *
+ * @param id An ID to search for in this item hierarchy.
+ * @return An ItemHierarchy which matches the given ID.
+ */
+ ItemHierarchy findItemById(int id);
+}
diff --git a/library/main/src/com/android/setupwizardlib/items/ItemInflater.java b/library/main/src/com/android/setupwizardlib/items/ItemInflater.java
index e25e2ad..6bd77ac 100644
--- a/library/main/src/com/android/setupwizardlib/items/ItemInflater.java
+++ b/library/main/src/com/android/setupwizardlib/items/ItemInflater.java
@@ -23,7 +23,7 @@ import android.content.Context;
*
* Modified from android.support.v7.preference.PreferenceInflater
*/
-public class ItemInflater extends GenericInflater<Item> {
+public class ItemInflater extends GenericInflater<ItemHierarchy> {
private static final String TAG = "ItemInflater";
@@ -49,7 +49,7 @@ public class ItemInflater extends GenericInflater<Item> {
}
@Override
- protected void onAddChildItem(Item parent, Item child) {
+ protected void onAddChildItem(ItemHierarchy parent, ItemHierarchy child) {
if (parent instanceof ItemGroup) {
((ItemGroup) parent).addChild(child);
} else {