# HG changeset patch # User Jaroslav Tulach # Date 1361188981 -3600 # Node ID ade90921ede5aa6aec72bf6e51a5ee961512770f # Parent 4bd6f3bc6c64819788561c14b8d2a02f50192ec6 Changes in String array are properly notified diff -r 4bd6f3bc6c64 -r ade90921ede5 javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/KOList.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/KOList.java Mon Feb 18 13:03:01 2013 +0100 @@ -0,0 +1,107 @@ +/** + * Back 2 Browser Bytecode Translator + * Copyright (C) 2012 Jaroslav Tulach + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. Look for COPYING file in the top folder. + * If not, see http://opensource.org/licenses/GPL-2.0. + */ +package org.apidesign.bck2brwsr.htmlpage; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * + * @author Jaroslav Tulach + */ +public final class KOList extends ArrayList { + private final String name; + private final String[] deps; + private Knockout model; + + public KOList(String name, String... deps) { + this.name = name; + this.deps = deps; + } + + public void assign(Knockout model) { + this.model = model; + } + + @Override + public boolean add(T e) { + boolean ret = super.add(e); + notifyChange(); + return ret; + } + + @Override + public boolean remove(Object o) { + boolean ret = super.remove(o); + notifyChange(); + return ret; + } + + @Override + public void clear() { + super.clear(); + notifyChange(); + } + + @Override + public boolean removeAll(Collection c) { + boolean ret = super.removeAll(c); + notifyChange(); + return ret; + } + + @Override + public boolean retainAll(Collection c) { + boolean ret = super.retainAll(c); + notifyChange(); + return ret; + } + + @Override + public T set(int index, T element) { + T ret = super.set(index, element); + notifyChange(); + return ret; + } + + @Override + public void add(int index, T element) { + super.add(index, element); + notifyChange(); + } + + @Override + public T remove(int index) { + T ret = super.remove(index); + notifyChange(); + return ret; + } + + private void notifyChange() { + Knockout m = model; + if (m == null) { + return; + } + m.valueHasMutated(name); + for (String dependant : deps) { + m.valueHasMutated(dependant); + } + } + + +} diff -r 4bd6f3bc6c64 -r ade90921ede5 javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java --- a/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java Mon Feb 18 12:26:16 2013 +0100 +++ b/javaquery/api/src/main/java/org/apidesign/bck2brwsr/htmlpage/PageProcessor.java Mon Feb 18 13:03:01 2013 +0100 @@ -97,6 +97,7 @@ try { w.append("package " + pkg + ";\n"); w.append("import org.apidesign.bck2brwsr.htmlpage.api.*;\n"); + w.append("import org.apidesign.bck2brwsr.htmlpage.KOList;\n"); w.append("final class ").append(className).append(" {\n"); w.append(" private boolean locked;\n"); if (!initializeOnClick(className, (TypeElement) e, w, pp)) { @@ -320,9 +321,21 @@ String[] gs = toGetSet(p.name(), tn, p.array()); if (p.array()) { - w.write("private java.util.List<" + tn + "> prop_" + p.name() + " = new java.util.ArrayList<" + tn + ">();\n"); + w.write("private KOList<" + tn + "> prop_" + p.name() + " = new KOList<" + tn + ">(\"" + + p.name() + "\""); + final Collection dependants = deps.get(p.name()); + if (dependants != null) { + for (String depProp : dependants) { + w.write(", "); + w.write('\"'); + w.write(depProp); + w.write('\"'); + } + } + w.write(");\n"); w.write("public java.util.List<" + tn + "> " + gs[0] + "() {\n"); w.write(" if (locked) throw new IllegalStateException();\n"); + w.write(" prop_" + p.name() + ".assign(ko);\n"); w.write(" return prop_" + p.name() + ";\n"); w.write("}\n"); } else { diff -r 4bd6f3bc6c64 -r ade90921ede5 javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ModelTest.java --- a/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ModelTest.java Mon Feb 18 12:26:16 2013 +0100 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ModelTest.java Mon Feb 18 13:03:01 2013 +0100 @@ -18,7 +18,9 @@ package org.apidesign.bck2brwsr.htmlpage; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; +import java.util.ListIterator; import org.apidesign.bck2brwsr.htmlpage.api.ComputedProperty; import org.apidesign.bck2brwsr.htmlpage.api.Page; import org.apidesign.bck2brwsr.htmlpage.api.Property; @@ -60,6 +62,35 @@ assertEquals(model.getNames().size(), 1, "One element"); } + @Test public void arrayChangesNotified() { + MockKnockout my = new MockKnockout(); + MockKnockout.next = my; + + model.applyBindings(); + + model.getNames().add("Hello"); + + assertFalse(my.mutated.isEmpty(), "There was a change" + my.mutated); + assertTrue(my.mutated.contains("names"), "Change in names property: " + my.mutated); + + my.mutated.clear(); + + Iterator it = model.getNames().iterator(); + assertEquals(it.next(), "Hello"); + it.remove(); + + assertFalse(my.mutated.isEmpty(), "There was a change" + my.mutated); + assertTrue(my.mutated.contains("names"), "Change in names property: " + my.mutated); + + my.mutated.clear(); + + ListIterator lit = model.getNames().listIterator(); + lit.add("Jarda"); + + assertFalse(my.mutated.isEmpty(), "There was a change" + my.mutated); + assertTrue(my.mutated.contains("names"), "Change in names property: " + my.mutated); + } + @Test public void derivedPropertiesAreNotified() { MockKnockout my = new MockKnockout(); MockKnockout.next = my;