package com.vitco.util.components.dialog; import javax.swing.*; import java.awt.*; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; /** * Needs to be extended by all objects that are added to a UserInputDialog. */ public class BlankDialogModule extends JComponent { // indicates ready status of component private boolean ready = true; // the child modules of this module private final HashSet<BlankDialogModule> childModules = new HashSet<BlankDialogModule>(); // maps ids to the child modules (needs to be separate if several child modules have the same identifier) private final HashMap<String, BlankDialogModule> id2ChildModule = new HashMap<String, BlankDialogModule>(); // the identifier of this object private final String identifier; public final String getIdentifier() { return identifier; } // the listener of this module private final ArrayList<DialogModuleChangeListener> listeners = new ArrayList<DialogModuleChangeListener>(); // add a state change listener protected final void addListener(DialogModuleChangeListener listener) { listeners.add(listener); } // listener that is used to propagate events from all children to // this module (so we always receive it at the top level) private final DialogModuleChangeListener propagationListener = new DialogModuleChangeAdapter() { @Override public void onReadyStateChanged() { notifyReadyStateChanged(); } @Override public void onContentChanged() { notifyContentChanged(); } }; // called when the ready state of this component has changed protected final void notifyReadyStateChanged() { // notify all listeners (including parents) for (DialogModuleChangeListener listener : listeners) { listener.onReadyStateChanged(); } } // called when the content of this component has changed // modules that overwrite their values should call this when the // value changes protected final void notifyContentChanged() { // notify all listeners (including parents) for (DialogModuleChangeListener listener : listeners) { listener.onContentChanged(); } } // -------------- // constructor public BlankDialogModule(String identifier) { // spacing below (is removed if child modules are added) setBorder(BorderFactory.createEmptyBorder(0, 0, 10, 0)); // set the layout setLayout(new GridBagLayout()); // store identifer this.identifier = identifier; } // ------------------- // set enabled lookup (format "[identifier]=[string]") private final String[] lookups = new String[4]; public final void setEnabledLookup(String lookup) { lookups[0] = lookup; } public final void setDisabledLookup(String lookup) { lookups[1] = lookup; } public final void setVisibleLookup(String lookup) { lookups[2] = lookup; } public final void setInvisibleLookup(String lookup) { lookups[3] = lookup; } // called to update the state of this component protected void refreshState(BlankDialogModule topLevelParent) { boolean visible = true; boolean enabled = true; for (int i = 0; i < 4; i++) { if (lookups[i] != null) { // split into different parts String[] parts = lookups[i].split("&"); int matchCount = 0; // loop over parts (we need to check all of them) for (String part : parts) { // split into key and possible values String[] lookup = part.split("="); if (lookup.length == 2) { // get the value for the key Object value = topLevelParent.getValue(lookup[0]); if (value != null) { // split possible values and see if one matches String[] possibleValues = lookup[1].split(","); boolean matched = false; for (String possibleValue : possibleValues) { if (possibleValue.equals(value.toString())) { matched = true; break; } } // we matched this part, increase counter if (matched) { matchCount++; } else { break; } } } } boolean matched = matchCount == parts.length; switch (i) { case 0: if (!matched) { enabled = false; } break; case 1: if (matched) { enabled = false; } break; case 2: if (!matched) { visible = false; } break; default: if (matched) { visible = false; } break; } } } if (lookups[0] != null || lookups[1] != null) { this.setDeepEnabled(enabled); } if (lookups[2] != null || lookups[3] != null) { this.setVisible(visible); } // refresh all children for (BlankDialogModule child : childModules) { child.refreshState(topLevelParent); } } // disable all children when this is triggered private void setDeepEnabled(boolean value) { ArrayList<Component> components = new ArrayList<Component>(); components.add(this); while (!components.isEmpty()) { Component com = components.remove(0); com.setEnabled(value); if (com instanceof Container) { Collections.addAll(components, ((Container) com).getComponents()); } } } // ------------------ // add a child module to this module protected final void addModule(BlankDialogModule module, boolean display) { // remove spacing (the child deals with that now) setBorder(BorderFactory.createEmptyBorder()); // register this module childModules.add(module); id2ChildModule.put(module.getIdentifier(), module); // inject listener module.addListener(propagationListener); // add child module to this container to be displayed if (display) { GridBagConstraints gbc = new GridBagConstraints(); gbc.fill = GridBagConstraints.HORIZONTAL; gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.weightx = 1; this.add(module, gbc); } } // set ready status of component protected final void setReady(boolean ready) { if (this.ready != ready) { this.ready = ready; notifyReadyStateChanged(); } } // returns true if this component and all sub components are ready protected final boolean isReady() { // check if visible (invisible components are ok to be not ready) if (!this.isVisible()) { return true; } if (!this.isDisplayable()) { return true; } // check if this is not ready if (!ready) { return false; } // check if any child is not ready for (BlankDialogModule module : childModules) { if (!module.isReady()) { return false; } } // all ready! return true; } // get the value of this object // needs to be overwritten for objects that do not // get their value from their children protected String getValue(String identifier) { if (identifier == null) { return null; } String[] path = identifier.split("\\.", 2); BlankDialogModule object = id2ChildModule.get(path[0]); if (object != null) { return object.getValue(path.length > 1 ? path[1] : null); } return null; } // retrieve the serialization of this object // needs to be overwritten if the object wants to store its value (serialization) protected ArrayList<String[]> getSerialization(String currentIdentifier) { ArrayList<String[]> keyValueSet = new ArrayList<String[]>(); for (BlankDialogModule child : childModules) { keyValueSet.addAll(child.getSerialization( currentIdentifier + (currentIdentifier.equals("") ? "" : ".") + child.getIdentifier()) ); } return keyValueSet; } // load a key // needs to be overwritten if the object wants to restore its value (deserialization) protected boolean loadValue(String[] pair) { String[] path = pair[0].split("\\.", 2); BlankDialogModule object = id2ChildModule.get(path[0]); pair = new String[]{path.length > 1 ? path[1] : "", pair[1]}; return object != null && object.loadValue(pair); } }