Package com.daikit.daikit4gxt.client.editor

Source Code of com.daikit.daikit4gxt.client.editor.DkPreFlushVisitor

/**
* Copyright (C) 2013 DaiKit.com - daikit4gxt module (admin@daikit.com)
*
*         Project home : http://code.daikit.com/daikit4gxt
*
* 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 com.daikit.daikit4gxt.client.editor;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.daikit.commons.shared.bean.AbstractDkModifiableBeanWithId;
import com.daikit.commons.shared.utils.DkObjectUtils;
import com.google.gwt.editor.client.EditorContext;
import com.google.gwt.editor.client.EditorVisitor;
import com.google.gwt.editor.client.HasEditorDelegate;
import com.google.gwt.editor.client.LeafValueEditor;
import com.sencha.gxt.data.client.editor.ListStoreEditor;
import com.sencha.gxt.data.shared.ListStore;


/**
* {@link EditorVisitor} permitting to update {@link AbstractEditedBeanAwareEditor} dirty status and
* {@link AbstractDkModifiableBeanWithId} dirty status, dirty paths and deletedChildrenIds
*
* @author tcaselli
* @author rdupuis
* @version $Revision$ Last modifier: $Author$ Last commit: $Date$
*/
@SuppressWarnings("rawtypes")
public class DkPreFlushVisitor extends EditorVisitor
{
  private boolean updateModel = false;

  /**
   * Constructor
   *
   * @param updateModelDirtyStatus
   *           false by default
   */
  public DkPreFlushVisitor(final boolean updateModelDirtyStatus)
  {
    this.updateModel = updateModelDirtyStatus;
  }

  private final List<AbstractEditedBeanAwareEditor> stack = new ArrayList<AbstractEditedBeanAwareEditor>();

  @Override
  public <T extends Object> boolean visit(final com.google.gwt.editor.client.EditorContext<T> ctx)
  {
    if (ctx.getEditor() instanceof AbstractEditedBeanAwareEditor)
    {
      stack.add((AbstractEditedBeanAwareEditor<T>) ctx.getEditor());
    }
    return true;
  };

  @Override
  public <T> void endVisit(final EditorContext<T> ctx)
  {
    if (customVisit(ctx))
    {
      visitLeaf(ctx);
      visitListRemovableEditor(ctx);
      visitListStoreEditor(ctx);
      visitTreeStoreEditor(ctx);
    }
    if (ctx.getEditor() instanceof AbstractEditedBeanAwareEditor)
    {
      if (!stack.isEmpty())
      {
        stack.remove(stack.size() - 1);
      }
    }
  }

  /**
   * To be overridden to provide custom visitor
   *
   * @param ctx
   *           the {@link EditorContext}
   * @return whether to apply other visitors or not. (Return true by default, and should return false if your custom
   *         implementation was effectively taking into account the given context)
   */
  protected <T> boolean customVisit(final EditorContext<T> ctx)
  {
    return true;
  }

  /**
   * Compare model value to editor value. if they are not the same all ancestor editor will be flagged as dirty.
   * Moreover the direct AbstractModifiableBeanWithId parent to the leaf editor will be updated. After being updated
   * the parent will contain the leafEditor attribute name.
   *
   * @param ctx
   */
  private <T> void visitLeaf(final EditorContext<T> ctx)
  {
    final LeafValueEditor<T> editor = ctx.asLeafValueEditor();
    if (editor != null)
    {
      final T modelValue = ctx.getFromModel();
      final T newValue = editor.getValue();

      if (!DkObjectUtils.equalsWithNull(modelValue, newValue))
      {
        final AbstractEditedBeanAwareEditor<T> parent = getParent();
        if (parent != null)
        {
          // iterate through parents starting from the oldest
          updateIterativelyDirtyStatusAndPath(ctx.getEditorDelegate().getPath());
        }
      }
    }
  }

  /**
   * If a ListStoreRemovableEditor is visited this method will update ancestor editor with dirty flag. It will also
   * populate the direct parent editor with the current editor attributeName and the list of removed items id.
   *
   * @param ctx
   */
  @SuppressWarnings("unchecked")
  private <T> void visitListRemovableEditor(final EditorContext<T> ctx)
  {
    final HasEditorDelegate<T> listEditor = ctx.asHasEditorDelegate();
    if (listEditor instanceof ListStoreRemovableEditor)
    {
      final List<T> removedItems = ((ListStoreRemovableEditor<T>) listEditor).getRemovedItems();
      if (removedItems != null && !removedItems.isEmpty())
      {
        // iterate through parent editors starting from the oldest
        updateIterativelyDirtyStatusAndPath(ctx.getEditorDelegate().getPath());
        // updated removed ids
        final AbstractEditedBeanAwareEditor<T> parent = getParent();
        if (parent != null && updateModel && parent.getEditedModel() instanceof AbstractDkModifiableBeanWithId)
        {
          final Set<String> removedIds = new HashSet<String>();
          for (final T item : removedItems)
          {
            if (item instanceof AbstractDkModifiableBeanWithId)
            {
              removedIds.add(((AbstractDkModifiableBeanWithId) item).getId());
            }
          }
          ((AbstractDkModifiableBeanWithId) parent.getEditedModel()).getDeletedChildrenIds().put(
              getLastAttributePath(ctx.getEditorDelegate().getPath()), removedIds);
        }
      }
    }
  }

  /**
   * Visit child {@link ListStoreEditor}
   *
   * @param ctx
   */
  @SuppressWarnings("unchecked")
  private <T> void visitListStoreEditor(final EditorContext<T> ctx)
  {
    final HasEditorDelegate<T> editor = ctx.asHasEditorDelegate();
    if (editor instanceof ListStoreEditor || editor instanceof ListStoreRemovableEditor)
    {
      boolean isDirty = false;
      if (editor instanceof ListStoreRemovableEditor)
      {
        final ListStoreRemovableEditor<T> removableEditor = (ListStoreRemovableEditor<T>) editor;
        if (removableEditor.getOriginalModels().size() != removableEditor.getStore().getAll().size())
        {
          isDirty = true;
        }
        else
        {
          final List<T> storeList = removableEditor.getStore().getAll();
          for (final T model : removableEditor.getOriginalModels())
          {
            if (!storeList.contains(model))
            {
              isDirty = true;
              break;
            }
          }
        }
      }
      if (!isDirty)
      {
        final ListStore<T> listStore = editor instanceof ListStoreEditor ? ((ListStoreEditor<T>) editor).getStore()
            : ((ListStoreRemovableEditor<T>) editor).getStore();

        for (final T listElement : listStore.getAll())
        {
          if (listElement instanceof AbstractDkModifiableBeanWithId
              && ((AbstractDkModifiableBeanWithId) listElement).isDirty())
          {
            isDirty = true;
            break;
          }
        }
      }
      if (isDirty)
      {
        updateIterativelyDirtyStatusAndPath(ctx.getEditorDelegate().getPath());
      }
    }
  }

  /**
   * Visit child {@link TreeStoreEditor}
   *
   * @param ctx
   */
  private <T> void visitTreeStoreEditor(final EditorContext<T> ctx)
  {
    final HasEditorDelegate<T> editor = ctx.asHasEditorDelegate();
    if (editor instanceof TreeStoreEditor)
    {
      final TreeStoreEditor treeStoreEditor = (TreeStoreEditor) editor;
      boolean isDirty = false;
      for (final Object listElement : treeStoreEditor.getStore().getAll())
      {
        if (listElement instanceof AbstractDkModifiableBeanWithId && ((AbstractDkModifiableBeanWithId) listElement).isDirty())
        {
          isDirty = true;
          break;
        }
      }
      if (isDirty)
      {
        updateIterativelyDirtyStatusAndPath(ctx.getEditorDelegate().getPath());
      }
    }
  }

  // *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
  // UTILITY METHODS
  // *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-

  /**
   *
   * @param contextDelegatePath
   *           the current context delegate path
   */
  protected void updateIterativelyDirtyStatusAndPath(final String contextDelegatePath)
  {
    // iterate through parent editors starting from the oldest
    for (int i = 0; i < stack.size(); i++)
    {
      final AbstractEditedBeanAwareEditor ancestor = stack.get(i);
      ancestor.setDirty(true);
      if (updateModel && ancestor.getEditedModel() instanceof AbstractDkModifiableBeanWithId)
      {
        final AbstractDkModifiableBeanWithId data = (AbstractDkModifiableBeanWithId) ancestor.getEditedModel();
        data.setDirty(true);
        if (i == stack.size() - 1)
        {
          // update status in bean
          data.getDirtyPaths().add(getLastAttributePath(contextDelegatePath));
        }
        else
        {
          final AbstractEditedBeanAwareEditor childAncestor = stack.get(i + 1);
          data.getDirtyPaths().add(getLastAttributePath(childAncestor.getDelegate().getPath()));
        }
      }
    }
  }

  private String getLastAttributePath(final String absolutePath)
  {
    return absolutePath.substring(absolutePath.lastIndexOf(".") + 1);
  }


  @SuppressWarnings("unchecked")
  private <T> AbstractEditedBeanAwareEditor<T> getParent()
  {
    return stack.isEmpty() ? null : stack.get(stack.size() - 1);
  }
}
TOP

Related Classes of com.daikit.daikit4gxt.client.editor.DkPreFlushVisitor

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.