blob: 0026289d77f3a3780a2d21cc4a504ea8e59a05e7 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007 IBM Corporation and Others
* 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:
* Hisashi MIYASHITA - initial API and implementation
*******************************************************************************/
package org.eclipse.actf.ai.fennec.impl;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.eclipse.actf.ai.fennec.FennecException;
import org.eclipse.actf.ai.fennec.FennecInterruptedException;
import org.eclipse.actf.ai.fennec.autotranslator.AutoTranslator;
import org.eclipse.actf.ai.fennec.treemanager.ITreeItem;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
// TODO I'd like to make it package-local.
public class FennecMode {
static public final int TYPE_SIMPLE = 0;
static public final int TYPE_ATTACH = 1;
static public final int TYPE_UNWRAP = 2;
static public final int TYPE_BUILT = 2;
static public final int TRIGGER_MOVE = 1 << 0;
static public final int TRIGGER_CLICK = 1 << 1;
static public final int TRIGGER_KEEP = 1 << 2;
static public final int TRIGGER_WITHOUTCHANGE = 1 << 3;
static public final int TRIGGER_UNWRAP = 1 << 4;
static public final int TRIGGER_ALWAYS = (TRIGGER_MOVE
| TRIGGER_CLICK
| TRIGGER_KEEP
| TRIGGER_UNWRAP);
private final int type;
private final int trigger;
private final boolean automatic;
private final boolean changeless;
private final boolean waitContents;
private FennecRecombinantMetadata baseMetadata;
private List<FennecMetadata> belongingMetadata;
private HashMap<Node, ArrayList<FennecMetadata>> metadataMap;
void addMetadata(FennecMetadata md) {
if (false) {
// A mode manages its belonging metadata in order to manage substate, but
// currently it is not used... So now this part is disabled.
if (belongingMetadata == null) {
belongingMetadata = new ArrayList<FennecMetadata>();
}
belongingMetadata.add(md);
}
}
void setBaseMetadata(FennecRecombinantMetadata md) {
this.baseMetadata = md;
}
boolean changed(TreeItemFennec pItem, int trigger) {
// TODO:
// return true;
if ((trigger & TRIGGER_WITHOUTCHANGE) != 0)
return false;
if (changeless)
return false;
return true;
}
private TreeItemFennec currentTopItem;
TreeItemFennec buildItem(Node n, TreeItemFennec pItem) {
currentTopItem = pItem;
TreeItemFennec item = AutoTranslator.translate(this, pItem, n);
if (pItem != null)
pItem.markRefreshedChild();
return item;
}
TreeItemFennec buildItemContinued(Node n, TreeItemFennec item) {
currentTopItem = null;
TreeItemFennec newItem = AutoTranslator.translateContinued(this, item, n);
if (newItem != null)
newItem.markRefreshedChild();
return newItem;
}
private FennecMetadata[] topMds;
private FennecMetadata[] initMetadataMap(FennecMetadata[] mds, Node n) {
if (topMds != null) return topMds;
metadataMap = new HashMap<Node, ArrayList<FennecMetadata>>();
ArrayList<FennecMetadata> mdList = new ArrayList<FennecMetadata>();
for (int i = 0; i < mds.length; i++) {
if (mds[i].hasTargets()) {
registMetadata(metadataMap, mds[i], n);
} else {
mdList.add(mds[i]);
}
}
topMds = mdList.toArray(new FennecMetadata[mdList.size()]);
return topMds;
}
public TreeItemFennec generateItem(TreeItemFennec pItem, Node n) {
FennecMetadata[] cmds = null;
FennecMetadata[] mds = baseMetadata.getChildMetadata();
if (mds != null) {
if (currentTopItem == pItem) {
// This item is top.
cmds = initMetadataMap(mds, n);
} else {
initMetadataMap(mds, n);
ArrayList<FennecMetadata> aMeta = metadataMap.get(n);
if (aMeta != null) {
cmds = (FennecMetadata[]) aMeta.toArray(new FennecMetadata[aMeta.size()]);
}
}
}
FennecMetadata md = FennecGeneratedMetadata.generate(baseMetadata, this, n, cmds);
return TreeItemFennec.newTreeItem(md, pItem, n);
}
private void registMetadata(HashMap<Node, ArrayList<FennecMetadata>> metaMap, FennecMetadata meta, Node base) {
NodeList list = meta.query(base);
for (int i = 0; i < list.getLength(); i++) {
Node node = list.item(i);
ArrayList<FennecMetadata> aMeta = metaMap.get(node);
if (aMeta == null) {
aMeta = new ArrayList<FennecMetadata>();
metaMap.put(node, aMeta);
}
if (meta instanceof FennecBundleMetadata) {
FennecMetadata[] m = ((FennecBundleMetadata) meta).childMetadata;
for (int j = 0; j < m.length; j++) {
if (m[j].hasTargets()) {
registMetadata(metaMap, m[j], node);
} else {
aMeta.add(m[j]);
}
}
}
}
}
private List autoAttach(TreeItemFennec pItem, NodeList nl, int len, int trigger) throws FennecException {
List l = new ArrayList(len);
for (int i = 0; i < len; i++) {
Node n = nl.item(i);
/*
if (n instanceof CacheableNode) {
CachableNode cn = (CachableNode) cn;
if (!cn.isChanged()) {
} else {
}
}
*/
TreeItemFennec newItem = buildItem(n, pItem);
if (newItem != null)
l.add(newItem);
}
if (l.size() == 0) {
if (this.trigger == TRIGGER_CLICK) {
throw new FennecInterruptedException("Could not attach the expected nodes.");
}
return null;
}
if (waitContents && (l.size() == 0)) {
throw new FennecInterruptedException("Contents have not been prepared yet.");
}
return l;
}
private List manualAttach(TreeItemFennec pItem, NodeList nl, int len, int trigger) throws FennecException {
List l = new ArrayList(len);
FennecMetadata[] childMds = baseMetadata.getChildMetadata();
for (int j = 0; j < len; j++) {
for (int i = 0; i < childMds.length; i++) {
FennecMetadata md = childMds[i];
List l2 = md.buildItems(pItem, nl.item(j), trigger);
if (l2 != null) {
if (l2.size() > 0) {
l.addAll(l2);
} else if (waitContents) {
throw new FennecInterruptedException("Contents have not been prepared yet.");
}
}
}
}
return l;
}
private List unwrap(TreeItemFennec pItem, NodeList nl, int len, int trigger) {
//TODO
return null;
}
// TODO:
private HashMap cachedResult = new HashMap();
List expand(TreeItemFennec pItem, Node baseNode, int trigger) throws FennecException {
if ((trigger != TRIGGER_KEEP) && ((trigger & this.trigger) == 0)) {
return null;
}
Object key;
if (baseNode != null) {
key = baseNode;
} else if (pItem == null) {
key = null;
} else {
key = pItem.getBaseNode();
}
if (!changed(pItem, trigger)) {
List l = (List) cachedResult.get(key);
if (l != null)
return l;
}
NodeList nl;
if (baseNode != null) {
nl = baseMetadata.query(baseNode);
} else {
nl = baseMetadata.query(pItem);
}
int len = nl.getLength();
List result = null;
switch (type) {
case TYPE_ATTACH:
if (len == 0) {
if (this.trigger == TRIGGER_CLICK) {
throw new FennecInterruptedException("Could not attach the expected nodes.");
}
return null;
}
if (automatic) {
result = autoAttach(pItem, nl, len, trigger);
} else {
result = manualAttach(pItem, nl, len, trigger);
}
cachedResult.put(key, result);
return result;
case TYPE_UNWRAP:
// TODO;
}
return result;
}
FennecMode(int type, int trigger, boolean automatic, boolean changeless, boolean waitContents) {
this.type = type;
this.trigger = trigger;
this.automatic = automatic;
this.changeless = changeless;
this.waitContents = waitContents;
}
FennecMode(int type) {
this.type = type;
this.trigger = TRIGGER_ALWAYS;
this.automatic = false;
this.changeless = false;
this.waitContents = false;
}
}