SelectionManager.java revision c3afc99304e4d6ada6eaaaa0a1513e408ecca6eb
1package autotest.common.table;
2
3import autotest.common.JSONArrayList;
4import autotest.common.Utils;
5import autotest.common.table.DataSource.DataCallback;
6
7import com.google.gwt.json.client.JSONArray;
8import com.google.gwt.json.client.JSONObject;
9
10import java.util.AbstractSet;
11import java.util.ArrayList;
12import java.util.Collection;
13import java.util.HashMap;
14import java.util.Iterator;
15import java.util.List;
16import java.util.Map;
17import java.util.Set;
18
19public class SelectionManager {
20    protected Set<JSONObject> selectedObjects = new JSONValueSet<JSONObject>();
21    protected boolean selectOnlyOne = false;
22    protected DynamicTable attachedTable;
23    protected List<SelectionListener> listeners =
24        new ArrayList<SelectionListener>();
25
26    public interface SelectionListener {
27        public void onAdd(Collection<JSONObject> objects);
28        public void onRemove(Collection<JSONObject> objects);
29    }
30
31
32    /**
33     * Set that hashes JSONObjects by their ID, so that identical objects get
34     * matched together.
35     */
36    static class JSONValueSet<T extends JSONObject> extends AbstractSet<T> {
37        protected Map<String, T> backingMap = new HashMap<String, T>();
38
39        protected String getKey(Object obj) {
40            return ((JSONObject) obj).get("id").toString();
41        }
42
43        @Override
44        public boolean add(T arg0) {
45            return backingMap.put(getKey(arg0), arg0) == null;
46        }
47
48        @Override
49        public Iterator<T> iterator() {
50            return backingMap.values().iterator();
51        }
52
53        @Override
54        public boolean remove(Object arg0) {
55            return backingMap.remove(getKey(arg0)) != null;
56        }
57
58        @Override
59        public boolean contains(Object o) {
60            return backingMap.containsKey(getKey(o));
61        }
62
63        @Override
64        public int size() {
65            return backingMap.size();
66        }
67    }
68
69    public SelectionManager(DynamicTable table, boolean selectOnlyOne) {
70        attachedTable = table;
71        this.selectOnlyOne = selectOnlyOne;
72    }
73
74    public void refreshSelection() {
75        for (int i = 0; i < attachedTable.getRowCount(); i++) {
76            if (selectedObjects.contains(attachedTable.getRow(i)))
77                attachedTable.highlightRow(i);
78            else
79                attachedTable.unhighlightRow(i);
80        }
81    }
82
83    public void selectObject(JSONObject object) {
84        selectObjects(Utils.wrapObjectWithList(object));
85    }
86
87    public void selectObjects(Collection<? extends JSONObject> objects) {
88        if (selectOnlyOne) {
89            assert objects.size() == 1;
90            deselectAll();
91        }
92        addOrRemoveObjects(objects, true);
93    }
94
95    public void deselectObject(JSONObject object) {
96        deselectObjects(Utils.wrapObjectWithList(object));
97    }
98
99    public void deselectObjects(Collection<JSONObject> objects) {
100        addOrRemoveObjects(objects, false);
101    }
102
103    protected void addOrRemoveObjects(Collection<? extends JSONObject> objects,
104                                      boolean add) {
105        List<JSONObject> actuallyUsed = new ArrayList<JSONObject>();
106        for (JSONObject object : objects) {
107            boolean used = false;
108            if (add)
109                used = selectedObjects.add(object);
110            else
111                used = selectedObjects.remove(object);
112            if (used)
113                actuallyUsed.add(object);
114        }
115        notifyListeners(actuallyUsed, add);
116    }
117
118    /*
119     * Select all objects covering all pages, not just the currently displayed page in the table.
120     */
121    public void selectAll() {
122        DataSource dataSource = attachedTable.getDataSource();
123        dataSource.getPage(null, null, null, new DataCallback() {
124            public void handlePage(JSONArray data) {
125                selectObjects(new JSONArrayList<JSONObject>(data));
126            }
127
128            public void onGotData(int totalCount) {}
129        });
130    }
131
132    public void deselectAll() {
133        List<JSONObject> removed = new ArrayList<JSONObject>(selectedObjects);
134        selectedObjects.clear();
135        notifyListeners(removed, false);
136    }
137
138    public void selectVisible() {
139        List<JSONObject> rowsToAdd = new ArrayList<JSONObject>();
140        for (int i = 0; i < attachedTable.getRowCount(); i++) {
141            rowsToAdd.add(attachedTable.getRow(i));
142        }
143        selectObjects(rowsToAdd);
144    }
145
146    public void toggleSelected(JSONObject object) {
147        if (selectedObjects.contains(object))
148            deselectObject(object);
149        else
150            selectObject(object);
151    }
152
153    public JSONObject getSelectedOne() {
154        assert selectOnlyOne;
155        if (selectedObjects.isEmpty())
156            return null;
157        return selectedObjects.iterator().next();
158    }
159
160    public Set<JSONObject> getSelectedObjects() {
161        // TODO: return a copy or an unmodifiable view
162        return selectedObjects;
163    }
164
165    public boolean isEmpty() {
166        return selectedObjects.isEmpty();
167    }
168
169    public void addListener(SelectionListener listener) {
170        listeners.add(listener);
171    }
172
173    public void removeListener(SelectionListener listener) {
174        listeners.remove(listener);
175    }
176
177    protected void notifyListeners(JSONObject object, boolean add) {
178        List<JSONObject> objectList = new ArrayList<JSONObject>();
179        objectList.add(object);
180        notifyListeners(objectList, add);
181    }
182
183    protected void notifyListeners(Collection<JSONObject> objects,
184                                   boolean add) {
185        for (SelectionListener listener : listeners) {
186            if (add)
187                listener.onAdd(objects);
188            else
189                listener.onRemove(objects);
190        }
191    }
192}
193