/******************************************************************************
* Copyright (C) 2013 Fabio Zadrozny
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Fabio Zadrozny <fabiofz@gmail.com> - initial API and implementation
******************************************************************************/
package org.python.pydev.shared_ui.outline;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.python.pydev.shared_core.model.ErrorDescription;
public abstract class BaseParsedItem implements IParsedItem, Comparable<Object> {
protected IParsedItem parent;
protected IParsedItem[] children;
protected ErrorDescription errorDesc;
/**
* Updates the structure of this parsed item (old structure) to be the same as the structure in the passed
* parsed item (new structure) trying to reuse the existing children (if possible).
*
* This is usually only called when the structure actually changes (different number of nodes). A common case
* is having a syntax error...
*/
@Override
public void updateTo(IParsedItem item) {
IParsedItem updateToItem = item;
this.toStringCache = null;
this.errorDesc = updateToItem.getErrorDesc();
IParsedItem[] newStructureChildren = updateToItem.getChildren();
//handle special cases...
if (this.children == null) {
this.children = newStructureChildren;
return;
}
if (newStructureChildren.length == 0 || this.children.length == 0) {
//nothing to actually update... (just set the new children directly)
this.children = newStructureChildren;
return;
}
ArrayList<IParsedItem> newChildren = new ArrayList<IParsedItem>();
//ok, something there... let's update the requested children...
//(trying to maintain the existing nodes were possible)
HashMap<String, List<IParsedItem>> childrensCache = new HashMap<String, List<IParsedItem>>();
for (IParsedItem existing : this.children) {
String s = existing.toString();
List<IParsedItem> list = childrensCache.get(s);
if (list == null) {
list = new ArrayList<IParsedItem>();
childrensCache.put(s, list);
}
list.add(existing);
}
for (IParsedItem n : newStructureChildren) {
IParsedItem similarChild = getSimilarChild(n, childrensCache);
if (similarChild != null) {
similarChild.updateTo(n);
n = similarChild;
} else {
n.setParent(this);
}
newChildren.add(n);
}
this.children = newChildren.toArray(new IParsedItem[newChildren.size()]);
}
@Override
public void setParent(IParsedItem parsedItem) {
this.parent = parsedItem;
}
private IParsedItem getSimilarChild(IParsedItem n, HashMap<String, List<IParsedItem>> childrensCache) {
//try to get a similar child from the 'cache'
List<IParsedItem> list = childrensCache.get(n.toString());
if (list != null && list.size() > 0) {
return list.remove(0);
}
return null;
}
@Override
public IParsedItem getParent() {
return parent;
}
/**
* When null, it must be rebuilt!
*/
protected String toStringCache;
@Override
public String toString() {
if (toStringCache == null) {
toStringCache = calcToString();
}
return toStringCache;
}
protected abstract String calcToString();
@Override
public ErrorDescription getErrorDesc() {
return errorDesc;
}
public void setErrorDesc(ErrorDescription errorDesc) {
if (this.errorDesc == null && errorDesc == null) {
return; // don't clear the caches
}
this.toStringCache = null;
this.errorDesc = errorDesc;
}
}