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