1 /*******************************************************************************
2  * Copyright (c) 2005, 2015 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 
15 package org.eclipse.core.commands;
16 
17 import java.util.HashMap;
18 import java.util.Map;
19 import java.util.Set;
20 
21 /**
22  * <p>
23  * An abstract implementation of {@link IObjectWithState}. This provides basic
24  * handling for adding and remove state. When state is added, the handler
25  * attaches itself as a listener and fire a handleStateChange event to notify
26  * this handler. When state is removed, the handler removes itself as a
27  * listener.
28  * </p>
29  * <p>
30  * Clients may extend this class.
31  * </p>
32  *
33  * @since 3.2
34  */
35 public abstract class AbstractHandlerWithState extends AbstractHandler implements IObjectWithState, IStateListener {
36 
37 	/**
38 	 * The map of states currently held by this handler. If this handler has no
39 	 * state (generally, when inactive), then this will be <code>null</code>.
40 	 */
41 	private Map<String, State> states;
42 
43 	private static final String[] EMPTY = new String[0];
44 
45 	/**
46 	 * <p>
47 	 * Adds a state to this handler. This will add this handler as a listener to
48 	 * the state, and then fire a handleStateChange so that the handler can
49 	 * respond to the incoming state.
50 	 * </p>
51 	 * <p>
52 	 * Clients may extend this method, but they should call this super method
53 	 * first before doing anything else.
54 	 * </p>
55 	 *
56 	 * @param stateId
57 	 *            The identifier indicating the type of state being added; must
58 	 *            not be <code>null</code>.
59 	 * @param state
60 	 *            The state to add; must not be <code>null</code>.
61 	 */
62 	@Override
addState(final String stateId, final State state)63 	public void addState(final String stateId, final State state) {
64 		if (state == null) {
65 			throw new NullPointerException("Cannot add a null state"); //$NON-NLS-1$
66 		}
67 
68 		if (states == null) {
69 			states = new HashMap<>(3);
70 		}
71 		states.put(stateId, state);
72 		state.addListener(this);
73 		handleStateChange(state, null);
74 	}
75 
76 	@Override
getState(final String stateId)77 	public final State getState(final String stateId) {
78 		if ((states == null) || (states.isEmpty())) {
79 			return null;
80 		}
81 
82 		return states.get(stateId);
83 	}
84 
85 	@Override
getStateIds()86 	public final String[] getStateIds() {
87 		if ((states == null) || (states.isEmpty())) {
88 			return EMPTY;
89 		}
90 
91 		final Set<String> stateIds = states.keySet();
92 		return stateIds.toArray(new String[stateIds.size()]);
93 	}
94 
95 	/**
96 	 * <p>
97 	 * Removes a state from this handler. This will remove this handler as a
98 	 * listener to the state. No event is fired to notify the handler of this
99 	 * change.
100 	 * </p>
101 	 * <p>
102 	 * Clients may extend this method, but they should call this super method
103 	 * first before doing anything else.
104 	 * </p>
105 	 *
106 	 * @param stateId
107 	 *            The identifier of the state to remove; must not be
108 	 *            <code>null</code>.
109 	 */
110 	@Override
removeState(final String stateId)111 	public void removeState(final String stateId) {
112 		if (stateId == null) {
113 			throw new NullPointerException("Cannot remove a null state"); //$NON-NLS-1$
114 		}
115 		if (states == null) {
116 			return;
117 		}
118 		final State state = states.get(stateId);
119 		if (state != null) {
120 			state.removeListener(this);
121 			if (states != null) {
122 				states.remove(stateId);
123 				if (states.isEmpty()) {
124 					states = null;
125 				}
126 			}
127 		}
128 	}
129 }
130