1f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka/*
2f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka * Copyright (C) 2014 The Android Open Source Project
3f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka *
4f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License");
5f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka * you may not use this file except in compliance with the License.
6f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka * You may obtain a copy of the License at
7f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka *
8f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka *      http://www.apache.org/licenses/LICENSE-2.0
9f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka *
10f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software
11f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS,
12f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka * See the License for the specific language governing permissions and
14f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka * limitations under the License.
15f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka */
16f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka
17f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaokapackage com.android.inputmethod.keyboard.layout.expected;
18f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka
19f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaokaimport java.util.Arrays;
20f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka
21f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka/**
22f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka * This class builds a keyboard that is a two dimensional array of elements <code>E</code>.
23f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka *
24e6f467c0fe694d93b7f000fcca509587014fb7e8Tadashi G. Takaoka * A keyboard consists of an array of rows, and a row consists of an array of elements. Each row
25e6f467c0fe694d93b7f000fcca509587014fb7e8Tadashi G. Takaoka * may have different number of elements. A element of a keyboard can be specified by a row number
26e6f467c0fe694d93b7f000fcca509587014fb7e8Tadashi G. Takaoka * and a column number, both numbers starts from 1.
27f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka *
28f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka * @param <E> the type of a keyboard element. A keyboard element must be an immutable object.
29f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka */
30f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaokaabstract class AbstractKeyboardBuilder<E> {
31f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka    // A building array of rows.
32cd15cfdaaba7f361f4744bd3ff51ce6cdae1e608Tadashi G. Takaoka    private E[][] mRows;
33f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka
34f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka    // Returns an instance of default element.
35f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka    abstract E defaultElement();
36f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka    // Returns an <code>E</code> array instance of the <code>size</code>.
37f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka    abstract E[] newArray(final int size);
38f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka    // Returns an <code>E[]</code> array instance of the <code>size</code>.
39f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka    abstract E[][] newArrayOfArray(final int size);
40f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka
41f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka    /**
42e6f467c0fe694d93b7f000fcca509587014fb7e8Tadashi G. Takaoka     * Construct an empty builder.
43f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka     */
44cd15cfdaaba7f361f4744bd3ff51ce6cdae1e608Tadashi G. Takaoka    AbstractKeyboardBuilder() {
45cd15cfdaaba7f361f4744bd3ff51ce6cdae1e608Tadashi G. Takaoka        mRows = newArrayOfArray(0);
46f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka    }
47f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka
48f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka    /**
49f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka     * Construct a builder from template keyboard. This builder has the same dimensions and
50f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka     * elements of <code>rows</rows>.
51f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka     * @param rows the template keyboard rows. The elements of the <code>rows</code> will be
52f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka     *        shared with this builder. Therefore a element must be an immutable object.
53f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka     */
54f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka    AbstractKeyboardBuilder(final E[][] rows) {
55f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka        mRows = newArrayOfArray(rows.length);
56f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka        for (int rowIndex = 0; rowIndex < rows.length; rowIndex++) {
57f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka            final E[] row = rows[rowIndex];
58f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka            mRows[rowIndex] = Arrays.copyOf(row, row.length);
59f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka        }
60f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka    }
61f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka
62f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka    /**
63f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka     * Return current constructing keyboard.
64f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka     * @return the array of the array of the element being constructed.
65f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka     */
66f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka    E[][] build() {
67f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka        return mRows;
68f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka    }
69f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka
70f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka    /**
71f247b171ce98fd35f1f8de7e3d7f8f35099cf6feTadashi G. Takaoka     * Return the number of rows.
72f247b171ce98fd35f1f8de7e3d7f8f35099cf6feTadashi G. Takaoka     * @return the number of rows being constructed.
73f247b171ce98fd35f1f8de7e3d7f8f35099cf6feTadashi G. Takaoka     */
74f247b171ce98fd35f1f8de7e3d7f8f35099cf6feTadashi G. Takaoka    int getRowCount() {
75f247b171ce98fd35f1f8de7e3d7f8f35099cf6feTadashi G. Takaoka        return mRows.length;
76f247b171ce98fd35f1f8de7e3d7f8f35099cf6feTadashi G. Takaoka    }
77f247b171ce98fd35f1f8de7e3d7f8f35099cf6feTadashi G. Takaoka
78f247b171ce98fd35f1f8de7e3d7f8f35099cf6feTadashi G. Takaoka    /**
79f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka     * Get the current contents of the specified row.
80f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka     * @param row the row number to get the contents.
81f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka     * @return the array of elements at row number <code>row</code>.
82e6f467c0fe694d93b7f000fcca509587014fb7e8Tadashi G. Takaoka     * @throws RuntimeException if <code>row</code> is illegal.
83f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka     */
84f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka    E[] getRowAt(final int row) {
85f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka        final int rowIndex = row - 1;
86f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka        if (rowIndex < 0 || rowIndex >= mRows.length) {
87f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka            throw new RuntimeException("Illegal row number: " + row);
88f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka        }
89f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka        return mRows[rowIndex];
90f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka    }
91f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka
92f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka    /**
93f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka     * Set an array of elements to the specified row.
94f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka     * @param row the row number to set <code>elements</code>.
95f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka     * @param elements the array of elements to set at row number <code>row</code>.
96e6f467c0fe694d93b7f000fcca509587014fb7e8Tadashi G. Takaoka     * @throws RuntimeException if <code>row</code> is illegal.
97f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka     */
98f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka    void setRowAt(final int row, final E[] elements) {
99f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka        final int rowIndex = row - 1;
100cd15cfdaaba7f361f4744bd3ff51ce6cdae1e608Tadashi G. Takaoka        if (rowIndex < 0) {
101f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka            throw new RuntimeException("Illegal row number: " + row);
102f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka        }
103cd15cfdaaba7f361f4744bd3ff51ce6cdae1e608Tadashi G. Takaoka        final E[][] newRows = (rowIndex < mRows.length) ? mRows
104cd15cfdaaba7f361f4744bd3ff51ce6cdae1e608Tadashi G. Takaoka                : Arrays.copyOf(mRows, rowIndex + 1);
105cd15cfdaaba7f361f4744bd3ff51ce6cdae1e608Tadashi G. Takaoka        newRows[rowIndex] = elements;
106cd15cfdaaba7f361f4744bd3ff51ce6cdae1e608Tadashi G. Takaoka        mRows = newRows;
107f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka    }
108f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka
109f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka    /**
110f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka     * Set or insert an element at specified position.
111f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka     * @param row the row number to set or insert the <code>element</code>.
112f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka     * @param column the column number to set or insert the <code>element</code>.
113f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka     * @param element the element to set or insert at <code>row,column</code>.
114f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka     * @param insert if true, the <code>element</code> is inserted at <code>row,column</code>.
115f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka     *        Otherwise the <code>element</code> replace the element at <code>row,column</code>.
116e6f467c0fe694d93b7f000fcca509587014fb7e8Tadashi G. Takaoka     * @throws RuntimeException if <code>row</code> or <code>column</code> is illegal.
117f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka     */
118f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka    void setElementAt(final int row, final int column, final E element, final boolean insert) {
119f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka        final E[] elements = getRowAt(row);
120f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka        final int columnIndex = column - 1;
121cd15cfdaaba7f361f4744bd3ff51ce6cdae1e608Tadashi G. Takaoka        if (columnIndex < 0) {
122cd15cfdaaba7f361f4744bd3ff51ce6cdae1e608Tadashi G. Takaoka            throw new RuntimeException("Illegal column number: " + column);
123cd15cfdaaba7f361f4744bd3ff51ce6cdae1e608Tadashi G. Takaoka        }
124f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka        if (insert) {
125cd15cfdaaba7f361f4744bd3ff51ce6cdae1e608Tadashi G. Takaoka            if (columnIndex >= elements.length + 1) {
126f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka                throw new RuntimeException("Illegal column number: " + column);
127f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka            }
128f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka            final E[] newElements = Arrays.copyOf(elements, elements.length + 1);
129f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka            // Shift the remaining elements.
130f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka            System.arraycopy(newElements, columnIndex, newElements, columnIndex + 1,
131f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka                    elements.length - columnIndex);
132f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka            // Insert the element at <code>row,column</code>.
133f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka            newElements[columnIndex] = element;
134f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka            // Replace the current row with one.
135f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka            setRowAt(row, newElements);
136f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka            return;
137f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka        }
138cd15cfdaaba7f361f4744bd3ff51ce6cdae1e608Tadashi G. Takaoka        final E[] newElements  = (columnIndex < elements.length) ? elements
139cd15cfdaaba7f361f4744bd3ff51ce6cdae1e608Tadashi G. Takaoka                : Arrays.copyOf(elements, columnIndex + 1);
140cd15cfdaaba7f361f4744bd3ff51ce6cdae1e608Tadashi G. Takaoka        newElements[columnIndex] = element;
141cd15cfdaaba7f361f4744bd3ff51ce6cdae1e608Tadashi G. Takaoka        setRowAt(row, newElements);
142f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka    }
143f7c84f35c73081c9d7606378e5d91a759e7aae42Tadashi G. Takaoka}
144