Package org.jboss.errai.otec.client.atomizer

Source Code of org.jboss.errai.otec.client.atomizer.Atomizer

/*
* Copyright 2013 JBoss, by Red Hat, Inc
*
* 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.jboss.errai.otec.client.atomizer;


import java.util.Collection;

import org.jboss.errai.otec.client.EntityStreamRegistration;
import org.jboss.errai.otec.client.ListenerRegistration;
import org.jboss.errai.otec.client.OTEngine;
import org.jboss.errai.otec.client.OTEntity;
import org.jboss.errai.otec.client.StateChangeListener;
import org.jboss.errai.otec.client.util.DiffUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.dom.client.KeyEvent;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.EventListener;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.ValueBoxBase;

/**
* @author Mike Brock
* @author Christian Sadilek
*/
public abstract class Atomizer {
 
  private static final Logger logger = LoggerFactory.getLogger(Atomizer.class);
 
  private Atomizer() {
  }

  private static boolean NO_PROPAGATE_STATE_CHANGE = false;

  public static AtomizerSession syncWidgetWith(final OTEngine engine, final OTEntity entity, final ValueBoxBase widget) {
    logger.info("NEW ATOMIZER SESSION (engine:" + engine.getId() + ", widget=" + widget + ")");

    final Multimap<Object, HandlerRegistration> HANDLER_REGISTRATION_MAP
        = HashMultimap.create();
    final EntityChangeStreamImpl entityChangeStream = new EntityChangeStreamImpl(engine, entity);

    final EntityStreamRegistration entityStreamRegistration
        = engine.getPeerState().addEntityStream(entityChangeStream);

    widget.setValue(entity.getState().get());

    HANDLER_REGISTRATION_MAP.put(widget, widget.addKeyDownHandler(new KeyDownHandler() {
      @Override
      public void onKeyDown(final KeyDownEvent event) {
        if (shouldIgnoreKeyPress(event)) {
          return;
        }

        if (widget.getSelectedText().length() > 0) {
          stopEvents();
          entityChangeStream.notifyDelete(widget.getCursorPos(), widget.getSelectedText());
          startEvents();
        }
        else if (event.getNativeKeyCode() == KeyCodes.KEY_BACKSPACE) {
          stopEvents();
          final int index = widget.getCursorPos() - 1;
          entityChangeStream.notifyDelete(index, " ");
          startEvents();
        }
        else if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
          stopEvents();
          entityChangeStream.notifyInsert(widget.getCursorPos(), "\n");
          startEvents();
        }
      }
    }));

    HANDLER_REGISTRATION_MAP.put(widget, widget.addKeyPressHandler(new KeyPressHandler() {
      @Override
      public void onKeyPress(final KeyPressEvent event) {
        if (event.getUnicodeCharCode() != 13 && event.getUnicodeCharCode() != 0) {
          stopEvents();
          entityChangeStream.notifyInsert(widget.getCursorPos(), String.valueOf(event.getCharCode()));
          startEvents();
        }
      }
    }));

    DOM.setEventListener(widget.getElement(), new EventListener() {
      @Override
      public void onBrowserEvent(Event event) {
        if (event.getTypeInt() == Event.ONPASTE) {
          final String before = (String) entity.getState().get();
          new Timer() {
            @Override
            public void run() {
              final String after = (String) widget.getValue();
              final DiffUtil.Delta diff = DiffUtil.diff(before, after);

              stopEvents();
              entityChangeStream.notifyInsert(diff.getCursor(), diff.getDeltaText());
              startEvents();
            }
          }.schedule(1);
        }
        widget.onBrowserEvent(event);
      }
    });

    attachCutHandler(widget.getElement(), new Runnable() {
      @Override
      public void run() {
        stopEvents();
        entityChangeStream.notifyDelete(widget.getCursorPos(), widget.getSelectedText());
        startEvents();
      }
    });

    attachTextDragHandler(widget.getElement(), new Runnable() {
          @Override
          public void run() {
            stopEvents();
            entityChangeStream.notifyDelete(widget.getCursorPos(), widget.getSelectedText());
            entityChangeStream.flush();
            startEvents();
          }
        },
        new Runnable() {
          @Override
          public void run() {
            final String old = (String) entity.getState().get();
            new Timer() {
              @Override
              public void run() {
                final DiffUtil.Delta diff = DiffUtil.diff(old, (String) widget.getValue());
                if (diff.getDeltaText().length() > 0) {
                  stopEvents();
                  entityChangeStream.notifyInsert(diff.getCursor(), diff.getDeltaText());
                  startEvents();
                }
              }
            }.schedule(1);
          }
        }
    );

    final ListenerRegistration listenerRegistration
        = entity.getState().addStateChangeListener(new StateChangeListener() {
      @Override
      public int getCursorPos() {
        return widget.getCursorPos();
      }

      @Override
      public void onStateChange(final int newCursorPos, final Object newValue) {
        if (NO_PROPAGATE_STATE_CHANGE) {
          return;
        }

        widget.setValue(newValue, false);
        widget.setCursorPos(newCursorPos);
      }
    });

    DOM.sinkEvents(widget.getElement(), DOM.getEventsSunk(widget.getElement()) | Event.ONPASTE);

    final Timer timer = new Timer() {
      @Override
      public void run() {
        entityChangeStream.flush();
      }
    };
    timer.scheduleRepeating(500);

    return new AtomizerSession() {
      @Override
      public void end() {
        entityChangeStream.close();
        timer.cancel();

        logger.info("END ATOMIZER SESSION");
        entityStreamRegistration.remove();
        listenerRegistration.remove();
        final Collection<HandlerRegistration> values = HANDLER_REGISTRATION_MAP.values();
        for (final HandlerRegistration value : values) {
          value.removeHandler();
        }
      }
    };
  }

  private static boolean shouldIgnoreKeyPress(KeyEvent event) {
    if (event.isMetaKeyDown() || event.isControlKeyDown()) {
      return true;
    }

    int keyCode;
    if (event instanceof KeyDownEvent) {
      keyCode = ((KeyDownEvent) event).getNativeKeyCode();
    }
    else {
      return true;
    }

    switch (keyCode) {
      case KeyCodes.KEY_DOWN:
      case KeyCodes.KEY_LEFT:
      case KeyCodes.KEY_UP:
      case KeyCodes.KEY_RIGHT:
      case KeyCodes.KEY_ESCAPE:
      case KeyCodes.KEY_PAGEDOWN:
      case KeyCodes.KEY_PAGEUP:
      case KeyCodes.KEY_HOME:
      case KeyCodes.KEY_END:
        return true;
    }

    return false;
  }

  public static void stopEvents() {
    NO_PROPAGATE_STATE_CHANGE = true;
  }

  public static void startEvents() {
    NO_PROPAGATE_STATE_CHANGE = false;
  }

  private static native void attachCutHandler(Element element, Runnable runnable) /*-{
      element.oncut = function () {
          runnable.@java.lang.Runnable::run()();
          return true;
      }
  }-*/;

  private static native void attachTextDragHandler(Element element, Runnable onStart, Runnable onFinish) /*-{

      element.ondragstart = function () {
          onStart.@java.lang.Runnable::run()();
          return true;
      }


      element.ondragend = function () {
          onFinish.@java.lang.Runnable::run()();
          return true;
      }


  }-*/;

TOP

Related Classes of org.jboss.errai.otec.client.atomizer.Atomizer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.