org.zanata.webtrans.client.editor.table.InlineTargetCellEditor.java Source code

Java tutorial

Introduction

Here is the source code for org.zanata.webtrans.client.editor.table.InlineTargetCellEditor.java

Source

/*
 * Copyright 2010, Red Hat, Inc. and individual contributors as indicated by the
 * @author tags. See the copyright.txt file in the distribution for a full
 * listing of individual contributors.
 * 
 * This is free software; you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This software is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this software; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF
 * site: http://www.fsf.org.
 */
package org.zanata.webtrans.client.editor.table;

import org.zanata.common.ContentState;
import org.zanata.webtrans.client.action.UndoableTransUnitUpdateAction;
import org.zanata.webtrans.shared.model.TransUnit;

import com.allen_sauer.gwt.log.client.Log;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.FocusHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.gen2.table.client.CellEditor;
import com.google.gwt.gen2.table.client.InlineCellEditor.InlineCellEditorImages;
import com.google.gwt.gen2.table.override.client.HTMLTable;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.PushButton;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.Widget;

public class InlineTargetCellEditor implements CellEditor<TransUnit> {

    /**
     * An {@link ImageBundle} that provides images for
     * {@link InlineTargetCellEditor}.
     */
    public static interface TargetCellEditorImages extends InlineCellEditorImages {

    }

    /**
     * Default style name.
     */
    public static final String DEFAULT_STYLENAME = "gwt-TargetCellEditor";

    /**
     * The click listener used to clone.
     */
    private ClickHandler cloneHandler = new ClickHandler() {
        public void onClick(ClickEvent event) {
            textArea.setText(cellValue.getSource());
            textArea.setFocus(true);
            Log.info("InlineTargetCellEditor.java: Clone action.");
        }
    };

    /**
     * The click listener used to clone and save.
     */
    private ClickHandler cloneAndSaveHandler = new ClickHandler() {
        public void onClick(ClickEvent event) {
            cloneHandler.onClick(null);
            acceptHandler.onClick(null);
            Log.info(
                    "InlineTargetCellEditor.java: Clone-and-save action (The last clone action is called by this action).");
        }
    };

    /**
     * The click listener used to cancel.
     */
    private ClickHandler cancelHandler = new ClickHandler() {
        public void onClick(ClickEvent event) {
            cancelEdit();
        }
    };

    private final CheckBox toggleFuzzy;

    /**
     * The click listener used to accept.
     */
    private ClickHandler acceptHandler = new ClickHandler() {
        public void onClick(ClickEvent event) {
            acceptEdit();
            gotoNextRow(curRow);
        }
    };

    /**
     * The current {@link CellEditor.Callback}.
     */
    private Callback<TransUnit> curCallback = null;

    private CancelCallback<TransUnit> cancelCallback = null;

    private EditRowCallback editRowCallback = null;

    private UndoCallback<TransUnit> undoCallback = null;

    /**
     * The current {@link CellEditor.CellEditInfo}.
     */
    private CellEditInfo curCellEditInfo = null;

    /**
     * The main grid used for layout.
     */
    private FlowPanel layoutTable;

    private Widget cellViewWidget;

    private TransUnit cellValue;

    private final TextArea textArea;

    private boolean isFocused = false;

    // private Image stateImage;

    private int curRow;
    private int curCol;
    private HTMLTable table;

    /*
     * The minimum height of the target editor
     */
    private static final int MIN_HEIGHT = 48;

    /**
     * Construct a new {@link InlineTargetCellEditor}.
     * 
     * @param content the {@link Widget} used to edit
     */
    public InlineTargetCellEditor(final NavigationMessages messages, CancelCallback<TransUnit> callback,
            EditRowCallback tranValueCallback, UndoCallback<TransUnit> undoCallback) {
        this(messages, GWT.<TargetCellEditorImages>create(TargetCellEditorImages.class), callback,
                tranValueCallback, undoCallback);
    }

    /**
     * Construct a new {@link InlineTargetCellEditor} with the specified images.
     * 
     * @param content the {@link Widget} used to edit
     * @param images the images to use for the accept/cancel buttons
     */
    public InlineTargetCellEditor(final NavigationMessages messages, TargetCellEditorImages images,
            CancelCallback<TransUnit> callback, EditRowCallback rowCallback,
            UndoCallback<TransUnit> undoTransCallback) {
        // Wrap contents in a table
        layoutTable = new FlowPanel();

        cancelCallback = callback;
        editRowCallback = rowCallback;
        undoCallback = undoTransCallback;
        textArea = new TextArea();
        textArea.setStyleName("TableEditorContent-Edit");
        textArea.addBlurHandler(new BlurHandler() {
            @Override
            public void onBlur(BlurEvent event) {
                isFocused = false;
            }

        });
        textArea.addFocusHandler(new FocusHandler() {

            @Override
            public void onFocus(FocusEvent event) {
                isFocused = true;
            }

        });
        textArea.addKeyUpHandler(new KeyUpHandler() {
            @Override
            public void onKeyUp(KeyUpEvent event) {
                // NB: if you change these, please change NavigationConsts too!
                if (event.isControlKeyDown() && event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
                    acceptEdit();
                    gotoNextRow(curRow);
                } else if (event.getNativeKeyCode() == KeyCodes.KEY_ESCAPE) {
                    cancelEdit();
                }
                // else if (event.isControlKeyDown() && event.isShiftKeyDown() &&
                // event.getNativeKeyCode() == KeyCodes.KEY_PAGEDOWN)
                // { // was alt-e
                // handleNextState(ContentState.NeedReview);
                // }
                // else if (event.isControlKeyDown() && event.isShiftKeyDown() &&
                // event.getNativeKeyCode() == KeyCodes.KEY_PAGEUP)
                // { // was alt-m
                // handlePrevState(ContentState.NeedReview);
                // // } else if(event.isControlKeyDown() && event.getNativeKeyCode()
                // // == KeyCodes.KEY_PAGEDOWN) { // bad in Firefox
                // }
                else if (event.isAltKeyDown() && event.isDownArrow()) {
                    handleNext();
                    // } else if(event.isControlKeyDown() && event.getNativeKeyCode()
                    // == KeyCodes.KEY_PAGEUP) { // bad in Firefox
                } else if (event.isAltKeyDown() && event.isUpArrow()) {
                    handlePrev();
                } else if (event.isAltKeyDown() && event.getNativeKeyCode() == KeyCodes.KEY_PAGEDOWN) { // alt-pagedown
                    handleNextState();
                } else if (event.isAltKeyDown() && event.getNativeKeyCode() == KeyCodes.KEY_PAGEUP) { // alt-pageup
                    handlePrevState();
                }
                // these shortcuts disabled because they conflict with basic text editing:
                //            else if (event.isControlKeyDown() && event.getNativeKeyCode() == KeyCodes.KEY_HOME)
                //            { // ctrl-home
                //               cloneHandler.onClick(null);
                //            }
                //            else if (event.isControlKeyDown() && event.getNativeKeyCode() == KeyCodes.KEY_END)
                //            { // ctrl-end
                //               cloneAndSaveHandler.onClick(null);
                //            }
            }

        });
        layoutTable.add(textArea);

        HorizontalPanel operationsPanel = new HorizontalPanel();
        operationsPanel.addStyleName("float-right-div");
        operationsPanel.setSpacing(4);
        layoutTable.add(operationsPanel);

        // icon as the current state of the unit
        // stateImage = new Image(resources.newUnit());
        // operationsPanel.add(stateImage);

        // Add content widget
        toggleFuzzy = new CheckBox(messages.fuzzy());
        operationsPanel.add(toggleFuzzy);

        PushButton cloneButton = new PushButton(new Image(), cloneHandler);
        cloneButton.setText(messages.editClone());
        cloneButton.setTitle(messages.editCloneShortcut());
        operationsPanel.add(cloneButton);

        PushButton cloneAndSaveButton = new PushButton(new Image(), cloneAndSaveHandler);
        cloneAndSaveButton.setText(messages.editCloneAndSave());
        cloneAndSaveButton.setTitle(messages.editCloneAndSaveShortcut());
        operationsPanel.add(cloneAndSaveButton);

        PushButton cancelButton = new PushButton(images.cellEditorCancel().createImage(), cancelHandler);
        cancelButton.setText(messages.editCancel());
        cancelButton.setTitle(messages.editCancelShortcut());
        operationsPanel.add(cancelButton);

        PushButton acceptButton = new PushButton(images.cellEditorAccept().createImage(), acceptHandler);
        acceptButton.setText(messages.editSave());
        acceptButton.setTitle(messages.editSaveShortcut());
        operationsPanel.add(acceptButton);
    }

    private void gotoNextRow(int row) {
        editRowCallback.gotoNextRow(row);
    }

    private void gotoPrevRow(int row) {
        editRowCallback.gotoPrevRow(row);
    }

    private void gotoNextFuzzy(int row) {
        editRowCallback.gotoNextFuzzy(row);
    }

    private void gotoPrevFuzzy(int row) {
        editRowCallback.gotoPrevFuzzy(row);
    }

    private void restoreView() {
        if (curCellEditInfo != null && cellViewWidget != null) {
            curCellEditInfo.getTable().setWidget(curRow, curCol, cellViewWidget);
            cellViewWidget.getParent().setHeight(cellViewWidget.getOffsetHeight() + "px");
        }
    }

    private boolean isDirty() {
        if (cellValue == null)
            return false;
        return !textArea.getText().equals(cellValue.getTarget());
    }

    public boolean isEditing() {
        return cellValue != null;
    }

    public boolean isFocused() {
        return isFocused;
    }

    public void setText(String text) {
        if (isEditing()) {
            textArea.setText(text);
        }
    }

    public void editCell(CellEditInfo cellEditInfo, TransUnit cellValue, Callback<TransUnit> callback) {

        // don't allow edits of two cells at once
        if (isDirty()) {
            callback.onCancel(cellEditInfo);
            return;
        }

        if (isEditing()) {
            if (cellEditInfo.getCellIndex() == curCol && cellEditInfo.getRowIndex() == curRow) {
                return;
            }
            restoreView();
        }

        Log.debug("starting edit of cell");

        // Save the current values
        curCallback = callback;
        curCellEditInfo = cellEditInfo;

        // Get the info about the cell
        table = curCellEditInfo.getTable();

        curRow = curCellEditInfo.getRowIndex();
        curCol = curCellEditInfo.getCellIndex();

        cellViewWidget = table.getWidget(curRow, curCol);

        int height = table.getWidget(curRow, curCol - 1).getOffsetHeight();

        int realHeight = height > MIN_HEIGHT ? height : MIN_HEIGHT;

        textArea.setHeight(realHeight + "px");

        int width = table.getWidget(curRow, curCol - 1).getOffsetWidth() - 10;
        textArea.setWidth(width + "px");

        table.setWidget(curRow, curCol, layoutTable);
        textArea.setText(cellValue.getTarget());

        this.cellValue = cellValue;
        textArea.setFocus(true);
        DOM.scrollIntoView(textArea.getElement());
        toggleFuzzy.setValue(cellValue.getStatus() == ContentState.NeedReview);
        // refreshStateImage();
    }

    // private void refreshStateImage()
    // {
    // if (cellValue.getStatus() == ContentState.New)
    // stateImage.setUrl(resources.newUnit().getURL());
    // else if (cellValue.getStatus() == ContentState.NeedReview)
    // stateImage.setUrl(resources.fuzzyUnit().getURL());
    // else if (cellValue.getStatus() == ContentState.Approved)
    // stateImage.setUrl(resources.approvedUnit().getURL());
    // }

    /**
     * Accept the contents of the cell editor as the new cell value.
     */
    protected void acceptEdit() {
        // Check if we are ready to accept
        if (!onAccept()) {
            return;
        }
        TransUnit pre = new TransUnit(cellValue);
        cellValue.setTarget(textArea.getText());
        if (cellValue.getTarget().isEmpty())
            cellValue.setStatus(ContentState.New);
        else
            cellValue.setStatus(toggleFuzzy.getValue() ? ContentState.NeedReview : ContentState.Approved);
        restoreView();
        TransUnit cur = new TransUnit(cellValue);

        // Send the new cell value to the callback
        curCallback.onComplete(curCellEditInfo, cellValue);
        int curpage = this.undoCallback.getCurrentPage();
        UndoableTransUnitUpdateAction undoAction = new UndoableTransUnitUpdateAction(pre, cur, curRow, curpage);
        this.undoCallback.onUndo(undoAction);
        clearSelection();
    }

    public void clearSelection() {
        curCallback = null;
        curCellEditInfo = null;
        cellViewWidget = null;
        cellValue = null;
    }

    /**
     * Cancel the cell edit.
     */
    protected void cancelEdit() {
        // Fire the event
        if (!onCancel()) {
            return;
        }

        restoreView();

        // Call the callback
        if (curCallback != null) {
            // curCallback.onCancel(curCellEditInfo);
            cancelCallback.onCancel(cellValue);
        }

        clearSelection();
    }

    /**
     * Called before an accept takes place.
     * 
     * @return true to allow the accept, false to prevent it
     */
    protected boolean onAccept() {
        return true;
    }

    /**
     * Called before a cancel takes place.
     * 
     * @return true to allow the cancel, false to prevent it
     */
    protected boolean onCancel() {
        return true;
    }

    public void handleNext() {
        gotoNextRow(curRow);
    }

    public void handlePrev() {
        gotoPrevRow(curRow);
    }

    public void handleNextState() {
        gotoNextFuzzy(curRow);
    }

    public void handlePrevState() {
        gotoPrevFuzzy(curRow);
    }

}