View Javadoc

1   /*
2    * Created on Mar 12, 2005. Copyright 1999-2006 Faculty of Mathematics, Physics
3    * and Informatics, Comenius University, Bratislava. This file is protected by
4    * the Mozilla Public License version 1.1 (the "License"); you may not use this
5    * file except in compliance with the License. You may obtain a copy of the
6    * License at http://euromath2.sourceforge.net/license.html Unless required by
7    * applicable law or agreed to in writing, software distributed under the
8    * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
9    * OF ANY KIND, either express or implied. See the License for the specific
10   * language governing permissions and limitations under the License.
11   */
12  package sk.uniba.euromath.editor.widgets;
13  import java.util.ArrayList;
14  import java.util.Collections;
15  import java.util.HashMap;
16  import java.util.HashSet;
17  import java.util.List;
18  import java.util.Map;
19  import java.util.Set;
20  import javax.xml.namespace.QName;
21  import org.apache.commons.lang.StringUtils;
22  import org.eclipse.swt.SWT;
23  import org.eclipse.swt.events.DisposeEvent;
24  import org.eclipse.swt.events.DisposeListener;
25  import org.eclipse.swt.events.ModifyEvent;
26  import org.eclipse.swt.events.ModifyListener;
27  import org.eclipse.swt.layout.GridData;
28  import org.eclipse.swt.layout.GridLayout;
29  import org.eclipse.swt.widgets.Composite;
30  import org.eclipse.swt.widgets.Label;
31  import org.eclipse.swt.widgets.Text;
32  import sk.uniba.euromath.document.NamespaceManager;
33  import sk.uniba.euromath.editor.lang.Messages;
34  /***
35   * Queries for new prefixes.
36   * @author Martin Vysny
37   */
38  public class NewPrefixesQuery extends AbstractUserInputWidget {
39  	/***
40  	 * Composite where all controls are placed.
41  	 */
42  	protected final Composite composite;
43  	/***
44  	 * Get prefixes for these namespaces.
45  	 */
46  	protected final Set<String> namespaces;
47  	/***
48  	 * Current namespace manager.
49  	 */
50  	protected final NamespaceManager nsManager;
51  	/***
52  	 * Constructs the component.
53  	 * @param parent the parent composite.
54  	 * @param namespaces get prefixes for these namespaces.
55  	 * @param nsManager current namespace manager. New prefixes are not
56  	 * registered here, new manager is created instead.
57  	 */
58  	public NewPrefixesQuery(Composite parent, Set<String> namespaces,
59  			NamespaceManager nsManager) {
60  		super();
61  		if (namespaces.size() == 0)
62  			throw new IllegalArgumentException(
63  					"At least one namespace must be present."); //$NON-NLS-1$
64  		this.namespaces = namespaces;
65  		this.nsManager = nsManager;
66  		// create composite
67  		composite = new Composite(parent, SWT.NONE);
68  		GridLayout layout = new GridLayout(2, false);
69  		composite.setLayout(layout);
70  		// place controls on it
71  		for (String namespace : namespaces) {
72  			Label namespaceMarkLabel = new Label(composite, SWT.NONE);
73  			namespaceMarkLabel.setText(Messages.getString("NAMESPACE_MARK")); //$NON-NLS-1$
74  			Label namespaceLabel = new Label(composite, SWT.NONE);
75  			namespaceLabel.setText(namespace);
76  			GridData data = new GridData(SWT.NONE, SWT.FILL, false, false);
77  			namespaceLabel.setLayoutData(data);
78  			Label prefixMarkLabel = new Label(composite, SWT.NONE);
79  			prefixMarkLabel.setText(Messages.getString("PREFIX_MARK")); //$NON-NLS-1$
80  			Text prefixText = new Text(composite, SWT.BORDER | SWT.SINGLE);
81  			data = new GridData(SWT.NONE, SWT.FILL, false, false);
82  			data.widthHint = 150;
83  			prefixText.setLayoutData(data);
84  			prefixText.setText(nsManager.getBestPrefix(namespace));
85  			prefixText.setEnabled(!nsManager.isBestPrefixRequired(namespace));
86  			prefixTexts.put(namespace, prefixText);
87  			prefixText.addDisposeListener(new TextDisposeListener(namespace));
88  			prefixText.addModifyListener(new ModifyListener() {
89  				public void modifyText(ModifyEvent e) {
90  					fireDataModified();
91  				}
92  			});
93  		}
94  	}
95  	/***
96  	 * Here all prefix textboxes are kept.
97  	 */
98  	protected final Map<String, Text> prefixTexts = new HashMap<String, Text>();
99  	/***
100 	 * Maps namespace URI to prefix.
101 	 */
102 	protected final Map<String, String> prefixes = new HashMap<String, String>();
103 	/***
104 	 * Dispose listener for text boxes. When disposed, registers its text to the
105 	 * <code>prefixes</code> map.
106 	 * @author Martin Vysny
107 	 */
108 	protected class TextDisposeListener implements DisposeListener {
109 		/***
110 		 * The namespace.
111 		 */
112 		public final String namespace;
113 		/***
114 		 * Constructor.
115 		 * @param namespace
116 		 */
117 		protected TextDisposeListener(String namespace) {
118 			super();
119 			this.namespace = namespace;
120 		}
121 		/*
122 		 * (non-Javadoc)
123 		 * @see org.eclipse.swt.events.DisposeListener#widgetDisposed(org.eclipse.swt.events.DisposeEvent)
124 		 */
125 		public void widgetDisposed(DisposeEvent e) {
126 			Text sender = (Text) e.widget;
127 			prefixes.put(namespace, sender.getText());
128 		}
129 	}
130 	/*
131 	 * (non-Javadoc)
132 	 * @see sk.uniba.euromath.editor.widgets.IEncapsulatesComposite#getComposite()
133 	 */
134 	public Composite getComposite() {
135 		return composite;
136 	}
137 	/***
138 	 * Returns currently selected prefixes.
139 	 * @return map that maps namespace URI to prefix, never <code>null</code>.
140 	 */
141 	public Map<String, String> getPrefixes() {
142 		Map<String, String> result = getPrefixesInternal();
143 		checkErrors(result);
144 		return result;
145 	}
146 	/***
147 	 * Returns currently selected prefixes. Does not check for errors.
148 	 * @return map that maps namespace URI to prefix, never <code>null</code>.
149 	 */
150 	public Map<String, String> getPrefixesInternal() {
151 		if (!composite.isDisposed()) {
152 			// update map with actual content.
153 			for (String namespace : prefixTexts.keySet()) {
154 				prefixes.put(namespace, prefixTexts.get(namespace).getText());
155 			}
156 		}
157 		return Collections.unmodifiableMap(prefixes);
158 	}
159 	/***
160 	 * Returns all namespaces that occurs in given list. Empty namespace is not
161 	 * in the result set - this is because empty namespace does not have prefix
162 	 * in EuroMath2.
163 	 * @param qnames set of qnames. <code>null</code>s are permitted - they
164 	 * are simply ignored.
165 	 * @return all namespaces in given list.
166 	 */
167 	public static Set<String> getNamespaces(List< ? extends QName> qnames) {
168 		Set<String> result = new HashSet<String>();
169 		for (QName qname : qnames) {
170 			if ((qname != null)
171 					&& !StringUtils.isEmpty(qname.getNamespaceURI()))
172 				result.add(qname.getNamespaceURI());
173 		}
174 		return result;
175 	}
176 	/***
177 	 * Produces a namespace manager where these new prefixes are registered.
178 	 * @return namespace manager containing new prefix mappings.
179 	 * @throws IllegalArgumentException if the page contains errors thus some
180 	 * prefixes cannot be registered.
181 	 * @throws IllegalStateException if the page contains errors thus some
182 	 * prefixes cannot be registered.
183 	 */
184 	public NamespaceManager newUpdatedManager() {
185 		Map<String, String> prefixes = getPrefixes();
186 		if (prefixes == null)
187 			throw new IllegalStateException("Errors on component."); //$NON-NLS-1$
188 		NamespaceManager child = new NamespaceManager(nsManager);
189 		for (String namespace : prefixes.keySet()) {
190 			String prefix = prefixes.get(namespace);
191 			child.declare(namespace, prefix);
192 		}
193 		return child;
194 	}
195 	/*
196 	 * (non-Javadoc)
197 	 * @see sk.uniba.euromath.editor.widgets.IUserInputWidget#validateLast()
198 	 */
199 	public ValidityMessages getMessages() {
200 		return lastMessages;
201 	}
202 	/***
203 	 * Error messages.
204 	 */
205 	protected ValidityMessages lastMessages = null;
206 	/***
207 	 * Checks data for errors.
208 	 * @param map map that maps namespace URI to prefix, must not be
209 	 * <code>null</code>.
210 	 */
211 	protected void checkErrors(Map<String, String> map) {
212 		lastMessages = null;
213 		// check if two namespaces maps to same prefixes
214 		Set<String> allPrefixes = new HashSet<String>(prefixes.values());
215 		if (allPrefixes.size() != prefixes.keySet().size()) {
216 			lastMessages = MessageLevelEnum.ERROR.newMessage(Messages
217 					.getString("MUST_USE_DIFFERENT_PREFIXES"));//$NON-NLS-1$
218 		}
219 		// check all prefixes if they are valid.
220 		for (String namespace : map.keySet()) {
221 			String prefix = map.get(namespace);
222 			// check prefix
223 			assert (nsManager.getPrefix(namespace) == null);
224 			if (!nsManager.acceptsNewPrefix(namespace, prefix)) {
225 				lastMessages = MessageLevelEnum.ERROR
226 						.setMessage(
227 								lastMessages,
228 								Messages
229 										.getString(
230 												"ILLEGAL_PREFIX_AND_SUGGESTION", prefix, nsManager.getBestPrefix(namespace))); //$NON-NLS-1$
231 			}
232 		}
233 	}
234 	/***
235 	 * Modifies the prefixes of all qnames to currently selected prefixes.
236 	 * @param qnames list of qnames to modify
237 	 * @return modified qnames
238 	 */
239 	public List<QName> setPrefixes(List<QName> qnames) {
240 		Map<String, String> prefixMap = getPrefixes();
241 		if (prefixMap.isEmpty()) {
242 			// no new prefixes, just return given list
243 			return qnames;
244 		}
245 		List<QName> result = new ArrayList<QName>(qnames.size());
246 		for (QName qname : qnames) {
247 			QName qnameToAdd = qname;
248 			if (prefixMap.containsKey(qname.getNamespaceURI())) {
249 				String prefix = prefixMap.get(qname.getNamespaceURI());
250 				if (!prefix.equals(qname.getPrefix())) {
251 					qnameToAdd = new QName(qname.getNamespaceURI(), qname
252 							.getLocalPart(), prefix);
253 				}
254 			}
255 			result.add(qnameToAdd);
256 		}
257 		return result;
258 	}
259 	/*
260 	 * (non-Javadoc)
261 	 * @see sk.uniba.euromath.editor.widgets.IUserInputWidget#getState()
262 	 */
263 	public Map<String, String> getState() {
264 		return getPrefixes();
265 	}
266 	/*
267 	 * (non-Javadoc)
268 	 * @see sk.uniba.euromath.editor.widgets.IUserInputWidget#getStateClass()
269 	 */
270 	public Class< ? > getStateClass() {
271 		return Map.class;
272 	}
273 	/*
274 	 * (non-Javadoc)
275 	 * @see sk.uniba.euromath.editor.widgets.IUserInputWidget#setState(java.lang.Object)
276 	 */
277 	public void setState(Object state) {
278 		throw new UnsupportedOperationException();
279 	}
280 }