Package com.habitsoft.kiyaa.views

Source Code of com.habitsoft.kiyaa.views.CustomPopup

package com.habitsoft.kiyaa.views;

import java.util.ArrayList;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.ChangeListener;
import com.google.gwt.user.client.ui.ChangeListenerCollection;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.PopupListener;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.UIObject;
import com.google.gwt.user.client.ui.Widget;
import com.habitsoft.kiyaa.metamodel.Action;
import com.habitsoft.kiyaa.metamodel.ActionSeries;
import com.habitsoft.kiyaa.metamodel.Value;
import com.habitsoft.kiyaa.util.AsyncCallbackDirectProxy;
import com.habitsoft.kiyaa.util.AsyncCallbackFactory;
import com.habitsoft.kiyaa.util.AsyncCallbackProxy;
import com.habitsoft.kiyaa.util.ModelFilter;
import com.habitsoft.kiyaa.util.ToStringNameValueAdapter;
import com.habitsoft.kiyaa.util.Name;

public class CustomPopup<T> implements PopupListener {

   
    protected final PopupPanel popup = new PopupPanel(true);
    protected final ScrollPanel container = new ScrollPanel();
    protected final FlowPanel flow = new FlowPanel();
    protected BaseCollectionView<T> table;
    private ArrayList<Action> actions = new ArrayList<Action>();
    private ArrayList<Action> visibleActions = new ArrayList<Action>();
    private ActionSeries actionTests;
    protected T selectedModel;
    private ChangeListenerCollection changeListeners = new ChangeListenerCollection();
    //if the optional field is set to false it acts more like a list box (ie. you are unable to enter custom text)
    protected boolean optional = true;
    private T[] models;
    private Value<T[]> modelsValue;
    private ArrayList<ViewFactory<ModelView<T>>> columns = new ArrayList<ViewFactory<ModelView<T>>>();
    private View emptyContent;
    protected boolean selectable = true;
    protected boolean clickable = false;
    private Timer filterOperation = new Timer() {
        @Override
        public void run() {
          applyFilter(true);
        }
      };
    protected boolean popupShowing = false;
    protected boolean applyDefaultFilter = true;
    public final ModelFilter<T> NOOP_FILTER = new ModelFilter<T>() {
        public boolean includes(T model) {
            return true;
        }
    };
    private ModelFilter<T> defaultFilter = NOOP_FILTER;
    private Timer hidePopupOperation = new Timer() {
        @Override
        public void run() {
            //GWT.log("hidePopupOperation.run", null);
          hidePopup();
        }
      };
    protected Anchor removeFilterActionLabel;

   
    /**
     * A subclass can override this to disable the popup in some
     * circumstances - for example, if there's nothing to show in the
     * popup!
     *
     * @return true if the popup should be shown
     */
    protected boolean shouldShowPopup() {
      return (models != null && models.length > 0) || !visibleActions.isEmpty();
    }

    /**
     * If shouldShowPopup(), and the popup is not showing, show the popup.
     *
     * If not shouldShowPopup, hide the popup if it is showing.
     *
     * It's acceptable to pass null for the callback, if there's no follow-up operation
     * pending which depends on the pop-up being shown.
     */
    protected void showPopup(AsyncCallback<Void> callback, final int left, final int top) {
      try {
          if(shouldShowPopup()) {
              if(!popupShowing) {
                    popupShowing = true;
                if(table == null) {
                  createTableView(new AsyncCallbackDirectProxy<Void>(callback) {
                    @Override
                    public void onSuccess(Void arg0) {
                      if(table == null) throw new NullPointerException();
                      showPopupImpl(left, top);
                      returnSuccess(null);
                    }
                  });
                } else {
                        showPopupImpl(left, top);
                    if(callback != null)
                      callback.onSuccess(null);
                }
              } else {
                    if(callback != null)
                        callback.onSuccess(null);
              }
            } else {
                hidePopup();
                if(callback != null)
                    callback.onSuccess(null);
            }
      } catch(Throwable caught) {
        if(callback != null)
          callback.onFailure(caught);
        else caught.printStackTrace();
      }
    }

    private void showPopupImpl(final int left, final int top) {
        hidePopupOperation.cancel();
        popupShowing = true;
        popup.setPopupPosition(left, top);
        popup.show();
        ensureSelectedIndexIsVisible();
    }

    /**
     * Show the popup at the current mouse position.  Assumes a mouse event
     * is currently being processed.
     */
    protected void showPopup(AsyncCallback<Void> callback) {
        Event event = Event.getCurrentEvent();
        showPopup(callback, event.getClientX()+Window.getScrollLeft(), event.getClientY()+Window.getScrollTop());
    }
   
    protected ViewFactory<ModelView<T>> getDefaultViewFactory() {
        return new NameViewFactory<T>(ToStringNameValueAdapter.<T>getInstance());
    }
   
    protected void createTableView(AsyncCallback<Void> callback) {
      if(columns.isEmpty()) {
        ListView<T> list = new ListView<T>();
        list.setViewFactory(getDefaultViewFactory());
        list.setEmptyContent(emptyContent);
        //table.addColumn(new NameViewFactory<T>(nameValueAdapter));
        table = list;
      } else if(columns.size() == 1) {
        ListView<T> list = new ListView<T>();
        list.setViewFactory(columns.get(0));
        list.setEmptyContent(emptyContent);
        table = list;
      } else {
        TableView<T> t = new TableView<T>();
        for(ViewFactory column: columns) {
          t.addColumn(column);
        }
        t.setEmptyContent(emptyContent);
        table = t;
      }
      // Defer adding the table to the DOM until after it's loaded
      callback = new AsyncCallbackDirectProxy<Void>(callback) {
        @Override
        public void onSuccess(Void result) {
          if(table != null) // Amazingly, the table could be set to null before we get here
            flow.insert(table.getViewWidget(), 0);
          super.onSuccess(result);
        }
      };
      table.addClickListener(new ClickListener() {
        public void onClick(Widget sender) {
            //GWT.log("Table clicked, enqueueHidePopup(10)", null);
          enqueueHidePopup(10);
          onTableClick();
        }
      });
      table.setSelectable(selectable);
      table.setClickable(clickable);
      if(models != null) {
        updateModelsInTable();
      }
      //GWT.log("loading table in custom popup.createTableView()", null);
      table.load(callback);
    }
   
    protected void onTableClick(){
     
    }

    public void hidePopup() {
      if(popupShowing) {
        //GWT.log("Hide popup "+this, new Exception());
        table.getHoverGroup().setActive(null);
        popup.hide();
        popupShowing = false;
      }
    }

    protected void enqueueHidePopup(int delay) {
      //GWT.log("Enqueue hide popup "+this+" after "+delay, new Exception());
      hidePopupOperation.schedule(delay);
    }

    protected void cancelPendingHidePopup() {
        hidePopupOperation.cancel();
    }
   
    public void clearFields() {
      selectedModel = null;
      if(table != null) {
        table.getViewWidget().removeFromParent();
        table = null;
      }
    }

    public void addPopupListener(PopupListener listener) {
      popup.addPopupListener(listener);
    }

    public void removePopupListener(PopupListener listener) {
      popup.removePopupListener(listener);
    }

    public native boolean isIE() /*-{
        return /msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent);
    }-*/;
   
    public void setPopupHeight(String height) {       
        // Also setup a scroll bar, assuming that the height is being limited
        DOM.setStyleAttribute(container.getElement(), "overflowX", "hidden");
        DOM.setStyleAttribute(container.getElement(), "overflowY", "scroll");
        if(isIE()) // HACK for IE's broken way of doing layout with scroll bars
            DOM.setStyleAttribute(container.getElement(), "paddingRight", "20px");
      popup.setHeight(height);
    }

    public void setPopupWidth(String width) {
      popup.setWidth(width);
    }

    public void setPopupClass(String styleClass) {
      popup.setStylePrimaryName(styleClass);
    }

    public T[] getModels() {
      return models;
    }

    protected void modelsChanged(T[] models) {
       
    }
    public void setModels(final T[] models) {
      if(this.models == models) {
        return;
      }
      this.models = models;
      if(table != null) {
        updateModelsInTable();
      }
        modelsChanged(models);
    }

    private void updateModelsInTable() {
      applyFilter(false);
        table.setModels(models);
    }

    public void addChangeListener(ChangeListener listener) {
      changeListeners.add(listener);
    }

    public void removeChangeListener(ChangeListener listener) {
      changeListeners.remove(listener);
    }

    @Name("action")
    public void addAction(@Name("label") final String label, @Name("action") final Action action) {
      addAction(label, action, null);
    }

    @Name("action")
    public void addAction(@Name("label") String label, @Name("action") Action action, @Name("test") Value<Boolean> test) {
      addAction(label, action, test, true);
    }

    /**
     * Add an action to the menu.
     *
     * @param label
     * @param action
     * @param test If non-null, the action will only show when the value is true
     */
    public Anchor addAction(@Name("label") final String label, @Name("action") final Action action, @Name("test") final Value<Boolean> test, @Name("hideOnClick") final boolean hideOnClick) {
      final Anchor widget = new Anchor();
      widget.setText(label);
      widget.setStyleName("action");
      flow.add(widget);
      actions.add(action);
        //GWT.log("Action added ..."+label, null);
      widget.addClickListener(new ClickListener() {
        public void onClick(Widget sender) {
                //GWT.log("Action clicked ..."+label, null);
          if(hideOnClick)
            hidePopup();
          action.perform(AsyncCallbackFactory.<Void>defaultNewInstance());
        }
      });
      if(test != null) {
        if(actionTests == null) actionTests = new ActionSeries();
        actionTests.add(new Action() {
          @Override
          public void perform(AsyncCallback<Void> callback) {
            test.getValue(new AsyncCallbackProxy<Boolean,Void>(callback) {
              @Override
              public void onSuccess(Boolean result) {
                  if(widget.isVisible() != result)
                      widget.setVisible(result);
                  if(result && !visibleActions.contains(action))
                      visibleActions.add(action);
                  else if(!result && visibleActions.contains(action))
                      visibleActions.remove(action);
                returnSuccess(null);
              }
            });
          }
        });
      } else visibleActions.add(action);
      return widget;
    }

    protected Anchor restoreFilterActionLabel;

    public void onPopupClosed(PopupPanel sender, boolean autoClosed) {
        popupShowing = false;
    }

    public CustomPopup() {
        popup.addPopupListener(this);
        popup.setStylePrimaryName("ui-dropdown");
        popup.setWidget(container);
        container.setWidget(flow);
    }

    @Name("removeFilterAction")
    public void addRemoveFilterAction(@Name("removeLabel") String removeLabel, @Name("restoreLabel") String restoreLabel) {
      if(removeFilterActionLabel != null) {
        removeFilterActionLabel.setText(removeLabel);
      } else {
        removeFilterActionLabel = addAction(removeLabel, new Action() {
          @Override
          public void perform(AsyncCallback<Void> callback) {
            applyDefaultFilter = false;
            if(restoreFilterActionLabel != null)
                restoreFilterActionLabel.setVisible(true);
            removeFilterActionLabel.setVisible(false);
            applyFilter(true);
            callback.onSuccess(null);
          }
        }, new Value<Boolean>() {
          public void getValue(AsyncCallback<Boolean> callback) {
            callback.onSuccess(applyDefaultFilter);
          }
          public void setValue(Boolean newValue, AsyncCallback<Void> callback) {
            applyDefaultFilter = ((Boolean)newValue).booleanValue();
                    applyFilter(true);
            callback.onSuccess(null);
          }
        }, false);
      }
      if(restoreFilterActionLabel != null) {
        restoreFilterActionLabel.setText(restoreLabel);
      } else {
        restoreFilterActionLabel = addAction(restoreLabel, new Action() {
          @Override
          public void perform(AsyncCallback<Void> callback) {
            applyDefaultFilter = true;
                    if(removeFilterActionLabel != null)
                        removeFilterActionLabel.setVisible(true);
                    restoreFilterActionLabel.setVisible(false);
            applyFilter(true);
            callback.onSuccess(null);
          }
        }, new Value<Boolean>() {
          public void getValue(AsyncCallback<Boolean> callback) {
            callback.onSuccess(!applyDefaultFilter);
          }
          public void setValue(Boolean newValue, AsyncCallback<Void> callback) {
            applyDefaultFilter = !((Boolean)newValue).booleanValue();
            applyFilter(true);
            callback.onSuccess(null);
          }
        }, false);
      }
    }

    @Name("column")
    public void addColumn(ViewFactory<ModelView<T>> viewFactory) {
        if(viewFactory == null) throw new NullPointerException("viewFactory");
      columns.add(viewFactory);
      if(table != null) {
        if(table instanceof TableView<?>)
          ((TableView<T>)table).addColumn(viewFactory);
        else
          createTableView(AsyncCallbackFactory.<Void>defaultNewInstance());
      }
    }

    public T getSelectedModel() {
      return selectedModel;
    }

    protected void ensureSelectedIndexIsVisible() {
      if(table.getSelectedIndex() >= && table.getRowCount() > 0) {
        final UIObject rowUIObject = table.getRowUIObject(table.getSelectedIndex());
        if(rowUIObject != null)
            container.ensureVisible(rowUIObject);
            // TODO Ensure that the part of the container which has the ui object is also visible.  #584
      }
    }

    protected void sendChangeEvent() {
      changeListeners.fireChange(null);
    }

    protected void enqueueApplyFilter() {
      // Calling schedule will re-schedule the timer; any pending event is cancelled first,
      // then the timer will run after 250ms.  Basically we want to only run the timer after
      // the user stops typing for a little bit.
      filterOperation.schedule(250);
    }

    public ModelFilter<T> getDefaultFilter() {
      return defaultFilter;
    }

    public void setDefaultFilter(ModelFilter<T> defaultFilter) {
      this.defaultFilter = defaultFilter;
    }

    public void load(AsyncCallback<Void> callback) {
      if(actionTests != null)
        callback = actionTests.performOnSuccess(callback);
     
      if(modelsValue != null) {
          modelsValue.getValue(new AsyncCallbackProxy<T[],Void>(callback) {
              @Override
                public void onSuccess(T[] result) {
                  setModels(result);
                  //if(table != null) GWT.log("loading table in custom popup.load() (async models)", null);
                  loadTable(takeCallback());
              }
          });
      } else {
          loadTable(callback);
      }
    }

    private void loadTable(AsyncCallback<Void> callback) {
        if(table != null) {
        table.load(callback);
      } else {
        createTableView(callback);
      }
    }

    public void save(AsyncCallback<Void> callback) {
      if(table != null) {
        table.save(callback);       
      } else {
        callback.onSuccess(null);
      }
    }

    public boolean isOptional() {
      return optional;
    }

    public void setOptional(boolean optional) {
      this.optional = optional;
    }

    public View getEmptyContent() {
      return emptyContent;
    }

    public void setEmptyContent(View emptyContent) {
      this.emptyContent = emptyContent;
    }

    protected boolean isFiltered() {
        return false;
    }
   
    protected ModelFilter<T> getFilter() {
        return null;
    }

    protected void applyFilter(final boolean loadTable) {
        // Don't apply the filter if we haven't created the table
        if(table == null)
            return;
        //GWT.log("Filtering...", null);
        AsyncCallback<Void> callback =
            new AsyncCallback<Void>() {
            public void onSuccess(Void result) {
                if(loadTable) {
                    //GWT.log("Loading table in applyFilter()", null);
                    loadTable(AsyncCallbackFactory.<Void>defaultNewInstance());
                }
            }
            public void onFailure(Throwable caught) {
                GWT.log("Filter operation failed", caught);
            }
        };
        if(isFiltered()) {
            table.setFilter(getFilter(), callback);
        } else {
            table.setFilter(applyDefaultFilter?defaultFilter:NOOP_FILTER, callback);
        }
    }

    public boolean isPopupShowing() {
        return popupShowing;
    }

    public void setPopupShowing(boolean popupShowing) {
        this.popupShowing = popupShowing;
    }

    public void setModelsValue(Value<T[]> models) {
        modelsValue = models;
    }

    public boolean isSelectable() {
        return selectable;
    }

    public void setSelectable(boolean selectable) {
        this.selectable = selectable;
        if(table != null)
            table.setSelectable(selectable);
    }

    public boolean isClickable() {
        return clickable;
    }

    public void setClickable(boolean clickable) {
        this.clickable = clickable;
        if(table != null)
            table.setClickable(clickable);
    }

   
}
TOP

Related Classes of com.habitsoft.kiyaa.views.CustomPopup

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.