// Near Infinity - An Infinity Engine Browser and Editor // Copyright (C) 2001 - 2005 Jon Olav Hauglid // See LICENSE.txt for license information package org.infinity.resource.are.viewer; import java.util.ArrayList; import java.util.List; import org.infinity.gui.layeritem.AbstractLayerItem; import org.infinity.resource.AbstractStruct; import org.infinity.resource.StructEntry; import org.infinity.resource.are.AreResource; import org.infinity.resource.are.viewer.ViewerConstants.LayerType; import org.infinity.resource.wed.WedResource; /** * Common base class for layer-specific managers. */ public abstract class BasicLayer<E extends LayerObject> { private final LayerType layerType; private final int layerTypeIndex; private final List<E> listObjects = new ArrayList<E>(); private final AreaViewer viewer; private AbstractStruct parent; private int schedule; private boolean visible, initialized, scheduleEnabled; /** * Initializes the current layer. * @param parent The parent resource of the layer (either AreResource or WedResource). * @param type The type/identifier of the layer. */ public BasicLayer(AbstractStruct parent, LayerType type, AreaViewer viewer) { // setting parent resource if (parent instanceof AreResource || parent instanceof WedResource) { this.parent = parent; } else { this.parent = null; } // setting layer type this.layerType = type; // getting associated layer type index int idx = -1; LayerType[] lt = LayerType.values(); for (int i = 0; i < lt.length; i++) { if (lt[i] == this.layerType) { idx = i; } } layerTypeIndex = idx; // setting associated area viewer instance this.viewer = viewer; } /** * Returns the registered AreaViewer instance. */ public AreaViewer getViewer() { return viewer; } /** * Returns whether the parent structure is of type AreResource. */ public boolean hasAre() { return (parent instanceof AreResource); } /** * Returns the parent as AreResource structure if available. */ public AreResource getAre() { return (parent instanceof AreResource) ? (AreResource)parent : null; } /** * Returns whether the parent structure is of type WedResource. */ public boolean hasWed() { return (parent instanceof WedResource); } /** * Returns the parent as WedResource structure if available. */ public WedResource getWed() { return (parent instanceof WedResource) ? (WedResource)parent : null; } /** * Returns the layer type of this specific layer. * @return The layer type */ public LayerType getLayerType() { return layerType; } /** * Returns the index of the layer type. * @return Index of layer type. */ public int getLayerTypeIndex() { return layerTypeIndex; } /** * Returns the number of objects in this layer. * @return Number of layer objects. */ public int getLayerObjectCount() { return listObjects.size(); } /** * Returns the layer object at the specified index. * @param index The index of the layer object. * @return The layer object, of {@code null} if not available. */ public E getLayerObject(int index) { if (index >= 0 && index < listObjects.size()) { return listObjects.get(index); } else { return null; } } /** * Returns the list of layer objects for direct manipulation. * @return List of layer objects. */ public List<E> getLayerObjects() { return listObjects; } /** * Returns whether the whole layer of items is marked as visible. (Note: Does not work correctly * if the visibility state of individual items are overridden.) */ public boolean isLayerVisible() { return visible; } /** * Sets the visibility state of all items in the layer. */ public void setLayerVisible(boolean visible) { for (int i = 0, size = listObjects.size(); i < size; i++) { boolean state = visible && (!isScheduleEnabled() || (isScheduleEnabled() && isScheduled(i))); E obj = listObjects.get(i); AbstractLayerItem[] items = obj.getLayerItems(); for (int j = 0; j < items.length; j++) { items[j].setVisible(state); } } this.visible = visible; } /** * Returns the layer object containing the specified layer item. * @return The object, if it has been found, {@code null} otherwise. */ public E getLayerObjectOf(AbstractLayerItem item) { if (item != null) { for (int i = 0, size = listObjects.size(); i < size; i++) { E obj = listObjects.get(i); AbstractLayerItem[] items = obj.getLayerItems(); for (int j = 0; j < items.length; j++) { if (items[j] == item) { return obj; } } } } return null; } /** * Loads all available objects of this layer if it hasn't been loaded yet. * @param forced If {@code true}, always (re-)loads the current layer, even if it has been loaded already. * @return The number of initialized layer objects. */ public abstract int loadLayer(boolean forced); /** * Removes all objects of the layer from memory. Additionally all associated layer items will be * removed from their associated container(s). */ public void close() { if (getViewer() != null) { for (int i = 0, size = listObjects.size(); i < size; i++) { listObjects.get(i).close(); } } listObjects.clear(); setInitialized(false); } /** * Returns whether schedules will be considered when querying {@link #isScheduled(int)}. * @return {@code true} if schedules will be considered, {@code false} otherwise. */ public boolean isScheduleEnabled() { return scheduleEnabled; } /** * Set whether schedules will be considered when querying {@link #isScheduled(int)}. * When setting {@code false}, {@link #isScheduled(int)} will always return true. */ public void setScheduleEnabled(boolean enable) { if (enable != scheduleEnabled) { scheduleEnabled = enable; setLayerVisible(isLayerVisible()); } } /** * Set the current schedule. It can be used on layer objects that support schedules to check against. * @param schedule The schedule value (schedule = hour - 1) */ public void setSchedule(int schedule) { if (schedule < 0) schedule = 0; else if (schedule > 23) schedule = 23; if (this.schedule != schedule) { this.schedule = schedule; setLayerVisible(isLayerVisible()); } } /** * Returns the currently set schedule. * @return The current schedule value. */ public int getSchedule() { return schedule; } /** * Returns whether the layer object at the specified index is active at the currently set schedule. * @param index The index of the layer object to check. * @return {@code true} if the layer object is scheduled, {@code false} otherwise. * (Note: Layer objects without schedule always return {@code true}.) */ public boolean isScheduled(int index) { E obj = getLayerObject(index); if (obj != null) { return !isScheduleEnabled() || obj.isScheduled(getSchedule()); } else { return false; } } /** * Returns the number of objects in this layer as a formatted string. * @return A formatted string telling about the number of objects in this layer. */ public abstract String getAvailability(); // Creates a list of structures of the specified type from the parent structure protected List<StructEntry> getStructures(int baseOfs, int count, Class<? extends StructEntry> type) { List<StructEntry> listStruct = new ArrayList<StructEntry>(); if (getParent() != null && baseOfs >= 0 && count >= 0 && type != null) { List<StructEntry> list = getParent().getList(); int cnt = 0; for (int i = 0, size = list.size(); i < size; i++) { if (list.get(i).getOffset() >= baseOfs && type.isAssignableFrom(list.get(i).getClass())) { listStruct.add(list.get(i)); cnt++; if (cnt >= count) { break; } } } } return listStruct; } // Convenience method: sets required listeners protected void setListeners(LayerObject obj) { if (obj != null) { AbstractLayerItem[] items = obj.getLayerItems(); for (int i = 0; i < items.length; i++) { if (items[i] != null) { items[i].addActionListener(viewer.getListeners()); items[i].addLayerItemListener(viewer.getListeners()); items[i].addMouseListener(viewer.getListeners()); items[i].addMouseMotionListener(viewer.getListeners()); } } } } /** * [For internal use only] Returns whether this layer has been loaded at least once. */ protected boolean isInitialized() { return initialized; } /** * [For internal use only] Marks the current layer as loaded. */ protected void setInitialized(boolean set) { initialized = set; } /** * [For internal use only] Sets the global visibility state of layer items without actually * touching the layer items. Use this method if you need to override {@link #setLayerVisible(boolean)}. */ protected void setVisibilityState(boolean state) { visible = state; } // Returns the parent structure of the layer objects regardless of type. private AbstractStruct getParent() { return parent; } }