1 /*******************************************************************************
2  * Copyright (c) 2004, 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.ui.internal;
15 
16 import static org.eclipse.swt.events.SelectionListener.widgetSelectedAdapter;
17 
18 import java.util.ArrayList;
19 import java.util.Iterator;
20 import java.util.List;
21 import org.eclipse.swt.SWT;
22 import org.eclipse.swt.events.SelectionListener;
23 import org.eclipse.swt.widgets.Menu;
24 import org.eclipse.swt.widgets.MenuItem;
25 
26 /**
27  * Represents a group of radio buttons in a menu. Each menu item is mapped onto
28  * a particular value. The RadioMenu reports its state using the attached Model
29  * object. That is, Model.getState() will return the value of the currently
30  * selected radio button and Model.setState(value) will select the radio button
31  * associated with the given value.
32  */
33 public class RadioMenu implements IChangeListener {
34 
35 	private Model data;
36 
37 	private Menu parent;
38 
39 	private List items = new ArrayList();
40 
41 	SelectionListener selectionAdapter = widgetSelectedAdapter(e -> {
42 		Object newState = e.widget.getData();
43 
44 		data.setState(newState, RadioMenu.this);
45 	});
46 
47 	/**
48 	 * Creates a set of radio menu items on the given menu.
49 	 *
50 	 * @param parent  menu that will contain the menu items
51 	 * @param newData the model that will store the value of the currently selected
52 	 *                item
53 	 */
RadioMenu(Menu parent, Model newData)54 	public RadioMenu(Menu parent, Model newData) {
55 		this.parent = parent;
56 		this.data = newData;
57 
58 		newData.addChangeListener(this);
59 	}
60 
61 	/**
62 	 * Returns true iff the given values are considered equal.
63 	 *
64 	 * @param value1
65 	 * @param value2
66 	 * @return
67 	 */
isEqual(Object value1, Object value2)68 	private static boolean isEqual(Object value1, Object value2) {
69 		if (value1 == null) {
70 			return value2 == null;
71 		} else if (value2 == null) {
72 			return false;
73 		}
74 
75 		return value1.equals(value2);
76 	}
77 
78 	/**
79 	 * Creates a new menu item with the given text and value. When the item is
80 	 * selected, the state of the model will change to match the given value.
81 	 *
82 	 * @param text
83 	 * @param value
84 	 */
addMenuItem(String text, Object value)85 	public void addMenuItem(String text, Object value) {
86 		MenuItem newItem = new MenuItem(parent, SWT.RADIO);
87 
88 		newItem.setSelection(isEqual(data.getState(), value));
89 		newItem.setText(text);
90 		newItem.setData(value);
91 		items.add(newItem);
92 
93 		newItem.addSelectionListener(selectionAdapter);
94 	}
95 
96 	/**
97 	 * Disposes all menu items
98 	 */
dispose()99 	public void dispose() {
100 		Iterator iter = items.iterator();
101 		while (iter.hasNext()) {
102 			MenuItem next = (MenuItem) iter.next();
103 
104 			if (!next.isDisposed()) {
105 				next.removeSelectionListener(selectionAdapter);
106 				next.dispose();
107 			}
108 		}
109 
110 		items.clear();
111 	}
112 
113 	/**
114 	 * Refreshes the selected menu items to match the current state of the model.
115 	 */
refreshSelection()116 	private void refreshSelection() {
117 		Iterator iter = items.iterator();
118 		while (iter.hasNext()) {
119 			MenuItem next = (MenuItem) iter.next();
120 
121 			if (!next.isDisposed()) {
122 				next.setSelection(isEqual(data.getState(), next.getData()));
123 			}
124 		}
125 	}
126 
127 	@Override
update(boolean changed)128 	public void update(boolean changed) {
129 		refreshSelection();
130 	}
131 
132 }
133