001package gwt.material.design.client.base;
002
003/*
004 * #%L
005 * GwtMaterial
006 * %%
007 * Copyright (C) 2015 GwtMaterialDesign
008 * %%
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 * 
013 *      http://www.apache.org/licenses/LICENSE-2.0
014 * 
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 * #L%
021 */
022
023import com.google.gwt.cell.client.AbstractEditableCell;
024import com.google.gwt.cell.client.ValueUpdater;
025import com.google.gwt.dom.client.BrowserEvents;
026import com.google.gwt.dom.client.Document;
027import com.google.gwt.dom.client.Element;
028import com.google.gwt.dom.client.InputElement;
029import com.google.gwt.dom.client.NativeEvent;
030import com.google.gwt.event.dom.client.KeyCodes;
031import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
032import com.google.gwt.safehtml.shared.SafeHtmlUtils;
033
034public class MaterialCheckBoxCell extends AbstractEditableCell<Boolean, Boolean> {
035
036    private final boolean dependsOnSelection;
037    private final boolean handlesSelection;
038
039    public MaterialCheckBoxCell() {
040        this(false);
041    }
042
043    @Deprecated
044    public MaterialCheckBoxCell(boolean isSelectBox) {
045        this(isSelectBox, isSelectBox);
046    }
047
048    public MaterialCheckBoxCell(boolean dependsOnSelection, boolean handlesSelection) {
049        super(BrowserEvents.CHANGE, BrowserEvents.KEYDOWN, BrowserEvents.CLICK);
050        this.dependsOnSelection = dependsOnSelection;
051        this.handlesSelection = handlesSelection;
052    }
053
054    @Override
055    public boolean dependsOnSelection() {
056        return dependsOnSelection;
057    }
058
059    @Override
060    public boolean handlesSelection() {
061        return handlesSelection;
062    }
063
064    @Override
065    public boolean isEditing(Context context, Element parent, Boolean value) {
066        // A checkbox is never in "edit mode". There is no intermediate state
067        // between checked and unchecked.
068        return false;
069    }
070
071    @Override
072    public void onBrowserEvent(Context context, Element parent, Boolean value, NativeEvent event, ValueUpdater<Boolean> valueUpdater) {
073        String type = event.getType();
074
075        boolean enterPressed = (BrowserEvents.KEYDOWN.equals(type) && event.getKeyCode() == KeyCodes.KEY_ENTER)
076            || event.getType().equals(BrowserEvents.CLICK);
077
078        if (BrowserEvents.CHANGE.equals(type) || enterPressed) {
079            InputElement input = parent.getFirstChild().getFirstChild().cast();
080            Boolean isChecked = input.isChecked();
081
082            /*
083             * Toggle the value if the enter key was pressed and the cell handles selection or doesn't depend on selection. If the cell depends on selection but doesn't handle selection, then ignore
084             * the enter key and let the SelectionEventManager determine which keys will trigger a change.
085             */
086            if (enterPressed && (handlesSelection() || !dependsOnSelection())) {
087                isChecked = !isChecked;
088                input.setChecked(isChecked);
089            }
090
091            /*
092             * Save the new value. However, if the cell depends on the selection, then do not save the value because we can get into an inconsistent state.
093             */
094            if (value != isChecked && !dependsOnSelection()) {
095                setViewData(context.getKey(), isChecked);
096            } else {
097                clearViewData(context.getKey());
098            }
099
100            if (valueUpdater != null) {
101                valueUpdater.update(isChecked);
102            }
103        }
104    }
105
106    @Override
107    public void render(Context context, Boolean value, SafeHtmlBuilder sb) {
108        Object key = context.getKey();
109        Boolean viewData = getViewData(key);
110        if (viewData != null && viewData.equals(value)) {
111            clearViewData(key);
112            viewData = null;
113        }
114
115        String state = "";
116        if (value != null && ((viewData != null) ? viewData : value)) {
117            state = "checked";
118        }
119        String id = Document.get().createUniqueId();
120
121        sb.append(SafeHtmlUtils.fromSafeConstant(
122            "<span class=\"gwt-CheckBox\">" +
123                "<input type=\"checkbox\" class=\"filled-in\" tabindex=\"-1\" value=\"on\" id=\"" + id + "\" " + state + "/>" +
124                "<label for=\"" + id + "\"></label>" +
125            "</span>"));
126
127    }
128}