/*
This library is part of octools
Copyright (c) 2000-2007 Valtech A/S (http://www.valtech.dk)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
Alkacon OpenCms and the OpenCms logo are registered trademarks of
Alkacon Software GmbH in Germany, the USA and other countries
For further information about Alkacon Software GmbH, please see the
company website: http://www.alkacon.com
For further information about OpenCms, please see the
project website: http://www.opencms.org
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package dk.valtech.octools.navigation;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.opencms.file.CmsObject;
import org.opencms.file.CmsResource;
import org.opencms.file.CmsResourceFilter;
import org.opencms.jsp.CmsJspNavBuilder;
import org.opencms.jsp.CmsJspNavElement;
import org.opencms.main.CmsException;
import org.opencms.main.CmsLog;
public abstract class AbstractRecursiveNavigationIterator implements Iterator<CmsJspNavElement>, NavigationIterator {
/**
* This is the default filter, which includes only resources that are included in the navigation.
*/
public static final ResourceFilter NAVIGATION_FILTER = new NavigationResourceFilter();
/**
* This filter includes all resources returned by {@link CmsObject#getResourcesInFolder(String, CmsResourceFilter)}
*/
public static final ResourceFilter NO_FILTER = new AllResourceFilter();
private static final Log log = CmsLog.getLog(AbstractRecursiveNavigationIterator.class);
enum LevelChangeType {
BEFORE_LEVEL_INCREASE,
// AFTER_LEVEL_INCREASE,
BEFORE_LEVEL_DECREASE;
// AFTER_LEVEL_DECREASE;
}
public static final int UNSPECIFIED_LEVEL = Integer.MAX_VALUE;
protected CmsObject cms;
// aka startLevel
protected int level = UNSPECIFIED_LEVEL;
protected int endLevel = UNSPECIFIED_LEVEL;
protected int explodeFrom = UNSPECIFIED_LEVEL;
protected int explodeTo = UNSPECIFIED_LEVEL;
protected int currentLevel;
protected RecursiveNavigationIterationStatus status;
protected String[] path;
private HashMap<String, List<CmsJspNavElement>> navigationCache;
private Set<NavigationChangeListener> listeners;
private ResourceFilter filter = NAVIGATION_FILTER;
public AbstractRecursiveNavigationIterator(CmsObject cms) {
super();
this.cms = cms;
navigationCache = new HashMap<String, List<CmsJspNavElement>>();
listeners = new HashSet<NavigationChangeListener>();
}
public AbstractRecursiveNavigationIterator(CmsObject cms, int intLevel) {
this(cms);
this.level = intLevel;
}
public AbstractRecursiveNavigationIterator(CmsObject cms, String folder) {
this(cms);
setFolder(folder);
}
public AbstractRecursiveNavigationIterator(CmsObject cms, String folder, int level) {
this(cms, folder);
this.level = level;
}
public NavigationIterationStatus getStatus() {
return status;
}
public void init() {
if (path == null) {
setFolder(cms.getRequestContext().getFolderUri());
}
if (level == UNSPECIFIED_LEVEL) {
level = path.length-1;
}
if (explodeTo != explodeFrom && explodeFrom == UNSPECIFIED_LEVEL) {
explodeFrom = 0;
}
setCurrentLevel(level);
status = new RecursiveNavigationIterationStatus(this);
localInit();
}
protected abstract void localInit();
protected void setCurrentLevel(int level) {
currentLevel = level;
}
/**
* Returns true if the current element is a subNavigation and is either in the path or the
* current level should be exploded anyways.
* @return
*/
protected boolean shouldExplode() {
return status.isSubNavigation() && (status.isInPath() || currentLevel >= explodeFrom && currentLevel < explodeTo);
}
protected String getFolderForNewLevel(int newLevel) {
StringBuffer buf = new StringBuffer();
for (int i = 0; i <= newLevel; i++) {
buf.append(path[i]).append("/");
}
return buf.toString();
}
public void setFolder(String folder) {
this.path = folder.split("/");
if (this.path.length == 0 && folder.equals("/")) {
this.path = new String[] {""};
}
}
public int getCurrentLevel() {
return currentLevel;
}
public int getLevel() {
return level;
}
protected CmsObject getCms() {
return cms;
}
public int getEndLevel() {
return endLevel;
}
public void setEndLevel(int endLevel) {
this.endLevel = endLevel;
}
public void setLevel(int level) {
this.level = level;
}
public int getExplodeFrom() {
return explodeFrom;
}
public void setExplodeFrom(int explodeFrom) {
this.explodeFrom = explodeFrom;
}
public int getExplodeTo() {
return explodeTo;
}
public void setExplodeTo(int explodeTo) {
this.explodeTo = explodeTo;
}
public String[] getPath() {
return path;
}
public Iterator<CmsJspNavElement> iterator() {
init();
return this;
}
public void remove() {
throw new UnsupportedOperationException("Remove is not supported from TreeNavigationElement");
}
protected abstract LevelIterator getCurrentIterator();
public List<CmsJspNavElement> getNavigationForFolder(String folder) {
if (!navigationCache.containsKey(folder)) {
folder = CmsResource.getFolderPath(folder);
List<CmsJspNavElement> result = new ArrayList<CmsJspNavElement>();
try {
@SuppressWarnings("unchecked")
List<CmsResource> resources = cms.getResourcesInFolder(folder, CmsResourceFilter.DEFAULT);
for (int i = 0; i < resources.size(); i++) {
CmsResource r = (CmsResource)resources.get(i);
CmsJspNavElement element = CmsJspNavBuilder.getNavigationForResource(cms, cms.getSitePath(r));
if ((element != null) && filter.include(cms, this, r, element)) {
result.add(element);
}
}
filter.sort(result);
navigationCache.put(folder, result);
} catch (CmsException e) {
log.warn("Unable to read folder '" + folder + "'. Using empty list.", e);
navigationCache.put(folder, Collections.<CmsJspNavElement>emptyList());
}
}
return navigationCache.get(folder);
}
@Deprecated
public boolean isIncludingNonNavigation() {
return !(filter instanceof NavigationResourceFilter);
}
@Deprecated
public void setIncludingNonNavigation(boolean includingNonNavigation) {
if (includingNonNavigation) {
setFilter(new AllResourceFilter());
} else {
setFilter(new NavigationResourceFilter());
}
}
public void addListener(NavigationChangeListener listener) {
listeners.add(listener);
}
public void removeListener(NavigationChangeListener listener) {
listeners = new HashSet<NavigationChangeListener>();
listeners.addAll(listeners);
listeners.remove(listener);
}
public void fireNavigationLevelChangeEvent(LevelChangeType eventType) {
Iterator<NavigationChangeListener> iter = listeners.iterator();
CmsJspNavElement e = getCurrentIterator().getCurrentElement();
while (iter.hasNext()) {
NavigationChangeListener listener = iter.next();
switch (eventType) {
case BEFORE_LEVEL_INCREASE:
listener.beforeNavigationLevelChange(currentLevel, currentLevel+1, e);
break;
// case AFTER_LEVEL_INCREASE:
// listener.afterNavigationLevelChanged(currentLevel-1, currentLevel);
// break;
case BEFORE_LEVEL_DECREASE:
listener.beforeNavigationLevelChange(currentLevel, currentLevel-1, e);
break;
// case AFTER_LEVEL_DECREASE:
// listener.afterNavigationLevelChanged(currentLevel+1, currentLevel);
// break;
}
}
}
public ResourceFilter getFilter() {
return filter;
}
public void setFilter(ResourceFilter filter) {
this.filter = filter;
}
}