1
2
3
4
5
6
7
8
9
10
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.");
64 this.namespaces = namespaces;
65 this.nsManager = nsManager;
66
67 composite = new Composite(parent, SWT.NONE);
68 GridLayout layout = new GridLayout(2, false);
69 composite.setLayout(layout);
70
71 for (String namespace : namespaces) {
72 Label namespaceMarkLabel = new Label(composite, SWT.NONE);
73 namespaceMarkLabel.setText(Messages.getString("NAMESPACE_MARK"));
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"));
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
123
124
125 public void widgetDisposed(DisposeEvent e) {
126 Text sender = (Text) e.widget;
127 prefixes.put(namespace, sender.getText());
128 }
129 }
130
131
132
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
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.");
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
197
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
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"));
218 }
219
220 for (String namespace : map.keySet()) {
221 String prefix = map.get(namespace);
222
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)));
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
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
261
262
263 public Map<String, String> getState() {
264 return getPrefixes();
265 }
266
267
268
269
270 public Class< ? > getStateClass() {
271 return Map.class;
272 }
273
274
275
276
277 public void setState(Object state) {
278 throw new UnsupportedOperationException();
279 }
280 }