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 package org.eclipse.core.commands; 15 16 import java.util.ArrayList; 17 import java.util.Collection; 18 import java.util.Iterator; 19 import java.util.Objects; 20 21 import org.eclipse.core.commands.common.NamedHandleObject; 22 23 /** 24 * <p> 25 * A logical group for a set of commands. A command belongs to exactly one 26 * category. The category has no functional effect, but may be used in graphical 27 * tools that want to group the set of commands somehow. 28 * </p> 29 * 30 * @since 3.1 31 */ 32 public final class Category extends NamedHandleObject { 33 34 /** 35 * A collection of objects listening to changes to this category. This 36 * collection is <code>null</code> if there are no listeners. 37 */ 38 private Collection<ICategoryListener> categoryListeners; 39 40 /** 41 * Constructs a new instance of <code>Category</code> based on the given 42 * identifier. When a category is first constructed, it is undefined. 43 * Category should only be constructed by the <code>CommandManager</code> 44 * to ensure that identifier remain unique. 45 * 46 * @param id 47 * The identifier for the category. This value must not be 48 * <code>null</code>, and must be unique amongst all 49 * categories. 50 */ Category(final String id)51 Category(final String id) { 52 super(id); 53 } 54 55 /** 56 * Adds a listener to this category that will be notified when this 57 * category's state changes. 58 * 59 * @param categoryListener 60 * The listener to be added; must not be <code>null</code>. 61 */ addCategoryListener( final ICategoryListener categoryListener)62 public final void addCategoryListener( 63 final ICategoryListener categoryListener) { 64 if (categoryListener == null) { 65 throw new NullPointerException(); 66 } 67 if (categoryListeners == null) { 68 categoryListeners = new ArrayList<>(); 69 } 70 if (!categoryListeners.contains(categoryListener)) { 71 categoryListeners.add(categoryListener); 72 } 73 } 74 75 /** 76 * <p> 77 * Defines this category by giving it a name, and possibly a description as 78 * well. The defined property automatically becomes <code>true</code>. 79 * </p> 80 * <p> 81 * Notification is sent to all listeners that something has changed. 82 * </p> 83 * 84 * @param name 85 * The name of this command; must not be <code>null</code>. 86 * @param description 87 * The description for this command; may be <code>null</code>. 88 */ define(final String name, final String description)89 public final void define(final String name, final String description) { 90 if (name == null) { 91 throw new NullPointerException("The name of a command cannot be null"); //$NON-NLS-1$ 92 } 93 94 final boolean definedChanged = !this.defined; 95 this.defined = true; 96 97 final boolean nameChanged = !Objects.equals(this.name, name); 98 this.name = name; 99 100 final boolean descriptionChanged = !Objects.equals(this.description, description); 101 this.description = description; 102 103 fireCategoryChanged(new CategoryEvent(this, definedChanged, descriptionChanged, nameChanged)); 104 } 105 106 /** 107 * Notifies the listeners for this category that it has changed in some way. 108 * 109 * @param categoryEvent 110 * The event to send to all of the listener; must not be 111 * <code>null</code>. 112 */ fireCategoryChanged(final CategoryEvent categoryEvent)113 private final void fireCategoryChanged(final CategoryEvent categoryEvent) { 114 if (categoryEvent == null) { 115 throw new NullPointerException(); 116 } 117 if (categoryListeners != null) { 118 final Iterator<ICategoryListener> listenerItr = categoryListeners.iterator(); 119 while (listenerItr.hasNext()) { 120 final ICategoryListener listener = listenerItr.next(); 121 listener.categoryChanged(categoryEvent); 122 } 123 } 124 } 125 126 /** 127 * Removes a listener from this category. 128 * 129 * @param categoryListener 130 * The listener to be removed; must not be <code>null</code>. 131 * 132 */ removeCategoryListener( final ICategoryListener categoryListener)133 public final void removeCategoryListener( 134 final ICategoryListener categoryListener) { 135 if (categoryListener == null) { 136 throw new NullPointerException(); 137 } 138 139 if (categoryListeners != null) { 140 categoryListeners.remove(categoryListener); 141 } 142 } 143 144 @Override toString()145 public String toString() { 146 if (string == null) { 147 final StringBuilder stringBuffer = new StringBuilder("Category("); //$NON-NLS-1$ 148 stringBuffer.append(id); 149 stringBuffer.append(','); 150 stringBuffer.append(name); 151 stringBuffer.append(','); 152 stringBuffer.append(description); 153 stringBuffer.append(','); 154 stringBuffer.append(defined); 155 stringBuffer.append(')'); 156 string = stringBuffer.toString(); 157 } 158 return string; 159 } 160 161 @Override undefine()162 public void undefine() { 163 string = null; 164 165 final boolean definedChanged = defined; 166 defined = false; 167 168 final boolean nameChanged = name != null; 169 name = null; 170 171 final boolean descriptionChanged = description != null; 172 description = null; 173 174 fireCategoryChanged(new CategoryEvent(this, definedChanged, descriptionChanged, nameChanged)); 175 } 176 177 } 178