1 /*******************************************************************************
2  * Copyright (c) 2005, 2016 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  *     Lars Vogel <Lars.Vogel@gmail.com> - Bug 440810
14  *******************************************************************************/
15 package org.eclipse.ui.internal;
16 
17 import java.util.Collection;
18 import java.util.HashMap;
19 import java.util.HashSet;
20 import java.util.Map;
21 import org.eclipse.core.runtime.ListenerList;
22 import org.eclipse.ui.IPropertyListener;
23 import org.eclipse.ui.contexts.IContextActivation;
24 import org.eclipse.ui.contexts.IContextService;
25 import org.eclipse.ui.internal.registry.IActionSetDescriptor;
26 import org.eclipse.ui.services.IServiceLocator;
27 
28 /**
29  * Maintains a reference counted set of action sets, with a visibility mask.
30  * This is used to determine the visibility of actions in a workbench page. In a
31  * workbench page, there may be may be many conditions that can cause an action
32  * set to become visible (such as the active part, the active editor, the
33  * default visibility of the action, the properties of the perspective, etc.)
34  * The user can also explicitly mask off particular action sets in each
35  * perspective.
36  * <p>
37  * The reference count indicates how many conditions have requested that the
38  * actions be active and the mask indicates whether or not the set was disabled
39  * by the user.
40  * </p>
41  *
42  * @since 3.1
43  */
44 public class ActionSetManager {
45 
46 	private static class ActionSetRec {
47 		int showCount;
48 
49 		int maskCount;
50 
isVisible()51 		public boolean isVisible() {
52 			return maskCount == 0 && showCount > 0;
53 		}
54 
isEmpty()55 		public boolean isEmpty() {
56 			return maskCount == 0 && showCount == 0;
57 		}
58 	}
59 
60 	private HashMap actionSets = new HashMap();
61 	private HashSet visibleItems = new HashSet();
62 
63 	public static final int PROP_VISIBLE = 0;
64 	public static final int PROP_HIDDEN = 1;
65 	public static final int CHANGE_MASK = 0;
66 	public static final int CHANGE_UNMASK = 1;
67 	public static final int CHANGE_SHOW = 2;
68 	public static final int CHANGE_HIDE = 3;
69 
70 	private ListenerList<IPropertyListener> listeners = new ListenerList<>();
71 	private IPropertyListener contextListener;
72 	private Map activationsById = new HashMap();
73 	private IContextService contextService;
74 
ActionSetManager(IServiceLocator locator)75 	public ActionSetManager(IServiceLocator locator) {
76 		contextService = locator.getService(IContextService.class);
77 		addListener(getContextListener());
78 	}
79 
80 	/**
81 	 * @return
82 	 */
getContextListener()83 	private IPropertyListener getContextListener() {
84 		if (contextListener == null) {
85 			contextListener = (source, propId) -> {
86 				if (source instanceof IActionSetDescriptor) {
87 					IActionSetDescriptor desc = (IActionSetDescriptor) source;
88 					String id = desc.getId();
89 					if (propId == PROP_VISIBLE) {
90 						activationsById.put(id, contextService.activateContext(id));
91 					} else if (propId == PROP_HIDDEN) {
92 						IContextActivation act = (IContextActivation) activationsById.remove(id);
93 						if (act != null) {
94 							contextService.deactivateContext(act);
95 						}
96 					}
97 				}
98 			};
99 		}
100 		return contextListener;
101 	}
102 
addListener(IPropertyListener l)103 	public void addListener(IPropertyListener l) {
104 		listeners.add(l);
105 	}
106 
removeListener(IPropertyListener l)107 	public void removeListener(IPropertyListener l) {
108 		listeners.remove(l);
109 	}
110 
firePropertyChange(IActionSetDescriptor descriptor, int id)111 	private void firePropertyChange(IActionSetDescriptor descriptor, int id) {
112 		for (IPropertyListener listener : listeners) {
113 			listener.propertyChanged(descriptor, id);
114 		}
115 	}
116 
getRec(IActionSetDescriptor descriptor)117 	private ActionSetRec getRec(IActionSetDescriptor descriptor) {
118 		ActionSetRec rec = (ActionSetRec) actionSets.get(descriptor);
119 
120 		if (rec == null) {
121 			rec = new ActionSetRec();
122 			actionSets.put(descriptor, rec);
123 		}
124 
125 		return rec;
126 	}
127 
showAction(IActionSetDescriptor descriptor)128 	public void showAction(IActionSetDescriptor descriptor) {
129 		ActionSetRec rec = getRec(descriptor);
130 
131 		boolean wasVisible = rec.isVisible();
132 		rec.showCount++;
133 		if (!wasVisible && rec.isVisible()) {
134 			visibleItems.add(descriptor);
135 			firePropertyChange(descriptor, PROP_VISIBLE);
136 			if (rec.isEmpty()) {
137 				actionSets.remove(descriptor);
138 			}
139 		}
140 	}
141 
hideAction(IActionSetDescriptor descriptor)142 	public void hideAction(IActionSetDescriptor descriptor) {
143 		ActionSetRec rec = getRec(descriptor);
144 
145 		boolean wasVisible = rec.isVisible();
146 		rec.showCount--;
147 		if (wasVisible && !rec.isVisible()) {
148 			visibleItems.remove(descriptor);
149 			firePropertyChange(descriptor, PROP_HIDDEN);
150 			if (rec.isEmpty()) {
151 				actionSets.remove(descriptor);
152 			}
153 		}
154 	}
155 
maskAction(IActionSetDescriptor descriptor)156 	public void maskAction(IActionSetDescriptor descriptor) {
157 		ActionSetRec rec = getRec(descriptor);
158 
159 		boolean wasVisible = rec.isVisible();
160 		rec.maskCount++;
161 		if (wasVisible && !rec.isVisible()) {
162 			visibleItems.remove(descriptor);
163 			firePropertyChange(descriptor, PROP_HIDDEN);
164 			if (rec.isEmpty()) {
165 				actionSets.remove(descriptor);
166 			}
167 		}
168 	}
169 
unmaskAction(IActionSetDescriptor descriptor)170 	public void unmaskAction(IActionSetDescriptor descriptor) {
171 		ActionSetRec rec = getRec(descriptor);
172 
173 		boolean wasVisible = rec.isVisible();
174 		rec.maskCount--;
175 		if (!wasVisible && rec.isVisible()) {
176 			visibleItems.add(descriptor);
177 			firePropertyChange(descriptor, PROP_VISIBLE);
178 			if (rec.isEmpty()) {
179 				actionSets.remove(descriptor);
180 			}
181 		}
182 	}
183 
getVisibleItems()184 	public Collection getVisibleItems() {
185 		return visibleItems;
186 	}
187 
change(IActionSetDescriptor descriptor, int changeType)188 	public void change(IActionSetDescriptor descriptor, int changeType) {
189 		switch (changeType) {
190 		case CHANGE_SHOW:
191 			showAction(descriptor);
192 			break;
193 		case CHANGE_HIDE:
194 			hideAction(descriptor);
195 			break;
196 		case CHANGE_MASK:
197 			maskAction(descriptor);
198 			break;
199 		case CHANGE_UNMASK:
200 			unmaskAction(descriptor);
201 			break;
202 		}
203 	}
204 }
205