diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ff0378 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.metadata diff --git a/Core/AndroidBinding/.classpath b/Core/AndroidBinding/.classpath index a4f1e40..26bdfa6 100644 --- a/Core/AndroidBinding/.classpath +++ b/Core/AndroidBinding/.classpath @@ -3,6 +3,7 @@ - + + diff --git a/Core/AndroidBinding/.gitignore b/Core/AndroidBinding/.gitignore index 2896a1c..beb0454 100644 --- a/Core/AndroidBinding/.gitignore +++ b/Core/AndroidBinding/.gitignore @@ -1,4 +1,3 @@ -gen -/**/* - -bin/**/* \ No newline at end of file +.settings/**/* +gen/**/* +bin/**/* diff --git a/Core/AndroidBinding/bin/AndroidManifest.xml b/Core/AndroidBinding/bin/AndroidManifest.xml deleted file mode 100644 index 9f65a6f..0000000 --- a/Core/AndroidBinding/bin/AndroidManifest.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/Core/AndroidBinding/bin/androidbinding.jar b/Core/AndroidBinding/bin/androidbinding.jar deleted file mode 100644 index c2c9a0a..0000000 Binary files a/Core/AndroidBinding/bin/androidbinding.jar and /dev/null differ diff --git a/Core/AndroidBinding/bin/classes/gueei/binding/menu/AbsMenuBridge$OptionsItemObserver.class b/Core/AndroidBinding/bin/classes/gueei/binding/menu/AbsMenuBridge$OptionsItemObserver.class deleted file mode 100644 index aba5e87..0000000 Binary files a/Core/AndroidBinding/bin/classes/gueei/binding/menu/AbsMenuBridge$OptionsItemObserver.class and /dev/null differ diff --git a/Core/AndroidBinding/bin/classes/gueei/binding/menu/AbsMenuBridge.class b/Core/AndroidBinding/bin/classes/gueei/binding/menu/AbsMenuBridge.class deleted file mode 100644 index dc2da27..0000000 Binary files a/Core/AndroidBinding/bin/classes/gueei/binding/menu/AbsMenuBridge.class and /dev/null differ diff --git a/Core/AndroidBinding/bin/classes/gueei/binding/menu/BindableOptionsMenu.class b/Core/AndroidBinding/bin/classes/gueei/binding/menu/BindableOptionsMenu.class deleted file mode 100644 index 997243f..0000000 Binary files a/Core/AndroidBinding/bin/classes/gueei/binding/menu/BindableOptionsMenu.class and /dev/null differ diff --git a/Core/AndroidBinding/bin/classes/gueei/binding/menu/ContextMenuBinder.class b/Core/AndroidBinding/bin/classes/gueei/binding/menu/ContextMenuBinder.class deleted file mode 100644 index 860443f..0000000 Binary files a/Core/AndroidBinding/bin/classes/gueei/binding/menu/ContextMenuBinder.class and /dev/null differ diff --git a/Core/AndroidBinding/bin/classes/gueei/binding/menu/IMenuBinder.class b/Core/AndroidBinding/bin/classes/gueei/binding/menu/IMenuBinder.class deleted file mode 100644 index ab49222..0000000 Binary files a/Core/AndroidBinding/bin/classes/gueei/binding/menu/IMenuBinder.class and /dev/null differ diff --git a/Core/AndroidBinding/bin/classes/gueei/binding/menu/IMenuItemChangedCallback.class b/Core/AndroidBinding/bin/classes/gueei/binding/menu/IMenuItemChangedCallback.class deleted file mode 100644 index 16c1242..0000000 Binary files a/Core/AndroidBinding/bin/classes/gueei/binding/menu/IMenuItemChangedCallback.class and /dev/null differ diff --git a/Core/AndroidBinding/bin/classes/gueei/binding/menu/MenuGroupBridge.class b/Core/AndroidBinding/bin/classes/gueei/binding/menu/MenuGroupBridge.class deleted file mode 100644 index a97c118..0000000 Binary files a/Core/AndroidBinding/bin/classes/gueei/binding/menu/MenuGroupBridge.class and /dev/null differ diff --git a/Core/AndroidBinding/bin/classes/gueei/binding/menu/MenuItemBridge.class b/Core/AndroidBinding/bin/classes/gueei/binding/menu/MenuItemBridge.class deleted file mode 100644 index 6669a6b..0000000 Binary files a/Core/AndroidBinding/bin/classes/gueei/binding/menu/MenuItemBridge.class and /dev/null differ diff --git a/Core/AndroidBinding/bin/classes/gueei/binding/menu/MenuItemViemodel.class b/Core/AndroidBinding/bin/classes/gueei/binding/menu/MenuItemViemodel.class deleted file mode 100644 index 52182b9..0000000 Binary files a/Core/AndroidBinding/bin/classes/gueei/binding/menu/MenuItemViemodel.class and /dev/null differ diff --git a/Core/AndroidBinding/bin/classes/gueei/binding/menu/OnMenuItemClickListenerMulticast.class b/Core/AndroidBinding/bin/classes/gueei/binding/menu/OnMenuItemClickListenerMulticast.class deleted file mode 100644 index 06c3f69..0000000 Binary files a/Core/AndroidBinding/bin/classes/gueei/binding/menu/OnMenuItemClickListenerMulticast.class and /dev/null differ diff --git a/Core/AndroidBinding/bin/classes/gueei/binding/menu/OptionsMenuBinder.class b/Core/AndroidBinding/bin/classes/gueei/binding/menu/OptionsMenuBinder.class deleted file mode 100644 index a1edd7a..0000000 Binary files a/Core/AndroidBinding/bin/classes/gueei/binding/menu/OptionsMenuBinder.class and /dev/null differ diff --git a/Core/AndroidBinding/src/gueei/binding/Attribute.java b/Core/AndroidBinding/src/gueei/binding/Attribute.java index caaadbc..8d23d7a 100644 --- a/Core/AndroidBinding/src/gueei/binding/Attribute.java +++ b/Core/AndroidBinding/src/gueei/binding/Attribute.java @@ -63,25 +63,36 @@ public void _setObject(final Object newValue, Collection initiators){ // Set to package internal for debug use Bridge mBridge; + BindingType mBindingType = BindingType.NoBinding; public BindingType BindTo(Context context, IObservable prop) { if (prop == null) return BindingType.NoBinding; - BindingType binding; - // Dirty fix // Since for InnerFieldObservable, it may not know what type of it will be // So, it assumes two way no matter what if (prop instanceof Undetermined) - binding = BindingType.TwoWay; + mBindingType = BindingType.TwoWay; else - binding = AcceptThisTypeAs(prop.getType()); + mBindingType = AcceptThisTypeAs(prop.getType()); - if (binding.equals(BindingType.NoBinding)) return binding; + if (mBindingType.equals(BindingType.NoBinding)) return mBindingType; - onBind(context, prop, binding); + onBind(context, prop, mBindingType); - return binding; + return mBindingType; + } + + public void UnbindAll() { + if(mBridge == null) + return; + + mBridge.unbind(); + if (mBindingType.equals(BindingType.TwoWay)) + this.unsubscribe(mBridge); + + mBridge = null; + mBindingType = BindingType.NoBinding; } /* @@ -122,6 +133,12 @@ public Bridge(Attribute attribute, IObservable observable){ mBindedObservable = observable; } + public void unbind() { + if(mBindedObservable != null) + mBindedObservable.unsubscribe(this); + mBindedObservable = null; + } + public void onPropertyChanged(IObservable prop, Collection initiators) { if (prop==mAttribute){ diff --git a/Core/AndroidBinding/src/gueei/binding/AttributeBinder.java b/Core/AndroidBinding/src/gueei/binding/AttributeBinder.java index b7f41f1..7288dff 100644 --- a/Core/AndroidBinding/src/gueei/binding/AttributeBinder.java +++ b/Core/AndroidBinding/src/gueei/binding/AttributeBinder.java @@ -3,6 +3,7 @@ import gueei.binding.ISyntaxResolver.SyntaxResolveException; import gueei.binding.bindingProviders.BindingProvider; import gueei.binding.exception.AttributeNotDefinedException; +import gueei.binding.widgets.IBindableLayout; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -60,6 +61,24 @@ public void bindView(Context context, View view, Object model) { bindAttributeWithModel(context, view, entry.getKey(), entry.getValue(), model); } } + + public void unbindView(Context context, View view) { + BindingMap map = Binder.getBindingMapForView(view); + + for(Entry entry: map.getMapTable().entrySet()){ + ViewAttribute attr; + try { + attr = Binder.getAttributeForView(view, entry.getKey()); + if(view instanceof IBindableLayout) { + ((IBindableLayout)view).unbind(); + } + attr.UnbindAll(); + } catch (AttributeNotDefinedException e) { + continue; + } + + } + } public boolean bindAttributeWithModel(Context context, View view, String viewAttributeName, String statement, Object model) { diff --git a/Core/AndroidBinding/src/gueei/binding/Binder.java b/Core/AndroidBinding/src/gueei/binding/Binder.java index d6a542f..336efe5 100644 --- a/Core/AndroidBinding/src/gueei/binding/Binder.java +++ b/Core/AndroidBinding/src/gueei/binding/Binder.java @@ -53,6 +53,10 @@ public static View bindView(Context context, InflateResult inflatedView, Object return _kernel.bindView(context, inflatedView, model); } + public static void unbindView(Context context, InflateResult inflatedView){ + _kernel.unbindView(context, inflatedView); + } + public static void init(Application application){ init(application, new DefaultKernel()); } diff --git a/Core/AndroidBinding/src/gueei/binding/Converter.java b/Core/AndroidBinding/src/gueei/binding/Converter.java index cc88651..325464b 100644 --- a/Core/AndroidBinding/src/gueei/binding/Converter.java +++ b/Core/AndroidBinding/src/gueei/binding/Converter.java @@ -22,7 +22,16 @@ public boolean ConvertBack(Object value, Object[] outResult) { public void setContext(Context context){ mContext = context; } + public Context getContext(){ return mContext; } + + @Override + public void unsubscribe(Observer o){ + super.unsubscribe(o); + if(!hasObservers()) + setContext(null); + } + } diff --git a/Core/AndroidBinding/src/gueei/binding/DependentObservable.java b/Core/AndroidBinding/src/gueei/binding/DependentObservable.java index 107a5a1..f0c7fae 100644 --- a/Core/AndroidBinding/src/gueei/binding/DependentObservable.java +++ b/Core/AndroidBinding/src/gueei/binding/DependentObservable.java @@ -71,4 +71,22 @@ public boolean isDirty() { public void setDirty(boolean dirty) { this.dirty = dirty; } + + @Override + public void unsubscribe(Observer o){ + super.unsubscribe(o); + + if(hasObservers()) + return; + + if(mDependents == null) + return; + + int len = mDependents.length; + for(int i=0; i> T getMulticastListenerForView(View view, Class listenerType); public void init(Application application); diff --git a/Core/AndroidBinding/src/gueei/binding/InnerFieldObservable.java b/Core/AndroidBinding/src/gueei/binding/InnerFieldObservable.java index 8165629..db5dfd3 100644 --- a/Core/AndroidBinding/src/gueei/binding/InnerFieldObservable.java +++ b/Core/AndroidBinding/src/gueei/binding/InnerFieldObservable.java @@ -151,7 +151,7 @@ public final void notifyChanged(Object initiator){ public final void notifyChanged(Collection initiators){ initiators.add(this); for(Object o: observers.toArray()){ - if (initiators.contains(o)) continue; + if (initiators.contains(o) || o == null) continue; ((Observer)o).onPropertyChanged(this, initiators); } } diff --git a/Core/AndroidBinding/src/gueei/binding/Observable.java b/Core/AndroidBinding/src/gueei/binding/Observable.java index 5f9a73a..8059840 100644 --- a/Core/AndroidBinding/src/gueei/binding/Observable.java +++ b/Core/AndroidBinding/src/gueei/binding/Observable.java @@ -55,7 +55,7 @@ public final void notifyChanged(Object initiator){ public final void notifyChanged(Collection initiators){ initiators.add(this); for(Object o: observers.toArray()){ - if (initiators.contains(o)) continue; + if (initiators.contains(o) || o == null) continue; ((Observer)o).onPropertyChanged(this, initiators); } } @@ -121,4 +121,8 @@ public Observer[] getAllObservers() { public boolean isNull() { return mValue==null; } + + public boolean hasObservers() { + return observers.size() > 0; + } } diff --git a/Core/AndroidBinding/src/gueei/binding/TwoWayDependentObservable.java b/Core/AndroidBinding/src/gueei/binding/TwoWayDependentObservable.java index b183497..539c4aa 100644 --- a/Core/AndroidBinding/src/gueei/binding/TwoWayDependentObservable.java +++ b/Core/AndroidBinding/src/gueei/binding/TwoWayDependentObservable.java @@ -20,9 +20,15 @@ public TwoWayDependentObservable(Class type, IObservable... dependents){ protected void doSetValue(T newValue, Collection initiators) { int count = mDependents.length; Object[] outResult = new Object[count]; + for(int i=0; iViewAttribute createAttributeForView(View view, String attributeId) { - if (view instanceof CheckedTextView) { - if (attributeId.equals("checked")){ - CheckedTextViewAttribute attr = new CheckedTextViewAttribute((CheckedTextView)view); - return (ViewAttribute) attr; - } - if (attributeId.equals("checkedClickable")){ - CheckedClickableTextViewAttribute attr = new CheckedClickableTextViewAttribute((CheckedTextView)view); - return (ViewAttribute) attr; - } - } - if (!(view instanceof TextView)) return null; - if (attributeId.equals("text")){ - TextViewAttribute attr = new TextViewAttribute((TextView)view, "text"); - return (ViewAttribute) attr; - } - if (attributeId.equals("minLines")){ - return (ViewAttribute) new MinLinesViewAttribute((TextView)view); - } - if (attributeId.equals("maxLines")){ - return (ViewAttribute) new MaxLinesViewAttribute((TextView)view); - } - if (attributeId.equals("textColor")){ - TextColorViewAttribute attr = new TextColorViewAttribute((TextView)view); - return (ViewAttribute) attr; - } - if (attributeId.equals("onTextChanged")){ - if (view instanceof EditText){ - return (ViewAttribute) (new OnTextChangedViewEvent((EditText)view)); - } - } - if (attributeId.equals("typeface")){ - TypefaceViewAttribute attr = new TypefaceViewAttribute((TextView)view); - return (ViewAttribute) attr; - } - if (attributeId.equals("drawableLeft")){ - CompoundDrawableViewAttribute attr = new CompoundDrawableViewAttribute((TextView)view, "drawableLeft"); - return (ViewAttribute) attr; - } - if (attributeId.equals("drawableTop")){ - CompoundDrawableViewAttribute attr = new CompoundDrawableViewAttribute((TextView)view, "drawableTop"); - return (ViewAttribute) attr; - } - if (attributeId.equals("drawableRight")){ - CompoundDrawableViewAttribute attr = new CompoundDrawableViewAttribute((TextView)view, "drawableRight"); - return (ViewAttribute) attr; - } - if (attributeId.equals("drawableBottom")){ - CompoundDrawableViewAttribute attr = new CompoundDrawableViewAttribute((TextView)view, "drawableBottom"); - return (ViewAttribute) attr; - } - - return null; - } +package gueei.binding.bindingProviders; + +import gueei.binding.ViewAttribute; +import gueei.binding.viewAttributes.textView.CheckedClickableTextViewAttribute; +import gueei.binding.viewAttributes.textView.CheckedTextViewAttribute; +import gueei.binding.viewAttributes.textView.CompoundDrawableViewAttribute; +import gueei.binding.viewAttributes.textView.MaxLinesViewAttribute; +import gueei.binding.viewAttributes.textView.MinLinesViewAttribute; +import gueei.binding.viewAttributes.textView.OnTextChangedViewEvent; +import gueei.binding.viewAttributes.textView.TextAppearanceViewAttribute; +import gueei.binding.viewAttributes.textView.TextColorViewAttribute; +import gueei.binding.viewAttributes.textView.TextViewAttribute; +import gueei.binding.viewAttributes.textView.TypefaceViewAttribute; +import android.view.View; +import android.widget.CheckedTextView; +import android.widget.EditText; +import android.widget.TextView; + + +public class TextViewProvider extends BindingProvider { + + @SuppressWarnings("unchecked") + @Override + public ViewAttribute createAttributeForView(View view, String attributeId) { + if (view instanceof CheckedTextView) { + if (attributeId.equals("checked")){ + CheckedTextViewAttribute attr = new CheckedTextViewAttribute((CheckedTextView)view); + return (ViewAttribute) attr; + } + if (attributeId.equals("checkedClickable")){ + CheckedClickableTextViewAttribute attr = new CheckedClickableTextViewAttribute((CheckedTextView)view); + return (ViewAttribute) attr; + } + } + if (!(view instanceof TextView)) return null; + if (attributeId.equals("text")){ + TextViewAttribute attr = new TextViewAttribute((TextView)view, "text"); + return (ViewAttribute) attr; + } + if (attributeId.equals("minLines")){ + return (ViewAttribute) new MinLinesViewAttribute((TextView)view); + } + if (attributeId.equals("maxLines")){ + return (ViewAttribute) new MaxLinesViewAttribute((TextView)view); + } + if (attributeId.equals("textColor")){ + TextColorViewAttribute attr = new TextColorViewAttribute((TextView)view); + return (ViewAttribute) attr; + } + if (attributeId.equals("textAppearance")){ + TextAppearanceViewAttribute attr = new TextAppearanceViewAttribute((TextView)view); + return (ViewAttribute) attr; + } + if (attributeId.equals("onTextChanged")){ + if (view instanceof EditText){ + return (ViewAttribute) (new OnTextChangedViewEvent((EditText)view)); + } + } + if (attributeId.equals("typeface")){ + TypefaceViewAttribute attr = new TypefaceViewAttribute((TextView)view); + return (ViewAttribute) attr; + } + if (attributeId.equals("drawableLeft")){ + CompoundDrawableViewAttribute attr = new CompoundDrawableViewAttribute((TextView)view, "drawableLeft"); + return (ViewAttribute) attr; + } + if (attributeId.equals("drawableTop")){ + CompoundDrawableViewAttribute attr = new CompoundDrawableViewAttribute((TextView)view, "drawableTop"); + return (ViewAttribute) attr; + } + if (attributeId.equals("drawableRight")){ + CompoundDrawableViewAttribute attr = new CompoundDrawableViewAttribute((TextView)view, "drawableRight"); + return (ViewAttribute) attr; + } + if (attributeId.equals("drawableBottom")){ + CompoundDrawableViewAttribute attr = new CompoundDrawableViewAttribute((TextView)view, "drawableBottom"); + return (ViewAttribute) attr; + } + + return null; + } } \ No newline at end of file diff --git a/Core/AndroidBinding/src/gueei/binding/collections/ArrayListObservable.java b/Core/AndroidBinding/src/gueei/binding/collections/ArrayListObservable.java index 9624fcb..c9bd17e 100644 --- a/Core/AndroidBinding/src/gueei/binding/collections/ArrayListObservable.java +++ b/Core/AndroidBinding/src/gueei/binding/collections/ArrayListObservable.java @@ -97,7 +97,8 @@ public boolean addAll(Collection arg0) { public void setAll(Collection arg0) { Object [] oldItems = mArray.toArray(); mArray.clear(); - mArray.addAll(arg0); + if(arg0 != null) + mArray.addAll(arg0); CollectionChangedEventArg e = new CollectionChangedEventArg(Action.Replace, mArray, Arrays.asList(oldItems)); this.notifyCollectionChanged(e); } diff --git a/Core/AndroidBinding/src/gueei/binding/collections/CollectionAdapter-unbind.java.txt b/Core/AndroidBinding/src/gueei/binding/collections/CollectionAdapter-unbind.java.txt new file mode 100644 index 0000000..aecdbbe --- /dev/null +++ b/Core/AndroidBinding/src/gueei/binding/collections/CollectionAdapter-unbind.java.txt @@ -0,0 +1,375 @@ +package gueei.binding.collections; + +import gueei.binding.AttributeBinder; +import gueei.binding.Binder; +import gueei.binding.BindingLog; +import gueei.binding.CollectionChangedEventArg; +import gueei.binding.CollectionObserver; +import gueei.binding.IObservable; +import gueei.binding.IObservableCollection; +import gueei.binding.ISyntaxResolver.SyntaxResolveException; +import gueei.binding.utility.CachedModelReflector; +import gueei.binding.utility.EventMarkerHelper; +import gueei.binding.utility.IModelReflector; +import gueei.binding.viewAttributes.adapterView.listView.ItemViewEventMark; +import gueei.binding.viewAttributes.templates.Layout; +import gueei.binding.widgets.BindableLayoutContent; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import android.content.Context; +import android.os.Handler; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AbsListView; +import android.widget.BaseAdapter; +import android.widget.Filter; +import android.widget.Filterable; + +public class CollectionAdapter extends BaseAdapter implements CollectionObserver, Filterable, LazyLoadAdapter { + + @Override + public int getViewTypeCount() { + return mLayout.getTemplateCount(); + } + + @Override + public int getItemViewType(int position) { + return mLayout.getLayoutTypeId(position); + } + + protected final Handler mHandler; + protected final Context mContext; + protected final Layout mLayout, mDropDownLayout; + protected final IObservableCollection mCollection; + protected final IModelReflector mReflector; + protected final Filter mFilter; + protected final List mItemList = new ArrayList(); + + public CollectionAdapter(Context context, IModelReflector reflector, IObservableCollection collection, Layout layout, Layout dropDownLayout, + Filter filter, String enableItemStatement) throws Exception { + mHandler = new Handler(); + mContext = context; + mLayout = layout; + mDropDownLayout = dropDownLayout; + mCollection = collection; + mReflector = reflector; + mFilter = filter; + mEnableItemStatement = enableItemStatement; + mCollection.subscribe(this); + } + + public CollectionAdapter(Context context, IModelReflector reflector, IObservableCollection collection, Layout layout, Layout dropDownLayout, + String enableItemStatement) throws Exception { + this(context, reflector, collection, layout, dropDownLayout, null, enableItemStatement); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public CollectionAdapter(Context context, IObservableCollection collection, Layout layout, Layout dropDownLayout, Filter filter, + String enableItemStatement) throws Exception { + this(context, new CachedModelReflector(collection.getComponentType()), collection, layout, dropDownLayout, filter, enableItemStatement); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public CollectionAdapter(Context context, IObservableCollection collection, Layout layout, Layout dropDownLayout, String enableItemStatement) + throws Exception { + this(context, new CachedModelReflector(collection.getComponentType()), collection, layout, dropDownLayout, enableItemStatement); + } + + public void subscribeCollectionObserver(CollectionObserver observer) { + mCollection.subscribe(observer); + } + + public void unsubscribeCollectionObserver(CollectionObserver observer) { + mCollection.unsubscribe(observer); + } + + public int getCount() { + return mCollection.size(); + } + + public Object getItem(int position) { + return mCollection.getItem(position); + } + + public long getItemId(int position) { + return mCollection.getItemId(position); + } + + private View getView(int position, View convertView, ViewGroup parent, Layout layout) { + View returnView = convertView; + if (position >= mCollection.size()) + return returnView; + try { + ObservableMapper mapper; + + mCollection.onLoad(position); + + Object item = mCollection.getItem(position); + + if ((convertView == null) || ((mapper = getAttachedMapper(convertView)) == null)) { + Binder.InflateResult result = + Binder.inflateView(mContext, layout.getLayoutId(position), parent, false); + layout.onAfterInflate(result, position); + ItemViewEventMark mark = new ItemViewEventMark(parent, position, mCollection.getItemId(position)); + EventMarkerHelper.mark(result.rootView, mark); + mapper = new ObservableMapper(); + Object model = mCollection.getItem(position); + mapper.startCreateMapping(mReflector, model); + for (View view : result.processedViews) { + AttributeBinder.getInstance().bindView(mContext, view, mapper); + } + mapper.endCreateMapping(); + returnView = result.rootView; + this.putAttachedMapper(returnView, mapper); + + if(position > -1 && position+1lastTotal){ + mCollection.setVisibleChildrenCount(this, total); + } + + int actualCollectionSize = mCollection.size(); + if (0 == actualCollectionSize) { + // nothing to show, nothing to hide, reset last* + lastDisplayingFirst = -1; + lastTotal = 0; + return; + } + // normalize NEW first and last indexes + // normalize newTotal, should be greater or equal to 0 + int newTotal = total < 0 ? 0 : total; + // normalize newFirstIndex, should be less than actualCollectionSize + int newFirstIndex = (first >= actualCollectionSize) ? actualCollectionSize - 1 : first; + // normalize newFirstIndex, should be greater or equal to 0 + newFirstIndex = newFirstIndex < 0 ? 0 : newFirstIndex; + // calculate last new visible index + int newLastIndex = newFirstIndex + newTotal; + // normalize newLastIndex, should be equal or greater than less than newFirstIndex + newLastIndex = (newLastIndex < newFirstIndex) ? newFirstIndex + 1 : newLastIndex; + // normalize newLastIndex, should be less than actualCollectionSize + newLastIndex = (newLastIndex > actualCollectionSize) ? actualCollectionSize : newLastIndex; + + // normalize OLD first and last indexes (collection size can be changed between function calls) + // normalize oldTotal, should be greater or equal to 0 + int oldTotal = lastTotal < 0 ? 0 : lastTotal; + // normalize oldFirstIndex, should be less or equal to actualCollectionSize + int oldFirstIndex = (lastDisplayingFirst > actualCollectionSize - 1) ? actualCollectionSize - 1 : lastDisplayingFirst; + // normalize oldFirstIndex, should be greater or equal to 0 + oldFirstIndex = oldFirstIndex < 0 ? 0 : oldFirstIndex; + // calculate last old visible index + int oldLastIndex = oldFirstIndex + oldTotal; + // normalize oldLastIndex, should be equal or greater than less than oldFirstIndex + oldLastIndex = (oldLastIndex < oldFirstIndex) ? oldFirstIndex + 1 : oldLastIndex; + // normalize oldLastIndex, should be less or equal to actualCollectionSize + oldLastIndex = (oldLastIndex > actualCollectionSize) ? actualCollectionSize : oldLastIndex; + + Object rawItem; + + for (int i = newFirstIndex; i < oldFirstIndex; ++i) { + rawItem = mCollection.getItem(i); + if (rawItem instanceof ILazyLoadRowModel) { + ((ILazyLoadRowModel) rawItem).display(mCollection, i); + } + } + for (int i = oldFirstIndex; i < newFirstIndex; ++i) { + rawItem = mCollection.getItem(i); + if (rawItem instanceof ILazyLoadRowModel) { + if (!((ILazyLoadRowModel) rawItem).isMapped()) + ((ILazyLoadRowModel) rawItem).hide(mCollection, i); + } + } + + for (int i = newLastIndex; i < oldLastIndex; ++i) { + rawItem = mCollection.getItem(i); + if (rawItem instanceof ILazyLoadRowModel) { + if (!((ILazyLoadRowModel) rawItem).isMapped()) + ((ILazyLoadRowModel) rawItem).hide(mCollection, i); + } + } + for (int i = oldLastIndex; i < newLastIndex; ++i) { + rawItem = mCollection.getItem(i); + if (rawItem instanceof ILazyLoadRowModel) { + ((ILazyLoadRowModel) rawItem).display(mCollection, i); + } + } + + // set lastDisplayingFirst and lastTotal; + lastDisplayingFirst = newFirstIndex; + lastTotal = newTotal; + } + + /** + * Statement that determines child item is enable/disable + */ + private String mEnableItemStatement = null; + + /** + * If the statement is null (unset), all items are assumed to be enabled. + */ + @Override + public boolean areAllItemsEnabled() { + return mEnableItemStatement == null; + } + + /** + * Make individual item enable/disable possible. + * This is not possible to do in Item level, but only from ListView's level since + * items are rendered by listView and listview seems to omit this value + */ + + @Override + public boolean isEnabled(int position) { + if (mEnableItemStatement == null) + return true; + IObservable obs; + try { + obs = Binder.getSyntaxResolver().constructObservableFromStatement(mContext, mEnableItemStatement, mCollection.getItem(position)); + } catch (SyntaxResolveException e) { + BindingLog.exception("CollectionAdapter.isEnabled", e); + return false; + } + // Even if the obs is null, or it's value is null, it is enabled by default + return obs == null || !Boolean.FALSE.equals(obs.get()); + } + + @Override + public void onCollectionChanged(IObservableCollection collection, + CollectionChangedEventArg args, Collection initiators) { + listChanged(args,collection); + notifyDataSetChanged(); + } + + private void listChanged(CollectionChangedEventArg e, IObservableCollection collection) { + if( e == null) + return; + + int start, size, i; + + switch( e.getAction()) { + case Add: + start = e.getNewStartingIndex(); + size = e.getNewItems().size(); + for(i = start; i < start+size; i++) { + mItemList.add(i, null); + } + break; + case Remove: + start = e.getOldStartingIndex(); + size = e.getOldItems().size(); + for(i = 0; i < size; i++) { + BindableLayoutContent content = mItemList.get(start); + if(content != null) { + Binder.unbindView(mContext, content.getInflateResult()); + } + mItemList.remove(start); + } + break; + case Replace: + start = e.getOldStartingIndex(); + size = e.getOldItems().size(); + for(i = 0; i < size; i++) { + BindableLayoutContent content = mItemList.get(start); + if(content != null) { + Binder.unbindView(mContext, content.getInflateResult()); + } + mItemList.remove(start); + } + + start = e.getNewStartingIndex(); + size = e.getNewItems().size(); + for(i = start; i < start+size; i++) { + mItemList.add(i, null); + } + break; + case Reset: + size = mItemList.size(); + for(i = 0; i < size; i++) { + BindableLayoutContent content = mItemList.get(i); + if(content != null) { + Binder.unbindView(mContext, content.getInflateResult()); + } + } + mItemList.clear(); + break; + case Move: + // currently the observable array list doesn't create this action + throw new IllegalArgumentException("move not implemented"); + default: + throw new IllegalArgumentException("unknown action " + e.getAction().toString()); + } + } + +} \ No newline at end of file diff --git a/Core/AndroidBinding/src/gueei/binding/converters/HIGHLIGHT_SPAN.java b/Core/AndroidBinding/src/gueei/binding/converters/HIGHLIGHT_SPAN.java index 60cdbdc..23936ed 100644 --- a/Core/AndroidBinding/src/gueei/binding/converters/HIGHLIGHT_SPAN.java +++ b/Core/AndroidBinding/src/gueei/binding/converters/HIGHLIGHT_SPAN.java @@ -8,51 +8,29 @@ import gueei.binding.Command; import gueei.binding.Converter; import gueei.binding.IObservable; +import gueei.binding.converters.SPAN.SPANHelper; import gueei.binding.observables.SpanObservable.Span; - /** - * highlights all occurences in a given text with a span + * HIGHLIGHT_SPAN accepts needs three arguments + * It will return a SpannableString and highlight the given positions + * + * @usage params + * + * @arg hey string + * @arg needle string + * @arg SpanCreatorCommand or SpanListCreatorCommand for creating the Spans * - * Param 0: TextInput - * Param 1: Text to search - * Param 2: SpanCreatorCommand or SpanListCreatorCommand for creating the Spans + * @return SpannableString * - * @return list of Spans + * @author egandro + * */ public class HIGHLIGHT_SPAN extends Converter { - public static abstract class SpanCreatorCommand extends Command { - public Span Span = null; - - @Override - public void Invoke(View view, Object... args) { - int occurence = 0; - if( args.length > 0 && args[0] instanceof Integer) { - occurence = (Integer)args[0]; - } - Span = onCreateSpan(occurence); - } - - public abstract Span onCreateSpan(int occurence); - } + private SPANHelper helper = new SPANHelper(this); - public static abstract class SpanListCreatorCommand extends Command { - public List SpanList = null; - - @Override - public void Invoke(View view, Object... args) { - int occurence = 0; - if( args.length > 0 && args[0] instanceof Integer) { - occurence = (Integer)args[0]; - } - SpanList = onCreateSpanList(occurence); - } - - public abstract List onCreateSpanList(int occurence); - } - public HIGHLIGHT_SPAN(IObservable[] dependents) { super(Object.class, dependents); } @@ -63,18 +41,26 @@ public Object calculateValue(Object... args) throws Exception { return null; if( args[0] == null || args[1] == null || args[2] == null) - return null; + return null; String hey = args[0].toString(); String needle = args[1].toString(); if(needle.length() < 1) - return null; + return args[0]; + + ArrayList spanList = new ArrayList(); + createSpanList(spanList, hey, needle, args[2]); - int length =needle.length(); + helper.updateSpanable(args[0], spanList); + + return helper.text; + } + + private void createSpanList(ArrayList spanList, String hey, String needle, Object command) { + + int length = needle.length(); - ArrayList result = new ArrayList(); - int occurence = 1; int index = hey.indexOf(needle); while (index >=0){ @@ -82,8 +68,8 @@ public Object calculateValue(Object... args) throws Exception { int start=index; int end=start+length; - if( args[2] instanceof SpanListCreatorCommand ) { - SpanListCreatorCommand cmd = (SpanListCreatorCommand)args[2]; + if( command instanceof SpanListCreatorCommand ) { + SpanListCreatorCommand cmd = (SpanListCreatorCommand)command; cmd.Invoke(null, (Object[])new Integer [] { occurence }); List list = cmd.SpanList; @@ -96,29 +82,55 @@ public Object calculateValue(Object... args) throws Exception { } else { s = new Span(o,start,end); } - result.add(s); + spanList.add(s); } } - } else if( args[2] instanceof SpanCreatorCommand ) { - SpanCreatorCommand cmd = (SpanCreatorCommand)args[2]; + } else if(command instanceof SpanCreatorCommand ) { + SpanCreatorCommand cmd = (SpanCreatorCommand)command; cmd.Invoke(null, (Object[])new Integer [] { occurence }); Span os = cmd.Span; if(os != null) { Span s = new Span(os.What,start,end,os.Flags); - result.add(s); + spanList.add(s); } } else { - Span s = new Span(args[2],start,end); - result.add(s); + Span s = new Span(command,start,end); + spanList.add(s); } index = hey.indexOf(needle, index+length); occurence++; } + } + + public static abstract class SpanCreatorCommand extends Command { + public Span Span = null; - if(result.size() == 0) - return null; - return result; + @Override + public void Invoke(View view, Object... args) { + int occurence = 0; + if( args.length > 0 && args[0] instanceof Integer) { + occurence = (Integer)args[0]; + } + Span = onCreateSpan(occurence); + } + + public abstract Span onCreateSpan(int occurence); } + + public static abstract class SpanListCreatorCommand extends Command { + public List SpanList = null; + + @Override + public void Invoke(View view, Object... args) { + int occurence = 0; + if( args.length > 0 && args[0] instanceof Integer) { + occurence = (Integer)args[0]; + } + SpanList = onCreateSpanList(occurence); + } + + public abstract List onCreateSpanList(int occurence); + } } diff --git a/Core/AndroidBinding/src/gueei/binding/converters/SPAN.java b/Core/AndroidBinding/src/gueei/binding/converters/SPAN.java new file mode 100644 index 0000000..a2fca33 --- /dev/null +++ b/Core/AndroidBinding/src/gueei/binding/converters/SPAN.java @@ -0,0 +1,160 @@ +package gueei.binding.converters; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import android.text.Spannable; +import android.text.SpannableString; + +import gueei.binding.CollectionChangedEventArg; +import gueei.binding.CollectionObserver; +import gueei.binding.Converter; +import gueei.binding.IObservable; +import gueei.binding.IObservableCollection; +import gueei.binding.collections.ObservableCollection; +import gueei.binding.observables.SpanObservable.Span; + +/** + * SPAN accepts needs two arguments + * It will return a SpannableString + * + * @usage params + * + * @arg input text string + * @arg args Object (Span or List of Spans) + * + * @return SpannableString + * + * @author egandro + * + */ +public class SPAN extends Converter { + + private SPANHelper helper = new SPANHelper(this); + + public SPAN(IObservable[] dependents) { + super(Object.class, dependents); + } + + @Override + public Object calculateValue(Object... args) throws Exception { + if(args.length == 0) return null; + if(args.length != 2) return args[0]; + if(args[0] == null) return args[0]; + + helper.updateSpanable(args[0], args[1]); + + return helper.text; + } + + public static class SPANHelper { + Converter parent; + Object oldValue; + ObservableCollection collection; + SpannableString text; + + public SPANHelper(Converter parent) { + this.parent = parent; + } + + private CollectionObserver attrObserver = new CollectionObserver(){ + @Override + public void onCollectionChanged(IObservableCollection collection, + CollectionChangedEventArg args, Collection initiators) { + updateSpanable(null, collection); + parent.notifyChanged(); + } + }; + + public void updateSpanable(Object textValue, Object newValue) { + if(newValue == null) + return; + + if(textValue != null) { + if( textValue instanceof SpannableString) + text = (SpannableString)textValue; + else + text = new SpannableString(textValue.toString()); + } + + if(text == null) + return; + + int length = text.length(); + + if(textValue == null && oldValue != null) { + if(oldValue instanceof Span ) { + text.removeSpan(((Span) oldValue).What); + } else if( oldValue instanceof List) { + @SuppressWarnings("rawtypes") + List list = (List)oldValue; + for( Object o : list) { + if(o instanceof Span) + text.removeSpan(((Span) o).What); + } + } + } + + if(collection != null) { + collection.unsubscribe(attrObserver); + collection = null; + } + + if( newValue instanceof Span ) { + Span s = (Span) newValue; + if(s.What != null) + safeSetSpan(text,s,length); + oldValue = newValue; + } else if(newValue instanceof List) { + ArrayList newList = new ArrayList(); + oldValue = newList; + + List list = (List)newValue; + + for( Object o : list) { + if( o instanceof Span) { + Span s = (Span) o; + if(s.What != null) { + if( safeSetSpan(text,s,length) ) + newList.add(s); + } + } + } + + if(newValue instanceof ObservableCollection) { + collection = (ObservableCollection)newValue; + collection.subscribe(attrObserver); + } + + // we need to create a new spanable - the set() of the textview only updates in case of a change + if(list != null) + text = new SpannableString(text); + } else { + oldValue = null; + } + } + + private boolean safeSetSpan(Spannable sText, Span s, int length) { + if(sText == null || s == null || length < 1) + return false; + + int start = s.Start; + int end = s.End; + + if(start == 0 && end == 0) + end = length; + + if(start > length) + return false; + if(end > length) + return false; + if(end < start) + return false; + + sText.setSpan(s.What, start, end, s.Flags); + return true; + } + } + +} diff --git a/Core/AndroidBinding/src/gueei/binding/kernel/KernelBase.java b/Core/AndroidBinding/src/gueei/binding/kernel/KernelBase.java index 4b02629..921b04a 100644 --- a/Core/AndroidBinding/src/gueei/binding/kernel/KernelBase.java +++ b/Core/AndroidBinding/src/gueei/binding/kernel/KernelBase.java @@ -16,19 +16,6 @@ import gueei.binding.ViewAttribute; import gueei.binding.ViewFactory; import gueei.binding.ViewTag; -import gueei.binding.bindingProviders.AbsSpinnerViewProvider; -import gueei.binding.bindingProviders.AdapterViewProvider; -import gueei.binding.bindingProviders.CompoundButtonProvider; -import gueei.binding.bindingProviders.ExpandableListViewProvider; -import gueei.binding.bindingProviders.ImageViewProvider; -import gueei.binding.bindingProviders.ListViewProvider; -import gueei.binding.bindingProviders.ProgressBarProvider; -import gueei.binding.bindingProviders.RatingBarProvider; -import gueei.binding.bindingProviders.SeekBarProvider; -import gueei.binding.bindingProviders.TabHostProvider; -import gueei.binding.bindingProviders.TextViewProvider; -import gueei.binding.bindingProviders.ViewAnimatorProvider; -import gueei.binding.bindingProviders.ViewProvider; import gueei.binding.exception.AttributeNotDefinedException; import gueei.binding.listeners.MulticastListenerCollection; import gueei.binding.listeners.ViewMulticastListener; @@ -119,6 +106,15 @@ public View bindView(Context context, InflateResult inflatedView, Object model) } return inflatedView.rootView; } + + @Override + public void unbindView(Context context, InflateResult inflatedView) { + if(inflatedView == null || inflatedView.processedViews == null) + return; + for(View v: inflatedView.processedViews){ + AttributeBinder.getInstance().unbindView(context, v); + } + } @Override public > T getMulticastListenerForView( diff --git a/Core/AndroidBinding/src/gueei/binding/utility/WeakList.java b/Core/AndroidBinding/src/gueei/binding/utility/WeakList.java index f0ebfa9..b3d7e8d 100644 --- a/Core/AndroidBinding/src/gueei/binding/utility/WeakList.java +++ b/Core/AndroidBinding/src/gueei/binding/utility/WeakList.java @@ -101,17 +101,33 @@ public Object[] toArray() { @Override public boolean remove(Object object) { synchronized(this){ - int len = items.size(); - for(int i=0; i[] itemArray = items.toArray(new WeakReference[0]); - for(int i=0; i[] itemArray = items.toArray(new WeakReference[0]); + for(int i=0; i { + + public TextAppearanceViewAttribute(TextView view) { + super(Integer.class, view, "textAppearance"); + } + + @Override + protected void doSetAttributeValue(Object newValue) { + if(getView()==null) return; + if (newValue instanceof Integer){ + getView().setTextAppearance(getView().getContext(),(Integer)newValue); + } + } + + @Override + protected BindingType AcceptThisTypeAs(Class type) { + return BindingType.OneWay; + } + + @Override + public Integer get() { + return null; + } +} diff --git a/Core/AndroidBinding/src/gueei/binding/viewAttributes/textView/TextViewAttribute.java b/Core/AndroidBinding/src/gueei/binding/viewAttributes/textView/TextViewAttribute.java index ce6f494..7ca12b7 100644 --- a/Core/AndroidBinding/src/gueei/binding/viewAttributes/textView/TextViewAttribute.java +++ b/Core/AndroidBinding/src/gueei/binding/viewAttributes/textView/TextViewAttribute.java @@ -5,6 +5,7 @@ import gueei.binding.ViewAttribute; import gueei.binding.listeners.TextWatcherMulticast; import android.text.Editable; +import android.text.SpannableString; import android.text.TextWatcher; import android.widget.EditText; import android.widget.TextView; @@ -55,6 +56,12 @@ private boolean compareCharSequence(CharSequence a, CharSequence b) { }else{ if (b==null) result = true; } + + // it's the same text sequence - but if it's a spanable text the look can be different + if( result == true && a instanceof SpannableString && b instanceof SpannableString) { + return a.equals(b); + } + return result; } diff --git a/Core/AndroidBinding/src/gueei/binding/viewAttributes/view/VisibilityViewAttribute.java b/Core/AndroidBinding/src/gueei/binding/viewAttributes/view/VisibilityViewAttribute.java index 2c65482..a0e3982 100644 --- a/Core/AndroidBinding/src/gueei/binding/viewAttributes/view/VisibilityViewAttribute.java +++ b/Core/AndroidBinding/src/gueei/binding/viewAttributes/view/VisibilityViewAttribute.java @@ -6,10 +6,15 @@ import android.view.View; -public class VisibilityViewAttribute extends ViewAttribute { - +public class VisibilityViewAttribute extends ViewAttribute { + + // this is a hackish way to avoid cast exceptions when + // when binding the visibility on a menu item and and a view + // the menu item returns an integer and we need a boolean + private boolean isBoolType = true; + public VisibilityViewAttribute(View view, String attributeName) { - super(Integer.class, view, attributeName); + super(Object.class, view, attributeName); } @Override @@ -20,6 +25,7 @@ protected void doSetAttributeValue(Object newValue) { return; } if (newValue instanceof Boolean){ + isBoolType = true; if ((Boolean)newValue) getView().setVisibility(View.VISIBLE); else @@ -27,15 +33,23 @@ protected void doSetAttributeValue(Object newValue) { return; } if (newValue instanceof Integer){ + isBoolType = false; getView().setVisibility((Integer)newValue); return; } } @Override - public Integer get() { + public Object get() { if(getView()==null) return null; - return getView().getVisibility(); + int visibility = getView().getVisibility(); + if(isBoolType) { + if(View.VISIBLE == visibility) + return true; + return false; + } else { + return visibility; + } } @Override diff --git a/Core/AndroidBinding/src/gueei/binding/widgets/BindableFrameLayout.java b/Core/AndroidBinding/src/gueei/binding/widgets/BindableFrameLayout.java index 5b64047..ce34499 100644 --- a/Core/AndroidBinding/src/gueei/binding/widgets/BindableFrameLayout.java +++ b/Core/AndroidBinding/src/gueei/binding/widgets/BindableFrameLayout.java @@ -7,19 +7,17 @@ import gueei.binding.Binder.InflateResult; import gueei.binding.viewAttributes.templates.SingleTemplateLayout; import android.content.Context; -import android.graphics.Canvas; import android.util.AttributeSet; import android.widget.FrameLayout; -public class BindableFrameLayout extends FrameLayout implements IBindableView{ + +// TODO: add a transition manager + +public class BindableFrameLayout extends FrameLayout implements IBindableView, IBindableLayout{ - private int LayoutId = 0; - private Object dataSource = null; - private boolean updateEnabled = true; - private InflateResult inflateResult = null; + private BindableLayoutContent mBindableLayoutContent = new BindableLayoutContent(); - public BindableFrameLayout(Context context, AttributeSet attrs, - int defStyle) { + public BindableFrameLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @@ -31,13 +29,16 @@ public BindableFrameLayout(Context context) { super(context); } + @Override + public void unbind () { + unbind(true); + } + @Override protected void onDetachedFromWindow() { - LayoutId = 0; - dataSource = null; - inflateResult = null; + unbind(false); super.onDetachedFromWindow(); - } + } private ViewAttribute LayoutIdViewAttribute = new ViewAttribute(Object.class, BindableFrameLayout.this, "LayoutId"){ @@ -60,11 +61,10 @@ protected void doSetAttributeValue(Object newValue) { @Override public Object get() { - return LayoutId; + return mBindableLayoutContent.getLayoutId(); } }; - - + private ViewAttribute DataSourceViewAttribute = new ViewAttribute( Object.class, BindableFrameLayout.this, "DataSource"){ @Override @@ -74,7 +74,7 @@ protected void doSetAttributeValue(Object newValue) { @Override public Object get() { - return dataSource; + return mBindableLayoutContent.getDataSource(); } }; @@ -103,89 +103,78 @@ public Command get() { return null; } }; - - private ViewAttribute ItemUpdateEnabledAttribute = - new ViewAttribute(Boolean.class, BindableFrameLayout.this, "UpdateEnabled"){ - @Override - protected void doSetAttributeValue(Object newValue) { - if( newValue == null ) { - updateEnabled = true; - } - else if( newValue instanceof Boolean ) { - Boolean value = (Boolean) newValue; - updateEnabled = value; - if(updateEnabled) { - BindableFrameLayout.this.invalidate(); - } - } - } - - @Override - public Boolean get() { - return updateEnabled; - } - }; - - @Override - protected void onDraw(Canvas canvas) { - if( !updateEnabled ) - return; - super.onDraw(canvas); - } - - @Override - protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) { - if( !updateEnabled ) - return; - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - } - + public ViewAttribute createViewAttribute( String attributeName) { if (attributeName.equals("layoutId")) return LayoutIdViewAttribute; if (attributeName.equals("dataSource")) return DataSourceViewAttribute; if (attributeName.equals("onLoad")) return OnLoadAttribute; - if (attributeName.equals("updateEnabled")) return ItemUpdateEnabledAttribute; return null; } - protected void setDatasource(Object newValue) { - if(dataSource!=null) - inflateResult = null; // inflate new - dataSource = newValue; - rebind(); - refreshDrawableState(); + protected void setDatasource(Object dataSource) { + synchronized(this){ + if(dataSource != null && mBindableLayoutContent.getDataSource() == dataSource) + return; + + int layoutId = mBindableLayoutContent.getLayoutId(); + unbind(true); + mBindableLayoutContent.setDataSource(dataSource); + mBindableLayoutContent.setLayoutId(layoutId); + + if(dataSource == null) + return; + + bind(true); + } } - // TODO: add layout caching - // TODO: add a binding:useLayoutCaching="true" attribute - // TODO: add a transition manager protected void setLayoutId(int layoutId) { - if( LayoutId != layoutId ) { - LayoutId = layoutId; - inflateResult = null; // inflate new - rebind(); - refreshDrawableState(); - } + synchronized(this){ + if( mBindableLayoutContent.getLayoutId() == layoutId ) + return; + + Object dataSource = mBindableLayoutContent.getDataSource(); + unbind(true); + mBindableLayoutContent.setDataSource(dataSource); + mBindableLayoutContent.setLayoutId(layoutId); + bind(true); + } } - protected void rebind(){ - BindableFrameLayout.this.removeAllViews(); - if (LayoutId<=0) return; - if(inflateResult==null||dataSource==null) - inflateResult= Binder.inflateView(BindableFrameLayout.this.getContext(), LayoutId, BindableFrameLayout.this, false); - BindableFrameLayout.this.addView(inflateResult.rootView); - if (dataSource==null){ - Binder.bindView(BindableFrameLayout.this.getContext(), inflateResult, null); - }else if (dataSource.getClass().isArray()){ - Object[] sources = (Object[])dataSource; + protected void bind(boolean addView){ + if (mBindableLayoutContent.getLayoutId()<=0) + return; + + if(mBindableLayoutContent.getInflateResult()==null||mBindableLayoutContent.getDataSource()==null) { + InflateResult result = Binder.inflateView(getContext(), mBindableLayoutContent.getLayoutId(), this, false); + mBindableLayoutContent.setInflateResult(result); + } + + if(addView) + addView(mBindableLayoutContent.getInflateResult().rootView); + + if (mBindableLayoutContent.getDataSource()==null){ + Binder.bindView(getContext(), mBindableLayoutContent.getInflateResult(), null); + }else if (mBindableLayoutContent.getDataSource().getClass().isArray()){ + Object[] sources = (Object[])mBindableLayoutContent.getDataSource(); for(int i=0; i { - private WeakList currentList = null; - private CollectionObserver collectionObserver = new CollectionObserver() { + +public class BindableLinearLayout extends LinearLayout implements IBindableView, IBindableLayout { + private ArrayList mCurrentList = null; + private IObservableCollection mItemList = null; + private LayoutItem mLayoutItem = null; + private SparseArray mItemMap = new SparseArray(); + + private CollectionObserver mCollectionObserver = new CollectionObserver() { @Override - public void onCollectionChanged( - IObservableCollection collection, - CollectionChangedEventArg args, - Collection initiators) { + public void onCollectionChanged(IObservableCollection collection, CollectionChangedEventArg args, Collection initiators) { listChanged(args, collection); } }; - - private ObservableCollection itemList = null; - private LayoutItem layout = null; - private boolean updateEnabled = true; - - private ObservableMultiplexer observableItemsLayoutID = new ObservableMultiplexer(new Observer() { + private ObservableMultiplexer mObservableItemsLayoutID = new ObservableMultiplexer(new Observer() { @Override public void onPropertyChanged(IObservable prop, Collection initiators) { if( initiators == null || initiators.size() < 1) return; Object parent = initiators.toArray()[0]; - int pos = currentList.indexOf(parent); + int pos = mCurrentList.indexOf(parent); ArrayList list = new ArrayList(); list.add(parent); - removeItems(list); - insertItem(pos, parent); + removeAllItems(list); + bindItem(pos, parent); } }); public BindableLinearLayout(Context context, AttributeSet attrs) { super(context, attrs); - init(); } public BindableLinearLayout(Context context) { super(context); - init(); } - private void init() { + @Override + public void unbind () { + synchronized(this){ + if( mItemList != null && mCollectionObserver != null) + mItemList.unsubscribe(mCollectionObserver); + + mObservableItemsLayoutID.clear(); + mCurrentList = null; + mItemList=null; + + for(int i = 0; i < mItemMap.size(); i++) { + BindableLayoutContent content = mItemMap.valueAt(i); + if(content==null) + continue; + Binder.unbindView(getContext(), content.getInflateResult()); + } + + removeAllViews(); + } } @Override protected void onDetachedFromWindow() { - observableItemsLayoutID.clear(); - currentList = null; + unbind(); super.onDetachedFromWindow(); } - private void createItemSourceList(ObservableCollection newList) { - if( itemList != null && collectionObserver != null) - itemList.unsubscribe(collectionObserver); - - itemList = newList; - - if(newList==null) - return; - - currentList = null; - - itemList.subscribe(collectionObserver); - newList(newList); - } - - private void newList(IObservableCollection list) { - this.removeAllViews(); - - observableItemsLayoutID.clear(); - - if( list == null) { - currentList = null; - return; - } - - currentList = new WeakList(); - - for( int pos=0; pos < list.size(); pos ++ ) { - Object item = list.getItem(pos); - insertItem(pos, item); - } - - for( int pos=0; pos < list.size(); pos ++ ) { - Object item = list.getItem(pos); - currentList.add(item); + protected void bind(IObservableCollection newList) { + synchronized(this){ + if(newList==null) + return; + + mItemList = newList; + mItemList.subscribe(mCollectionObserver); + mCurrentList = new ArrayList(); + + for(int pos=0; pos < newList.size(); pos ++) { + Object item = newList.getItem(pos); + bindItem(pos, item); + mCurrentList.add(item); + } } } @@ -134,25 +119,26 @@ private void listChanged(CollectionChangedEventArg e, IObservableCollection c case Add: pos = e.getNewStartingIndex(); for(Object item : e.getNewItems()) { - insertItem(pos, item); + bindItem(pos, item); pos++; } break; case Remove: - removeItems(e.getOldItems()); + removeAllItems(e.getOldItems()); break; case Replace: - removeItems(e.getOldItems()); + removeAllItems(e.getOldItems()); pos = e.getNewStartingIndex(); if( pos < 0) pos=0; for(Object item : e.getNewItems()) { - insertItem(pos, item); + bindItem(pos, item); pos++; } break; case Reset: - newList(collection); + unbind(); + bind(collection); break; case Move: // currently the observable array list doesn't create this action @@ -164,10 +150,10 @@ private void listChanged(CollectionChangedEventArg e, IObservableCollection c if( collection == null) return; - currentList = new WeakList(); + mCurrentList = new ArrayList(); for( pos=0; pos < collection.size(); pos ++ ) { Object item = collection.getItem(pos); - currentList.add(item); + mCurrentList.add(item); } } @@ -179,13 +165,15 @@ protected void doSetAttributeValue(Object newValue) { if( !(newValue instanceof ObservableCollection )) return; - if( layout != null ) - createItemSourceList((ObservableCollection)newValue); + if( mLayoutItem != null ) { + unbind(); + bind((ObservableCollection)newValue); + } } @Override public Object get() { - return itemList; + return mItemList; } }; @@ -193,102 +181,70 @@ public Object get() { new ViewAttribute(Object.class, BindableLinearLayout.this, "ItemLayout"){ @Override protected void doSetAttributeValue(Object newValue) { - layout = null; + mLayoutItem = null; if( newValue instanceof LayoutItem ) { - layout = (LayoutItem) newValue; + mLayoutItem = (LayoutItem) newValue; }else if (newValue instanceof Layout){ - layout = new LayoutItem(((Layout)newValue).getDefaultLayoutId()); + mLayoutItem = new LayoutItem(((Layout)newValue).getDefaultLayoutId()); }else if (newValue instanceof Integer){ - layout = new LayoutItem((Integer)newValue); + mLayoutItem = new LayoutItem((Integer)newValue); }else{ - layout = new LayoutItem(newValue.toString()); + mLayoutItem = new LayoutItem(newValue.toString()); } - if( itemList != null ) - createItemSourceList(itemList); - } - - @Override - public Object get() { - return layout; - } - }; - - private ViewAttribute ItemUpdateEnabledAttribute = - new ViewAttribute(Boolean.class, BindableLinearLayout.this, "UpdateEnabled"){ - @Override - protected void doSetAttributeValue(Object newValue) { - if( newValue == null ) { - updateEnabled = true; - } - else if( newValue instanceof Boolean ) { - Boolean value = (Boolean) newValue; - updateEnabled = value; - if(updateEnabled) { - BindableLinearLayout.this.invalidate(); - } + if( mItemList != null ) { + unbind(); + bind(mItemList); } } @Override - public Boolean get() { - return updateEnabled; + public Object get() { + return mLayoutItem; } - }; - - - @Override - protected void onDraw(Canvas canvas) { - if( !updateEnabled ) - return; - super.onDraw(canvas); - } - - @Override - protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) { - if( !updateEnabled ) - return; - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - } + }; @Override public ViewAttribute createViewAttribute(String attributeId) { if (attributeId.equals("itemSource")) return ItemSourceAttribute; if (attributeId.equals("itemLayout")) return ItemLayoutAttribute; - if (attributeId.equals("updateEnabled")) return ItemUpdateEnabledAttribute; return null; } - private void removeItems(List deleteList) { - if( deleteList == null || deleteList.size() == 0 || currentList == null) + private void removeAllItems(List deleteList) { + if( deleteList == null || deleteList.size() == 0 || mCurrentList == null) return; - ArrayList currentPositionList = new ArrayList(Arrays.asList(currentList.toArray())); + ArrayList currentPositionList = new ArrayList(Arrays.asList(mCurrentList.toArray())); for(Object item : deleteList){ int pos = currentPositionList.indexOf(item); - observableItemsLayoutID.removeParent(item); + mObservableItemsLayoutID.removeParent(item); currentPositionList.remove(item); - if( pos > -1 && pos < this.getChildCount()) - this.removeViewAt(pos); + if( pos > -1 && pos < this.getChildCount()){ + BindableLayoutContent content = mItemMap.valueAt(pos); + if(content!=null) + Binder.unbindView(getContext(), content.getInflateResult()); + removeViewAt(pos); + } } } @SuppressWarnings({ "rawtypes", "unchecked" }) - private void insertItem(int pos, Object item) { - if( layout == null ) + private void bindItem(int pos, Object item) { + if( mLayoutItem == null ) return; - int layoutId = layout.getLayoutId(); - if( layoutId < 1 && layout.getLayoutName() != null ) { + int layoutId = mLayoutItem.getLayoutId(); + if( layoutId < 1 && mLayoutItem.getLayoutName() != null ) { IObservable observable = null; - InnerFieldObservable ifo = new InnerFieldObservable(layout.getLayoutName()); + InnerFieldObservable ifo = new InnerFieldObservable(mLayoutItem.getLayoutName()); if (ifo.createNodes(item)) { observable = ifo; } else { Object rawField; try { - rawField = Binder.getSyntaxResolver().getFieldForModel(layout.getLayoutName(), item); + rawField = Binder.getSyntaxResolver().getFieldForModel(mLayoutItem.getLayoutName(), item); } catch (SyntaxResolveException e) { BindingLog.exception("BindableLinearLayout.insertItem()", e); return; @@ -300,14 +256,14 @@ else if (rawField!=null) } if( observable != null) { - observableItemsLayoutID.add(observable, item); + mObservableItemsLayoutID.add(observable, item); Object obj = observable.get(); if(obj instanceof Integer) layoutId = (Integer)obj; } } - View child = null; + View child = null; if( layoutId < 1 ) { TextView textView = new TextView(getContext()); @@ -315,14 +271,19 @@ else if (rawField!=null) textView.setTextColor(Color.RED); child = textView; } else { - Binder.InflateResult result = Binder.inflateView(getContext(), layoutId, this, false); - for(View view: result.processedViews){ + InflateResult inflateResult = Binder.inflateView(getContext(), layoutId, this, false); + + BindableLayoutContent content = new BindableLayoutContent(); + content.setInflateResult(inflateResult); + mItemMap.append(pos, content); + + for(View view: inflateResult.processedViews){ AttributeBinder.getInstance().bindView(getContext(), view, item); - } - child = result.rootView; + } + child = inflateResult.rootView; } - - this.addView(child,pos); + + addView(child,pos); } - + } diff --git a/Core/AndroidBinding/src/gueei/binding/widgets/BindableTableLayout.java b/Core/AndroidBinding/src/gueei/binding/widgets/BindableTableLayout.java index 829c923..89d9895 100644 --- a/Core/AndroidBinding/src/gueei/binding/widgets/BindableTableLayout.java +++ b/Core/AndroidBinding/src/gueei/binding/widgets/BindableTableLayout.java @@ -22,93 +22,97 @@ import gueei.binding.collections.ObservableCollection; import gueei.binding.utility.ObservableCollectionMultiplexer; import gueei.binding.utility.ObservableMultiplexer; -import gueei.binding.utility.WeakList; import gueei.binding.viewAttributes.templates.LayoutRowChild; import android.content.Context; -import android.graphics.Canvas; import android.graphics.Color; import android.util.AttributeSet; +import android.util.SparseArray; import android.view.View; import android.view.ViewGroup; import android.widget.TableLayout; import android.widget.TableRow; import android.widget.TextView; -public class BindableTableLayout extends TableLayout implements IBindableView { - private WeakList currentRowList = null; - private CollectionObserver collectionObserver = null; +public class BindableTableLayout extends TableLayout implements IBindableView, IBindableLayout { + private ArrayList mCurrentRowList = null; + private SparseArray> mItemMapList = null; + private CollectionObserver mCollectionObserver = null; - private ObservableCollection rowList = null; - private LayoutRowChild rowChild = null; - private boolean updateEnabled = true; + private ObservableCollection mRowList = null; + private LayoutRowChild mRowChild = null; - private Observer observer = new Observer() { + private Observer mObserver = new Observer() { @Override public void onPropertyChanged(IObservable prop, Collection initiators) { - if( initiators == null || currentRowList == null) + if( initiators == null || mCurrentRowList == null) return; int pos = -1; for(Object i : initiators) { - pos = currentRowList.indexOf(i); + pos = mCurrentRowList.indexOf(i); if( pos > 0) break; } if( pos < 0) return; - Object parent = currentRowList.get(pos); + Object rowData = mCurrentRowList.get(pos); ArrayList list = new ArrayList(); - list.add(parent); - removeRows(list); - insertRow(pos, parent); + list.add(rowData); + unbindRow(list); + addTablteRow(pos, rowData); } }; - private ObservableMultiplexer observableChildLayoutID = new ObservableMultiplexer(observer); - private ObservableMultiplexer observableChildSpan = new ObservableMultiplexer(observer); - private ObservableCollectionMultiplexer observableCollectionRowChildren = new ObservableCollectionMultiplexer(observer); + private ObservableMultiplexer mObservableChildLayoutID = new ObservableMultiplexer(mObserver); + private ObservableMultiplexer mObservableChildSpan = new ObservableMultiplexer(mObserver); + private ObservableCollectionMultiplexer mObservableCollectionRowChildren = new ObservableCollectionMultiplexer(mObserver); public BindableTableLayout(Context context, AttributeSet attrs) { super(context, attrs); - init(); } public BindableTableLayout(Context context) { super(context); - init(); - } + } - private void init() { + @Override + public void unbind () { + synchronized(this){ + if(mRowList != null) { + mRowList.unsubscribe(mCollectionObserver); + mCollectionObserver = null; + } + + if(mItemMapList != null && mItemMapList.size() > 0) { + for(int i = mItemMapList.size()-1; i > -1; i--) { + unbindAndRemove(i); + } + } + + mItemMapList = null; + mRowList = null; + mObservableChildLayoutID.clear(); + mObservableChildSpan.clear(); + mObservableCollectionRowChildren.clear(); + mCurrentRowList= null; + + removeAllViews(); + } } @Override protected void onDetachedFromWindow() { - if(rowList != null) { - rowList.unsubscribe(collectionObserver); - collectionObserver = null; - } - - rowList = null; - observableChildLayoutID.clear(); - observableChildSpan.clear(); - observableCollectionRowChildren.clear(); - currentRowList= null; - + unbind(); super.onDetachedFromWindow(); } - private void createItemSourceList(ObservableCollection newRowList) { - if( rowList != null && collectionObserver != null) - rowList.unsubscribe(collectionObserver); - - collectionObserver = null; - rowList = newRowList; + private void bind(ObservableCollection newRowList) { + mRowList = newRowList; if(newRowList==null) return; - - currentRowList = null; - collectionObserver = new CollectionObserver() { + + mCollectionObserver = new CollectionObserver() { @SuppressWarnings("unchecked") @Override public void onCollectionChanged( @@ -119,32 +123,19 @@ public void onCollectionChanged( } }; - rowList.subscribe(collectionObserver); - newRowList(rowList); - } - - private void newRowList(ObservableCollection rows) { - this.removeAllViews(); + mRowList.subscribe(mCollectionObserver); - observableChildLayoutID.clear(); - observableChildSpan.clear(); - observableCollectionRowChildren.clear(); - - if( rows == null) { - currentRowList= null; - return; - } + mObservableChildLayoutID.clear(); + mObservableChildSpan.clear(); + mObservableCollectionRowChildren.clear(); - currentRowList = new WeakList(); + mCurrentRowList = new ArrayList(); + mItemMapList = new SparseArray>(); - for( int pos=0; pos < rows.size(); pos ++ ) { - Object item = rows.getItem(pos); - insertRow(pos, item); - } - - for( int pos=0; pos < rows.size(); pos ++ ) { - Object item = rows.getItem(pos); - currentRowList.add(item); + for( int pos=0; pos < newRowList.size(); pos ++ ) { + Object rowData = newRowList.getItem(pos); + addTablteRow(pos, rowData); + mCurrentRowList.add(rowData); } } @@ -156,26 +147,27 @@ private void rowListChanged(CollectionChangedEventArg e, ObservableCollection )) return; - rowList = (ArrayListObservable)newValue; + mRowList = (ArrayListObservable)newValue; - if( rowChild != null ) - createItemSourceList(rowList); + if( mRowChild != null ) { + ObservableCollection list = mRowList; + unbind(); + mRowList = list; + bind(mRowList); + } } @Override public Object get() { - return rowList; + return mRowList; } }; @@ -216,93 +212,66 @@ public Object get() { new ViewAttribute(Object.class, BindableTableLayout.this, "RowChild"){ @Override protected void doSetAttributeValue(Object newValue) { - rowChild = null; + mRowChild = null; if( newValue instanceof LayoutRowChild ) { - rowChild = (LayoutRowChild) newValue; - if( rowList != null ) - createItemSourceList(rowList); + mRowChild = (LayoutRowChild) newValue; + if( mRowList != null ){ + ObservableCollection current = mRowList; + unbind(); + mRowList = current; + bind(mRowList); + } } } @Override public Object get() { - return rowChild; + return mRowChild; } }; - private ViewAttribute ItemUpdateEnabledAttribute = - new ViewAttribute(Boolean.class, BindableTableLayout.this, "UpdateEnabled"){ - @Override - protected void doSetAttributeValue(Object newValue) { - if( newValue == null ) { - updateEnabled = true; - } - else if( newValue instanceof Boolean ) { - Boolean value = (Boolean) newValue; - updateEnabled = value; - if(updateEnabled) { - BindableTableLayout.this.invalidate(); - } - } - } - - @Override - public Boolean get() { - return updateEnabled; - } - }; - - @Override - protected void onDraw(Canvas canvas) { - if( !updateEnabled ) - return; - super.onDraw(canvas); - } - - @Override - protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) { - if( !updateEnabled ) - return; - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - } @Override public ViewAttribute createViewAttribute(String attributeId) { if (attributeId.equals("itemSource")) return ItemSourceAttribute; - if (attributeId.equals("rowChild")) return RowChildAttribute; - if (attributeId.equals("updateEnabled")) return ItemUpdateEnabledAttribute; + if (attributeId.equals("rowChild")) return RowChildAttribute; return null; } - private void insertRow(int pos, Object row) { - if( rowChild == null ) - return; - - IObservable childDataSource = null; - InnerFieldObservable ifo = new InnerFieldObservable(rowChild.getChildDataSource()); - if (ifo.createNodes(row)) { - childDataSource = ifo; - } else { - Object rawField = null; - try { - rawField = Binder.getSyntaxResolver().getFieldForModel(rowChild.getChildDataSource(), row); - } catch (SyntaxResolveException e) { - BindingLog.exception("BindableTableLayout.insertRow", e); - } - if (rawField instanceof IObservable) - childDataSource = (IObservable)rawField; - } - - TableRow trow = createRow(childDataSource, pos, row); - - currentRowList.add(pos, row); - this.addView(trow,pos); + private void addTablteRow(int pos, Object rowData) { + synchronized(this){ + if( mRowChild == null ) + return; + + IObservable childDataSource = null; + InnerFieldObservable ifo = new InnerFieldObservable(mRowChild.getChildDataSource()); + if (ifo.createNodes(rowData)) { + childDataSource = ifo; + } else { + Object rawField = null; + try { + rawField = Binder.getSyntaxResolver().getFieldForModel(mRowChild.getChildDataSource(), rowData); + } catch (SyntaxResolveException e) { + BindingLog.exception("BindableTableLayout.insertRow", e); + } + if (rawField instanceof IObservable) + childDataSource = (IObservable)rawField; + } + + TableRow trow = createAndBindTableRow(childDataSource, pos, rowData); + mCurrentRowList.add(pos, rowData); + + addView(trow,pos); + } } @SuppressWarnings({ "rawtypes", "unchecked" }) - private TableRow createRow(IObservable childDataSource, int pos, Object row) { + private TableRow createAndBindTableRow(IObservable childDataSource, int pos, Object rowData) { TableRow tableRow = new TableRow(getContext()); InnerFieldObservable ifo = null; + + List list = new ArrayList(); + mItemMapList.append(pos, list); if( childDataSource == null) { TextView textView = new TextView(getContext()); @@ -316,21 +285,21 @@ private TableRow createRow(IObservable childDataSource, int pos, Object row) ArrayListObservable childItems = (ArrayListObservable)dataSource; // we might have to change the current row if the child datasource changes - observableCollectionRowChildren.add(childItems,row); + mObservableCollectionRowChildren.add(childItems,rowData); int col = 0; for( Object childItem : childItems) { int colSpan = 1; - int layoutId = rowChild.getLayoutId(); - if( layoutId < 1 && rowChild.getLayoutName() != null ) { + int layoutId = mRowChild.getLayoutId(); + if( layoutId < 1 && mRowChild.getLayoutName() != null ) { IObservable observable = null; - ifo = new InnerFieldObservable(rowChild.getLayoutName() ); + ifo = new InnerFieldObservable(mRowChild.getLayoutName() ); if (ifo.createNodes(childItem)) { observable = ifo; } else { Object rawField = null; try { - rawField = Binder.getSyntaxResolver().getFieldForModel(rowChild.getLayoutName(), childItem); + rawField = Binder.getSyntaxResolver().getFieldForModel(mRowChild.getLayoutName(), childItem); } catch (SyntaxResolveException e) { BindingLog.exception("BindableTableLayout.createRow", e); } @@ -343,7 +312,7 @@ else if (rawField!=null) if( observable != null) { Object obj = observable.get(); if(obj instanceof Integer) { - observableChildLayoutID.add(observable, row); + mObservableChildLayoutID.add(observable, rowData); layoutId = (Integer)obj; } } @@ -362,22 +331,26 @@ else if (rawField!=null) for(View view: result.processedViews){ AttributeBinder.getInstance().bindView(getContext(), view, childItem); } - child = result.rootView; + child = result.rootView; + + BindableLayoutContent content = new BindableLayoutContent(); + content.setInflateResult(result); + list.add(content); } } TableRow.LayoutParams params = null; // check if there is a colspan - if( rowChild.getColspanName() != null ) { + if( mRowChild.getColspanName() != null ) { IObservable observable = null; - ifo = new InnerFieldObservable(rowChild.getColspanName()); + ifo = new InnerFieldObservable(mRowChild.getColspanName()); if (ifo.createNodes(childItem)) { observable = ifo; } else { Object rawField = null; try { - rawField = Binder.getSyntaxResolver().getFieldForModel(rowChild.getColspanName(), childItem); + rawField = Binder.getSyntaxResolver().getFieldForModel(mRowChild.getColspanName(), childItem); } catch (SyntaxResolveException e) { BindingLog.exception("BindableTableLayout.createRow", e); } @@ -390,7 +363,7 @@ else if (rawField!=null) if( observable != null) { Object obj = observable.get(); if(obj instanceof Integer) { - observableChildSpan.add(observable, row); + mObservableChildSpan.add(observable, rowData); colSpan = (Integer)obj; } } @@ -435,22 +408,40 @@ else if (rawField!=null) return tableRow; } - private void removeRows(List deleteList) { - if( deleteList == null || deleteList.size() == 0 || currentRowList == null) - return; - - ArrayList currentPositionList = new ArrayList(Arrays.asList(currentRowList.toArray())); + private void unbindRow(List deleteList) { + synchronized(this){ + if( deleteList == null || deleteList.size() == 0 || mCurrentRowList == null) + return; + + ArrayList currentPositionList = new ArrayList(Arrays.asList(mCurrentRowList.toArray())); + + for(Object row : deleteList){ + int pos = currentPositionList.indexOf(row); + mCurrentRowList.remove(row); + mObservableChildLayoutID.removeParent(row); + mObservableChildSpan.removeParent(row); + mObservableCollectionRowChildren.removeParent(row); + currentPositionList.remove(row); + if( pos > -1 && pos < getChildCount()) { + unbindAndRemove(pos); + } + } + } + } + + private void unbindAndRemove(int pos) { + List list = mItemMapList.get(pos); - for(Object row : deleteList){ - int pos = currentPositionList.indexOf(row); - currentRowList.remove(row); - observableChildLayoutID.removeParent(row); - observableChildSpan.removeParent(row); - observableCollectionRowChildren.removeParent(row); - currentPositionList.remove(row); - if( pos > -1 && pos < this.getChildCount()) - this.removeViewAt(pos); + if(list != null) { + for(int i = 0; i < list.size(); i++) { + BindableLayoutContent content = list.get(i); + if(content==null) + continue; + Binder.unbindView(getContext(), content.getInflateResult()); + } } + + removeViewAt(pos); } } diff --git a/Core/AndroidBinding/src/gueei/binding/widgets/IBindableLayout.java b/Core/AndroidBinding/src/gueei/binding/widgets/IBindableLayout.java new file mode 100644 index 0000000..8c6493a --- /dev/null +++ b/Core/AndroidBinding/src/gueei/binding/widgets/IBindableLayout.java @@ -0,0 +1,5 @@ +package gueei.binding.widgets; + +public interface IBindableLayout { + public void unbind(); +} diff --git a/Core/AndroidBindingV30/.classpath b/Core/AndroidBindingV30/.classpath index 4fea6fe..4bd6d63 100644 --- a/Core/AndroidBindingV30/.classpath +++ b/Core/AndroidBindingV30/.classpath @@ -3,7 +3,8 @@ - + + diff --git a/Core/AndroidBindingV30/src/gueei/binding/v30/actionbar/attributes/TabNavigationAdapter.java b/Core/AndroidBindingV30/src/gueei/binding/v30/actionbar/attributes/TabNavigationAdapter.java index daad4ec..d38e479 100644 --- a/Core/AndroidBindingV30/src/gueei/binding/v30/actionbar/attributes/TabNavigationAdapter.java +++ b/Core/AndroidBindingV30/src/gueei/binding/v30/actionbar/attributes/TabNavigationAdapter.java @@ -69,6 +69,8 @@ public void rebind(ActionBar bar){ tab.setCustomView(mAdapter.getView(i, null, null)); tab.setTabListener(this); bar.addTab(tab, i); + + ActionBar ab; } } diff --git a/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/.classpath b/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/.classpath new file mode 100644 index 0000000..09d2fee --- /dev/null +++ b/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/.gitignore b/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/.gitignore new file mode 100644 index 0000000..89a135e --- /dev/null +++ b/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/.gitignore @@ -0,0 +1,3 @@ +/bin +/gen +.settings diff --git a/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/.project b/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/.project new file mode 100644 index 0000000..d834c12 --- /dev/null +++ b/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/.project @@ -0,0 +1,33 @@ + + + AndroidBinding.Plugin.BreadCrumbs.Demo + + + + + + com.android.ide.eclipse.adt.ResourceManagerBuilder + + + + + com.android.ide.eclipse.adt.PreCompilerBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + com.android.ide.eclipse.adt.ApkBuilder + + + + + + com.android.ide.eclipse.adt.AndroidNature + org.eclipse.jdt.core.javanature + + diff --git a/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/AndroidManifest.xml b/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/AndroidManifest.xml new file mode 100644 index 0000000..4eda300 --- /dev/null +++ b/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/AndroidManifest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + diff --git a/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/libs/android-support-v4.jar b/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/libs/android-support-v4.jar new file mode 100644 index 0000000..6080877 Binary files /dev/null and b/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/libs/android-support-v4.jar differ diff --git a/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/lint.xml b/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/lint.xml new file mode 100644 index 0000000..ee0eead --- /dev/null +++ b/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/lint.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/proguard-project.txt b/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/proguard-project.txt new file mode 100644 index 0000000..f2fe155 --- /dev/null +++ b/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/proguard-project.txt @@ -0,0 +1,20 @@ +# To enable ProGuard in your project, edit project.properties +# to define the proguard.config property as described in that file. +# +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in ${sdk.dir}/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the ProGuard +# include property in project.properties. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/project.properties b/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/project.properties new file mode 100644 index 0000000..17802c0 --- /dev/null +++ b/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/project.properties @@ -0,0 +1,17 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt + +# Project target. +target=android-15 +android.library.reference.1=..\\..\\Core\\AndroidBinding +android.library.reference.2=..\\..\\plugin\\AndroidBinding.Plugin.BreadCrumbs +android.library.reference.3=../../Core/AndroidBindingV30 diff --git a/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/res/drawable/ic_launcher.png b/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/res/drawable/ic_launcher.png new file mode 100644 index 0000000..5b8c63d Binary files /dev/null and b/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/res/drawable/ic_launcher.png differ diff --git a/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/res/layout/bread_crumb_item.xml b/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/res/layout/bread_crumb_item.xml new file mode 100644 index 0000000..69ca492 --- /dev/null +++ b/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/res/layout/bread_crumb_item.xml @@ -0,0 +1,15 @@ + + + + + + \ No newline at end of file diff --git a/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/res/layout/bread_crumb_item2.xml b/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/res/layout/bread_crumb_item2.xml new file mode 100644 index 0000000..00b1e9a --- /dev/null +++ b/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/res/layout/bread_crumb_item2.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/res/layout/bread_crumb_item_wrapper.xml b/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/res/layout/bread_crumb_item_wrapper.xml new file mode 100644 index 0000000..3fae81a --- /dev/null +++ b/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/res/layout/bread_crumb_item_wrapper.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/res/layout/bread_crumb_item_wrapper_blue.xml b/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/res/layout/bread_crumb_item_wrapper_blue.xml new file mode 100644 index 0000000..b4436f6 --- /dev/null +++ b/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/res/layout/bread_crumb_item_wrapper_blue.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/res/layout/main.xml b/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/res/layout/main.xml new file mode 100644 index 0000000..a5ad2de --- /dev/null +++ b/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/res/layout/main.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + diff --git a/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/res/menu/main_menu.xml b/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/res/menu/main_menu.xml new file mode 100644 index 0000000..94caee0 --- /dev/null +++ b/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/res/menu/main_menu.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/res/values-v11/styles.xml b/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/res/values-v11/styles.xml new file mode 100644 index 0000000..d408cbc --- /dev/null +++ b/Demo/AndroidBinding.Plugin.BreadCrumbs.Demo/res/values-v11/styles.xml @@ -0,0 +1,5 @@ + + +