aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/onos/core/api/src/main/java/org/onosproject/ui/table/TableModel.java
blob: d0fccb65b89f24b968be709ea6702aa440d253d8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
/*
 * Copyright 2015 Open Networking Laboratory
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.onosproject.ui.table;

import com.google.common.collect.Sets;
import org.onosproject.ui.table.cell.DefaultCellComparator;
import org.onosproject.ui.table.cell.DefaultCellFormatter;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

/**
 * A simple model of table data.
 * <p>
 * Note that this is not a full MVC type model; the expected usage pattern
 * is to create an empty table, add rows (by consulting the business model),
 * sort rows (based on client request parameters), and finally produce the
 * sorted list of rows.
 * <p>
 * The table also provides a mechanism for defining how cell values for a
 * particular column should be formatted into strings, to help facilitate
 * the encoding of the table data into a JSON structure.
 * <p>
 * Note that it is expected that all values for a particular column will
 * be the same class.
 */
public class TableModel {

    private static final CellComparator DEF_CMP = DefaultCellComparator.INSTANCE;
    private static final CellFormatter DEF_FMT = DefaultCellFormatter.INSTANCE;

    private final String[] columnIds;
    private final Set<String> idSet;
    private final Map<String, CellComparator> comparators = new HashMap<>();
    private final Map<String, CellFormatter> formatters = new HashMap<>();
    private final List<Row> rows = new ArrayList<>();


    /**
     * Constructs a table (devoid of data) with the given column IDs.
     *
     * @param columnIds column identifiers
     */
    public TableModel(String... columnIds) {
        checkNotNull(columnIds, "columnIds cannot be null");
        checkArgument(columnIds.length > 0, "must be at least one column");

        idSet = Sets.newHashSet(columnIds);
        if (idSet.size() != columnIds.length) {
            throw new IllegalArgumentException("duplicate column ID(s) detected");
        }

        this.columnIds = Arrays.copyOf(columnIds, columnIds.length);
    }

    private void checkId(String id) {
        checkNotNull(id, "must provide a column ID");
        if (!idSet.contains(id)) {
            throw new IllegalArgumentException("unknown column id: " + id);
        }
    }

    /**
     * Returns the number of rows in this table model.
     *
     * @return number of rows
     */
    public int rowCount() {
        return rows.size();
    }

    /**
     * Returns the number of columns in this table model.
     *
     * @return number of columns
     */
    public int columnCount() {
        return columnIds.length;
    }

    /**
     * Returns the array of column IDs for this table model.
     * <p>
     * Implementation note: we are knowingly passing you a reference to
     * our internal array to avoid copying. Don't mess with it. It's your
     * table you'll break if you do!
     *
     * @return the column identifiers
     */
    public String[] getColumnIds() {
        return columnIds;
    }

    /**
     * Returns the raw {@link Row} representation of the rows in this table.
     *
     * @return raw table rows
     */
    public Row[] getRows() {
        return rows.toArray(new Row[rows.size()]);
    }

    /**
     * Sets a cell comparator for the specified column.
     *
     * @param columnId column identifier
     * @param comparator comparator to use
     */
    public void setComparator(String columnId, CellComparator comparator) {
        checkNotNull(comparator, "must provide a comparator");
        checkId(columnId);
        comparators.put(columnId, comparator);
    }

    /**
     * Returns the cell comparator to use on values in the specified column.
     *
     * @param columnId column identifier
     * @return an appropriate cell comparator
     */
    private CellComparator getComparator(String columnId) {
        checkId(columnId);
        CellComparator cmp = comparators.get(columnId);
        return cmp == null ? DEF_CMP : cmp;
    }

    /**
     * Sets a cell formatter for the specified column.
     *
     * @param columnId column identifier
     * @param formatter formatter to use
     */
    public void setFormatter(String columnId, CellFormatter formatter) {
        checkNotNull(formatter, "must provide a formatter");
        checkId(columnId);
        formatters.put(columnId, formatter);
    }

    /**
     * Returns the cell formatter to use on values in the specified column.
     *
     * @param columnId column identifier
     * @return an appropriate cell formatter
     */
    public CellFormatter getFormatter(String columnId) {
        checkId(columnId);
        CellFormatter fmt = formatters.get(columnId);
        return fmt == null ? DEF_FMT : fmt;
    }

    /**
     * Adds a row to the table model.
     *
     * @return the row, for chaining
     */
    public Row addRow() {
        Row r = new Row();
        rows.add(r);
        return r;
    }

    /**
     * Sorts the table rows based on the specified column, in the
     * specified direction.
     *
     * @param columnId column identifier
     * @param dir sort direction
     */
    public void sort(String columnId, SortDir dir) {
        Collections.sort(rows, new RowComparator(columnId, dir));
    }


    /** Designates sorting direction. */
    public enum SortDir {
        /** Designates an ascending sort. */
        ASC,
        /** Designates a descending sort. */
        DESC
    }

    /**
     * Row comparator.
     */
    private class RowComparator implements Comparator<Row> {
        private final String columnId;
        private final SortDir dir;
        private final CellComparator cellComparator;

        /**
         * Constructs a row comparator based on the specified
         * column identifier and sort direction.
         *
         * @param columnId column identifier
         * @param dir sort direction
         */
        public RowComparator(String columnId, SortDir dir) {
            this.columnId = columnId;
            this.dir = dir;
            cellComparator = getComparator(columnId);
        }

        @Override
        public int compare(Row a, Row b) {
            Object cellA = a.get(columnId);
            Object cellB = b.get(columnId);
            int result = cellComparator.compare(cellA, cellB);
            return dir == SortDir.ASC ? result : -result;
        }
    }

    /**
     * Model of a row.
     */
    public class Row {
        private final Map<String, Object> cells = new HashMap<>();

        /**
         * Sets the cell value for the given column of this row.
         *
         * @param columnId column identifier
         * @param value value to set
         * @return self, for chaining
         */
        public Row cell(String columnId, Object value) {
            checkId(columnId);
            cells.put(columnId, value);
            return this;
        }

        /**
         * Returns the value of the cell in the given column for this row.
         *
         * @param columnId column identifier
         * @return cell value
         */
        public Object get(String columnId) {
            return cells.get(columnId);
        }

        /**
         * Returns the value of the cell as a string, using the
         * formatter appropriate for the column.
         *
         * @param columnId column identifier
         * @return formatted cell value
         */
        String getAsString(String columnId) {
            return getFormatter(columnId).format(get(columnId));
        }

        /**
         * Returns the row as an array of formatted strings.
         *
         * @return the formatted row data
         */
        public String[] getAsFormattedStrings() {
            List<String> formatted = new ArrayList<>(columnCount());
            for (String c : columnIds) {
                formatted.add(getAsString(c));
            }
            return formatted.toArray(new String[formatted.size()]);
        }
    }

    private static final String DESC = "desc";

    /**
     * Returns the appropriate sort direction for the given string.
     * <p>
     * The expected strings are "asc" for {@link SortDir#ASC ascending} and
     * "desc" for {@link SortDir#DESC descending}. Any other value will
     * default to ascending.
     *
     * @param s sort direction string encoding
     * @return sort direction
     */
    public static SortDir sortDir(String s) {
        return !DESC.equals(s) ? SortDir.ASC : SortDir.DESC;
    }
}