001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.form;
043:
044: import java.util.*;
045: import java.lang.reflect.Method;
046:
047: /**
048: * Manages information about used component events and their handlers (in
049: * one form). Also maps handled events to methods of a "common event
050: * dispatching listener" (CEDL), which may be generated by the code generator
051: * (in certain modes).
052: *
053: * @author Tomas Pavek
054: */
055:
056: public class FormEvents {
057:
058: static final Event[] NO_EVENTS = {};
059:
060: // CEDL: mapping listener type name to ListenerInfo
061: private Map<String, ListenerInfo> usedListeners = new HashMap<String, ListenerInfo>();
062:
063: // CEDL: mapping listener method signature to list of Event
064: private Map<String, List<Event>> usedMethods = new HashMap<String, List<Event>>();
065:
066: // event handlers: mapping event handler name to list of Event
067: private Map<String, List<Event>> eventHandlers = new HashMap<String, List<Event>>();
068:
069: private FormModel formModel;
070:
071: FormEvents(FormModel formModel) {
072: this .formModel = formModel;
073: }
074:
075: // --------
076: // public interface - getters
077:
078: public boolean hasEventsInCEDL() {
079: return !usedListeners.isEmpty();
080: }
081:
082: public Class[] getCEDLTypes() {
083: Collection<ListenerInfo> infoValues = usedListeners.values();
084: Class[] listenerTypes = new Class[infoValues.size()];
085: int i = 0;
086: Iterator<ListenerInfo> it = infoValues.iterator();
087: while (it.hasNext())
088: listenerTypes[i++] = it.next().listenerType;
089:
090: return listenerTypes;
091: }
092:
093: public Event[] getEventsForCEDLMethod(Method listenerMethod) {
094: List<Event> eventList = usedMethods
095: .get(fullMethodName(listenerMethod));
096: if (eventList == null)
097: return NO_EVENTS;
098:
099: Event[] eventArray = new Event[eventList.size()];
100: eventList.toArray(eventArray);
101: return eventArray;
102: }
103:
104: public Event[] getEventsForHandler(String handlerName) {
105: List<Event> handlerEventList = eventHandlers.get(handlerName);
106: Event[] events = new Event[handlerEventList.size()];
107: handlerEventList.toArray(events);
108: return events;
109: }
110:
111: public Method getOriginalListenerMethod(String handlerName) {
112: List<Event> handlerEventList = eventHandlers.get(handlerName);
113: return handlerEventList != null ? handlerEventList.get(0)
114: .getListenerMethod() : null;
115: }
116:
117: public String[] getAllEventHandlers() {
118: Set<String> nameSet = eventHandlers.keySet();
119: String[] names = new String[nameSet.size()];
120: nameSet.toArray(names);
121: return names;
122: }
123:
124: // --------
125: // public interface - adding/removing events
126:
127: public void attachEvent(Event event, String handlerName,
128: String handlerText) {
129: attachEvent(event, handlerName, handlerText, null);
130: }
131:
132: public void attachEvent(Event event, String handlerName,
133: String handlerText, String annotationText) {
134: boolean newHandler = false; // if new event handler has been created
135:
136: if (handlerName == null && event.hasEventHandlers()) { // nothing to do
137: handlerName = (String) event.getEventHandlerList().get(0);
138: event = null;
139: } else { // find/create handler, attach event to it
140: List<Event> handlerEventList;
141: if (handlerName != null) {
142: handlerEventList = eventHandlers.get(handlerName);
143: if (handlerEventList != null) // handler already exists
144: checkCompatibility(event, handlerEventList.get(0));
145: } else { // no name provided, find a free one
146: handlerEventList = null;
147: handlerName = findFreeHandlerName(event, event
148: .getComponent());
149: }
150:
151: if (handlerEventList == null) { // create new handler
152: handlerEventList = new ArrayList<Event>(3);
153: eventHandlers.put(handlerName, handlerEventList);
154: newHandler = true;
155: }
156:
157: if (!event.isInCEDL())
158: registerEventInCEDL(event);
159:
160: if (event.addEventHandler(handlerName))
161: handlerEventList.add(event);
162: else
163: // handler not added (event is already attached to it)
164: event = null;
165: }
166:
167: formModel.fireEventHandlerAdded(event, handlerName,
168: handlerText, annotationText, newHandler);
169: }
170:
171: public void detachEvent(Event event, String handlerName) {
172: if (event.removeEventHandler(handlerName)) {
173: if (!event.hasEventHandlers())
174: unregisterEventFromCEDL(event);
175:
176: detachEventHandler(event, handlerName);
177: }
178: }
179:
180: public void detachEvent(Event event) {
181: unregisterEventFromCEDL(event);
182: String[] handlerNames = event.getEventHandlers();
183: for (int i = 0; i < handlerNames.length; i++) {
184: event.removeEventHandler(handlerNames[i]);
185: detachEventHandler(event, handlerNames[i]);
186: }
187: }
188:
189: public void renameEventHandler(String oldHandlerName,
190: String newHandlerName) {
191: if (oldHandlerName == null || newHandlerName == null
192: || oldHandlerName.equals(newHandlerName))
193: return;
194:
195: List<Event> handlerEventList = eventHandlers
196: .get(oldHandlerName);
197: if (handlerEventList == null)
198: return; // oldHandlerName handler not found
199:
200: if (eventHandlers.get(newHandlerName) == null) {
201: for (int j = 0; j < handlerEventList.size(); j++) {
202: Event event = handlerEventList.get(j);
203: event
204: .renameEventHandler(oldHandlerName,
205: newHandlerName);
206: }
207: eventHandlers.remove(oldHandlerName);
208: eventHandlers.put(newHandlerName, handlerEventList);
209: formModel.fireEventHandlerRenamed(oldHandlerName,
210: newHandlerName);
211: } else {
212: IllegalArgumentException iae = new IllegalArgumentException(
213: "Cannot rename handler"); // NOI18N
214: org.openide.ErrorManager.getDefault().annotate(iae,
215: FormUtils.getBundleString("MSG_CannotRename")); // NOI18N
216: throw iae;
217: }
218: }
219:
220: public String findFreeHandlerName(Event event, RADComponent metacomp) {
221: String componentName = metacomp == formModel
222: .getTopRADComponent() ? "form" : metacomp.getName(); // NOI18N
223: String methodName = event.getListenerMethod().getName();
224:
225: return findFreeHandlerName(componentName
226: + methodName.substring(0, 1).toUpperCase()
227: + methodName.substring(1));
228: }
229:
230: public String findFreeHandlerName(String baseName) {
231: String name = baseName;
232: int n = 0;
233: while (eventHandlers.get(name) != null)
234: name = baseName + (++n);
235: return name;
236: }
237:
238: // --------
239: // package private interface
240:
241: static String getEventIdName(Method eventMethod) {
242: StringBuffer buf = new StringBuffer(64);
243:
244: buf.append("$"); // NOI18N
245: buf.append(eventMethod.getDeclaringClass().getName());
246: buf.append("."); // NOI18N
247: buf.append(eventMethod.getName());
248: buf.append("("); // NOI18N
249:
250: Class[] parameterTypes = eventMethod.getParameterTypes();
251: for (int i = 0; i < parameterTypes.length; i++) {
252: buf.append(parameterTypes[i].getName());
253: if (i + 1 < parameterTypes.length)
254: buf.append(", "); // NOI18N
255: }
256:
257: buf.append(")"); // NOI18N
258: return buf.toString();
259: }
260:
261: // --------
262: // private methods
263:
264: private void registerEventInCEDL(Event event) {
265: // listener class must be an interface (required for CEDL)
266: Class listenerType = event.getEventSetDescriptor()
267: .getListenerType();
268: if (!listenerType.isInterface())
269: return;
270:
271: // event method must have EventObject as parameter (required for CEDL)
272: Class[] parameters = event.getListenerMethod()
273: .getParameterTypes();
274: if (parameters.length == 0
275: || !java.util.EventObject.class
276: .isAssignableFrom(parameters[0]))
277: return;
278:
279: if (!addEventToMethod(event))
280: return; // method signature already used
281:
282: String listenerTypeName = listenerType.getName();
283: ListenerInfo lInfo = usedListeners.get(listenerTypeName);
284: if (lInfo == null) {
285: lInfo = new ListenerInfo(listenerType);
286: usedListeners.put(listenerTypeName, lInfo);
287: } else
288: lInfo.listenerType = listenerType;
289: lInfo.useCount++;
290:
291: event.setInCEDL(true);
292: }
293:
294: private void unregisterEventFromCEDL(Event event) {
295: if (removeEventFromMethod(event)) {
296: String listenerTypeName = event.getEventSetDescriptor()
297: .getListenerType().getName();
298: ListenerInfo lInfo = usedListeners.get(listenerTypeName);
299: if (lInfo != null && --lInfo.useCount == 0)
300: usedListeners.remove(listenerTypeName);
301:
302: event.setInCEDL(false);
303: }
304: }
305:
306: private boolean addEventToMethod(Event event) {
307: String methodName = fullMethodName(event.getListenerMethod());
308: List<Event> eventList = usedMethods.get(methodName);
309:
310: if (eventList == null) {
311: eventList = new ArrayList<Event>();
312: eventList.add(event);
313: usedMethods.put(methodName, eventList);
314: } else {
315: for (Iterator it = eventList.iterator(); it.hasNext();) {
316: Event e = (Event) it.next();
317: if (e.getComponent() == event.getComponent())
318: return false; // same event, or another event of the same
319: // component with the same method signature
320: }
321: eventList.add(event);
322: }
323:
324: return true;
325: }
326:
327: private boolean removeEventFromMethod(Event event) {
328: boolean removed;
329: String methodName = fullMethodName(event.getListenerMethod());
330: List<Event> eventList = usedMethods.get(methodName);
331:
332: if (eventList != null) {
333: removed = eventList.remove(event);
334: if (eventList.size() == 0)
335: usedMethods.remove(methodName);
336: } else
337: removed = false;
338:
339: return removed;
340: }
341:
342: private void detachEventHandler(Event event, String handlerName) {
343: List<Event> handlerEventList = eventHandlers.get(handlerName);
344: handlerEventList.remove(event);
345: if (handlerEventList.size() == 0)
346: eventHandlers.remove(handlerName); // handler is not used anymore
347:
348: formModel.fireEventHandlerRemoved(event, handlerName,
349: handlerEventList.size() == 0);
350: }
351:
352: private void checkCompatibility(Event event1, Event event2) {
353: Method m1 = event1.getListenerMethod();
354: Method m2 = event2.getListenerMethod();
355: Class[] params1 = m1.getParameterTypes();
356: Class[] params2 = m2.getParameterTypes();
357: boolean ok;
358:
359: if (params1.length == params2.length) {
360: ok = true;
361: for (int i = 0; i < params1.length; i++)
362: if (!params1[i].getName().equals(params2[i].getName())) {
363: ok = false;
364: break;
365: }
366: if (ok)
367: ok = m1.getReturnType().equals(m2.getReturnType());
368: } else
369: ok = false;
370:
371: if (!ok) {
372: IllegalArgumentException iae = new IllegalArgumentException(
373: "Incompatible event"); // NOI18N
374: org.openide.ErrorManager.getDefault().annotate(iae,
375: FormUtils.getBundleString("MSG_CannotAttach")); // NOI18N
376: throw iae;
377: }
378: }
379:
380: private static String fullMethodName(Method m) {
381: StringBuffer name = new StringBuffer();
382: name.append(m.getName());
383: name.append("("); // NOI18N
384:
385: Class[] params = m.getParameterTypes();
386: for (int i = 0; i < params.length; i++) {
387: name.append(params[i].getName());
388: if (i + 1 < params.length)
389: name.append(", "); // NOI18N
390: }
391:
392: name.append(")"); // NOI18N
393: return name.toString();
394: }
395:
396: // --------
397:
398: private static class ListenerInfo {
399: Class listenerType;
400: int useCount;
401:
402: ListenerInfo(Class listenerType) {
403: this.listenerType = listenerType;
404: }
405: }
406: }
|