|
1 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 package com.symbian.smt.gui.builder; |
|
17 |
|
18 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.BORDER_SHAPES_FILES; |
|
19 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.BORDER_STYLES_FILES; |
|
20 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.COLOURS_FILES; |
|
21 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.COPYRIGHT_TEXT; |
|
22 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.DEPENDENCIES_FILES; |
|
23 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.DISTRIBUTION_TEXT; |
|
24 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.FILTER_HAS_ITEMS; |
|
25 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.FIX_ITEM_SIZE; |
|
26 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.HIGHTLIGHT_CORE_OS; |
|
27 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.IGNORE_ITEMS; |
|
28 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.LEVELS_FILES; |
|
29 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.LEVEL_OF_DETAIL; |
|
30 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.LOCALISATION_FILES; |
|
31 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.MODEL_NAME; |
|
32 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.MODEL_VERSION; |
|
33 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.MODEL_VERSION_TEXT; |
|
34 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.OUTPUT_FILE; |
|
35 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.PATTERNS_FILES; |
|
36 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.PRINTED_DPI; |
|
37 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.S12_XML_FILES; |
|
38 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.SHAPES_FILES; |
|
39 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.SUPPRESS_MOUSE_OVER_EFFECT; |
|
40 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.SYSTEM_DEFINITION_FILES; |
|
41 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.SYSTEM_INFO_FILES; |
|
42 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.SYSTEM_NAME; |
|
43 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.SYSTEM_VERSION; |
|
44 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.TEMPDIR; |
|
45 import static com.symbian.smt.gui.builder.SystemModelGeneratorEnumsForCLI.WARNING_LEVEL; |
|
46 |
|
47 import java.io.File; |
|
48 import java.io.IOException; |
|
49 import java.util.ArrayList; |
|
50 import java.util.List; |
|
51 import java.util.Locale; |
|
52 import java.util.ResourceBundle; |
|
53 import java.util.regex.Matcher; |
|
54 import java.util.regex.Pattern; |
|
55 |
|
56 import javax.xml.parsers.ParserConfigurationException; |
|
57 |
|
58 import org.eclipse.core.resources.IFolder; |
|
59 import org.eclipse.core.resources.IProject; |
|
60 import org.eclipse.core.resources.ProjectScope; |
|
61 import org.eclipse.core.runtime.preferences.DefaultScope; |
|
62 import org.eclipse.core.runtime.preferences.IEclipsePreferences; |
|
63 import org.eclipse.core.runtime.preferences.IScopeContext; |
|
64 import org.eclipse.core.runtime.preferences.InstanceScope; |
|
65 import org.eclipse.swt.widgets.Display; |
|
66 import org.xml.sax.SAXException; |
|
67 |
|
68 import com.symbian.smt.gui.Activator; |
|
69 import com.symbian.smt.gui.Logger; |
|
70 import com.symbian.smt.gui.PersistentDataStore; |
|
71 import com.symbian.smt.gui.SystemDefinition; |
|
72 import com.symbian.smt.gui.SystemDefinitionValidationException; |
|
73 import com.symbian.smt.gui.SystemDefinitionValidationFatalException; |
|
74 import com.symbian.smt.gui.views.ConsoleOutput; |
|
75 |
|
76 public class SMTCommand { |
|
77 |
|
78 private static String SMG_FOLDER = ""; // The location of the System Model |
|
79 // Generator |
|
80 private static String SMT_COMMAND = ""; // The perl script to run for the |
|
81 // System Model Generator |
|
82 final static String TEMP_FOLDER = ".svg_temp"; // Folder names stating with |
|
83 // a . will not be displayed |
|
84 // in the project navigator |
|
85 private IFolder svgTempFolder; |
|
86 private IProject project; |
|
87 private ArrayList<String> command = new ArrayList<String>();; |
|
88 |
|
89 private PersistentDataStore defaultStore; |
|
90 private PersistentDataStore instanceStore; |
|
91 private PersistentDataStore projectStore; |
|
92 |
|
93 private Pattern ampersandPattern = Pattern.compile("&", |
|
94 Pattern.CASE_INSENSITIVE); |
|
95 private Pattern lessThanPattern = Pattern.compile("<", |
|
96 Pattern.CASE_INSENSITIVE); |
|
97 private Pattern greaterThanPattern = Pattern.compile(">", |
|
98 Pattern.CASE_INSENSITIVE); |
|
99 private Pattern singleQuotePattern = Pattern.compile("'", |
|
100 Pattern.CASE_INSENSITIVE); |
|
101 private Pattern doubleQuotePattern = Pattern.compile("\"", |
|
102 Pattern.CASE_INSENSITIVE); |
|
103 |
|
104 public SMTCommand(IProject project) { |
|
105 this.project = project; |
|
106 svgTempFolder = project.getFolder(TEMP_FOLDER); |
|
107 |
|
108 final ResourceBundle resourceBundle = ResourceBundle.getBundle( |
|
109 "location", Locale.getDefault(), this.getClass() |
|
110 .getClassLoader()); |
|
111 |
|
112 SMG_FOLDER = resourceBundle.getString("location"); |
|
113 |
|
114 try { |
|
115 SMT_COMMAND = new File(SMG_FOLDER + File.separator + "SysModGen.pl") |
|
116 .getCanonicalPath(); |
|
117 } catch (IOException e) { |
|
118 Logger.log(e.getMessage(), e); |
|
119 } |
|
120 } |
|
121 |
|
122 /** |
|
123 * Generates the command line string for the System Model Toolkit |
|
124 * |
|
125 * @return List<String> Arguments for the CLI |
|
126 */ |
|
127 public List<String> generateCommand() { |
|
128 // Set up access to the persistent data stores |
|
129 IScopeContext defaultScope = new DefaultScope(); |
|
130 IEclipsePreferences defaultNode = defaultScope |
|
131 .getNode(Activator.PLUGIN_ID); |
|
132 defaultStore = new PersistentDataStore(defaultNode); |
|
133 |
|
134 IScopeContext instanceScope = new InstanceScope(); |
|
135 IEclipsePreferences instanceNode = instanceScope |
|
136 .getNode(Activator.PLUGIN_ID); |
|
137 instanceStore = new PersistentDataStore(instanceNode, defaultNode); |
|
138 |
|
139 IScopeContext projectScope = new ProjectScope(project); |
|
140 IEclipsePreferences projectNode = projectScope |
|
141 .getNode(Activator.PLUGIN_ID); |
|
142 projectStore = new PersistentDataStore(projectNode); |
|
143 |
|
144 // Required to use the SMT script |
|
145 command.add("perl"); |
|
146 command.add(SMT_COMMAND); |
|
147 |
|
148 // Add the system definition files |
|
149 String[] sysDefFiles = projectStore.getSystemDefinitionFiles(); |
|
150 |
|
151 // The while loop below protects against concurrency conditions which |
|
152 // are encountered when the sys def file is a URL resource and |
|
153 // when we are creating a new project via the NewSMTProjectWizard. |
|
154 while (sysDefFiles.length == 0) { |
|
155 try { |
|
156 Thread.sleep(10); |
|
157 } catch (InterruptedException ignore) { |
|
158 } |
|
159 |
|
160 sysDefFiles = projectStore.getSystemDefinitionFiles(); |
|
161 } |
|
162 |
|
163 command.add(SYSTEM_DEFINITION_FILES.arg()); |
|
164 |
|
165 // Check that the system definition files are valid |
|
166 // Only fatal errors cause the build attempt to be aborted. |
|
167 // |
|
168 for (String filename : sysDefFiles) { |
|
169 try { |
|
170 SystemDefinition.checkValidSystemDefinitionFile(filename); |
|
171 } catch (SystemDefinitionValidationFatalException e1) { |
|
172 writeToConsoleOutput("Error: " + filename |
|
173 + " is not a valid system definition file:\n" |
|
174 + e1.getMessage()); |
|
175 Logger.log("Validation of system definition file ("+filename+") failed.", e1); |
|
176 return null; |
|
177 } catch (SystemDefinitionValidationException e1) { |
|
178 Logger.log("Validation of system definition file ("+filename+") failed.", e1); |
|
179 } |
|
180 } |
|
181 |
|
182 // There may be multiple system definition files, if there are they need |
|
183 // to be joined with a , |
|
184 if (sysDefFiles.length == 1) { |
|
185 command.add(prepareArg(sysDefFiles[0])); |
|
186 } else { |
|
187 StringBuilder sysDefJoined = new StringBuilder(); |
|
188 |
|
189 for (String file : sysDefFiles) { |
|
190 sysDefJoined.append(file); |
|
191 sysDefJoined.append(","); |
|
192 } |
|
193 |
|
194 command.add(prepareArg(sysDefJoined.toString())); |
|
195 } |
|
196 |
|
197 // Add the resources |
|
198 // Default files in this context mean file the user selected |
|
199 handleResource(SHAPES_FILES, projectStore.getSelectedShapesFiles()); |
|
200 handleResource(LEVELS_FILES, projectStore.getSelectedLevelsFiles()); |
|
201 handleResource(SYSTEM_INFO_FILES, projectStore |
|
202 .getSelectedSystemInfoFiles()); |
|
203 handleResource(DEPENDENCIES_FILES, projectStore |
|
204 .getSelectedDependenciesFiles()); |
|
205 handleResource(COLOURS_FILES, projectStore.getSelectedColoursFiles()); |
|
206 handleResource(BORDER_SHAPES_FILES, projectStore |
|
207 .getSelectedBorderShapesFiles()); |
|
208 handleResource(PATTERNS_FILES, projectStore.getSelectedPatternsFiles()); |
|
209 handleResource(LOCALISATION_FILES, projectStore |
|
210 .getSelectedLocalisationFiles()); |
|
211 handleResource(BORDER_STYLES_FILES, projectStore |
|
212 .getSelectedBorderStylesFiles()); |
|
213 handleResource(S12_XML_FILES, projectStore.getSelectedS12XmlFiles()); |
|
214 |
|
215 // Add the model labels |
|
216 command.add(COPYRIGHT_TEXT.arg()); |
|
217 command.add(prepareArg(projectStore.getCopyrightText())); |
|
218 |
|
219 command.add(SYSTEM_NAME.arg()); |
|
220 command.add(prepareArg(projectStore.getSystemName())); |
|
221 |
|
222 command.add(DISTRIBUTION_TEXT.arg()); |
|
223 command.add(prepareArg(projectStore.getSelectedDistributionText())); |
|
224 |
|
225 command.add(MODEL_NAME.arg()); |
|
226 command.add(prepareArg(projectStore.getModelName())); |
|
227 |
|
228 command.add(MODEL_VERSION.arg()); |
|
229 command.add(prepareArg(projectStore.getModelVersion())); |
|
230 |
|
231 command.add(MODEL_VERSION_TEXT.arg()); |
|
232 command.add(prepareArg(projectStore.getSelectedModelVersionText())); |
|
233 |
|
234 command.add(SYSTEM_VERSION.arg()); |
|
235 command.add(prepareArg(projectStore.getSystemVersion())); |
|
236 |
|
237 // Add the model control settings |
|
238 command.add(HIGHTLIGHT_CORE_OS.arg()); |
|
239 if (projectStore.getHighlightCoreOS().toString().equalsIgnoreCase( |
|
240 "true")) { |
|
241 command.add("on"); |
|
242 } else { |
|
243 command.add("false"); |
|
244 } |
|
245 |
|
246 command.add(LEVEL_OF_DETAIL.arg()); |
|
247 command.add(prepareArg(projectStore.getLevelOfDetail())); |
|
248 |
|
249 String dpi = projectStore.getSelectedPrintedDpi(); |
|
250 |
|
251 // The dpi option is to be added only if the user |
|
252 // selected or typed in an option other than "" |
|
253 if ((dpi != null) && (!dpi.equals(""))) { |
|
254 command.add(PRINTED_DPI.arg()); |
|
255 command.add(prepareArg(dpi)); |
|
256 } |
|
257 |
|
258 if (projectStore.getSuppressMouseOverEffect()) { |
|
259 command.add(SUPPRESS_MOUSE_OVER_EFFECT.arg()); |
|
260 } |
|
261 |
|
262 // The fix item size option is to be added only if the user |
|
263 // checked the corresponding check box |
|
264 if (projectStore.getFixItemSize()) { |
|
265 command.add(FIX_ITEM_SIZE.arg()); |
|
266 command.add("fixed"); |
|
267 } |
|
268 |
|
269 // Filter has Items |
|
270 command.add(FILTER_HAS_ITEMS.arg()); |
|
271 |
|
272 String[] filterHasItems = projectStore.getFilterHasItems(); |
|
273 |
|
274 // No command line argument if there are no filter-has keywords |
|
275 // If there are multiple filter has items, they need to be joined with a |
|
276 // , |
|
277 if (filterHasItems.length > 0) { |
|
278 if (filterHasItems.length == 1) { |
|
279 command.add(prepareArg(filterHasItems[0])); |
|
280 } else { |
|
281 StringBuilder filterItemsJoined = new StringBuilder(); |
|
282 |
|
283 for (String filter : filterHasItems) { |
|
284 filterItemsJoined.append(filter); |
|
285 filterItemsJoined.append(","); |
|
286 } |
|
287 |
|
288 filterItemsJoined.deleteCharAt(filterItemsJoined.length() - 1); |
|
289 command.add(prepareArg(filterItemsJoined.toString())); |
|
290 } |
|
291 } |
|
292 |
|
293 // Ignore Items |
|
294 List<String[]> ignoreItems = projectStore.getIgnoreItems(); |
|
295 |
|
296 StringBuilder ignoreItemsJoined = new StringBuilder(); |
|
297 |
|
298 for (String[] ignoreItem : ignoreItems) { |
|
299 ignoreItemsJoined.append(ignoreItem[0]); |
|
300 ignoreItemsJoined.append(":"); |
|
301 ignoreItemsJoined.append(ignoreItem[1]); |
|
302 ignoreItemsJoined.append(";"); |
|
303 } |
|
304 |
|
305 command.add(IGNORE_ITEMS.arg()); |
|
306 command.add(prepareArg(ignoreItemsJoined.toString())); |
|
307 |
|
308 // Set the temp folder to use |
|
309 command.add(TEMPDIR.arg()); |
|
310 command.add(prepareArg(svgTempFolder.getLocation().toString())); |
|
311 |
|
312 // Set the warning level |
|
313 command.add(WARNING_LEVEL.arg()); |
|
314 command.add(instanceStore.getWarningLevel()); |
|
315 |
|
316 // Set the output name |
|
317 command.add(OUTPUT_FILE.arg()); |
|
318 |
|
319 File file = new File(project.getLocationURI().getPath()); |
|
320 command.add(file.getAbsolutePath() + File.separator |
|
321 + projectStore.getOutputFilename()); |
|
322 |
|
323 // Advanced Options |
|
324 // They are added at the very end of the command line and only if |
|
325 // defined by the user. |
|
326 String[] options = projectStore.getAdvancedOptions(); |
|
327 |
|
328 if ((options != null) && (options.length > 0)) { |
|
329 for (String option : options) { |
|
330 command.addAll(prepareAdvancedOption(option.trim())); |
|
331 } |
|
332 } |
|
333 |
|
334 return command; |
|
335 } |
|
336 |
|
337 |
|
338 private List<String> prepareAdvancedOption(String option) { |
|
339 List<String> options = new ArrayList<String>(); |
|
340 |
|
341 String optionValue = null; |
|
342 String argumentValue = null; |
|
343 |
|
344 if (option.indexOf(" ") > 0) { |
|
345 optionValue = option.substring(0, option.indexOf(" ")); |
|
346 argumentValue = option.substring(option.indexOf(" ")).trim(); |
|
347 } else { |
|
348 optionValue = option; |
|
349 } |
|
350 |
|
351 while (optionValue.startsWith("-")) { |
|
352 optionValue = optionValue.substring(1); |
|
353 } |
|
354 |
|
355 options.add("--" + optionValue); |
|
356 |
|
357 if (argumentValue != null && argumentValue.length() != 0) { |
|
358 options.add(argumentValue); |
|
359 } |
|
360 |
|
361 return options; |
|
362 } |
|
363 |
|
364 private void handleResource(SystemModelGeneratorEnumsForCLI option, |
|
365 String[] selectedFiles) { |
|
366 // In the cases below where we have no selected files, we need to define |
|
367 // a "" string for compatibility with SMG, which does not like an empty array. |
|
368 switch (option) { |
|
369 case BORDER_SHAPES_FILES: |
|
370 case BORDER_STYLES_FILES: |
|
371 case COLOURS_FILES: |
|
372 case LOCALISATION_FILES: |
|
373 case PATTERNS_FILES: |
|
374 case SHAPES_FILES: |
|
375 case SYSTEM_INFO_FILES: |
|
376 if (selectedFiles.length == 0) { |
|
377 selectedFiles = new String[1]; |
|
378 selectedFiles[0] = "\"\""; |
|
379 } |
|
380 |
|
381 break; |
|
382 |
|
383 case LEVELS_FILES: |
|
384 if (selectedFiles.length == 0) { |
|
385 selectedFiles = new String[1]; |
|
386 selectedFiles[0] = "\"\""; |
|
387 } else { |
|
388 if (selectedFiles[0].equals("Auto")) { |
|
389 selectedFiles = new String[] {}; |
|
390 } |
|
391 } |
|
392 |
|
393 break; |
|
394 |
|
395 case DEPENDENCIES_FILES: |
|
396 case S12_XML_FILES: |
|
397 if (selectedFiles.length == 0) { |
|
398 selectedFiles = new String[] {}; |
|
399 } |
|
400 |
|
401 break; |
|
402 |
|
403 default: |
|
404 throw new IllegalArgumentException("Unknown option [" + option |
|
405 + "]"); |
|
406 |
|
407 } |
|
408 |
|
409 for (String file : selectedFiles) { |
|
410 command.add(option.arg()); |
|
411 command.add((file.equals("\"\"")) ? file : prepareArg(file)); |
|
412 } |
|
413 } |
|
414 |
|
415 private String prepareArg(String arg) { |
|
416 // Escape any XML entities |
|
417 arg = replace(arg, ampersandPattern.matcher(arg), "&"); |
|
418 arg = replace(arg, lessThanPattern.matcher(arg), "<"); |
|
419 arg = replace(arg, greaterThanPattern.matcher(arg), ">"); |
|
420 arg = replace(arg, singleQuotePattern.matcher(arg), "'"); |
|
421 arg = replace(arg, doubleQuotePattern.matcher(arg), """); |
|
422 arg = arg.trim(); |
|
423 |
|
424 // Escape any unicode characters |
|
425 StringBuffer result = new StringBuffer(); |
|
426 |
|
427 // Get chars as characters may be multibyte |
|
428 for (char theChar : arg.toCharArray()) { |
|
429 if ((int) theChar > 127) { |
|
430 // Turn into XML unicode entity |
|
431 result.append("&#x" + Integer.toHexString((int) theChar) + ";"); |
|
432 } else { |
|
433 // Characters < 128 should be the same in all code pages, we |
|
434 // don't escape these for aesthetic reasons |
|
435 result.append(theChar); |
|
436 } |
|
437 } |
|
438 |
|
439 return "\"" + result.toString() + "\""; |
|
440 } |
|
441 |
|
442 private String replace(String arg, Matcher m, String replacement) { |
|
443 m.reset(); |
|
444 |
|
445 StringBuffer result = new StringBuffer(); |
|
446 |
|
447 while (m.find()) { |
|
448 m.appendReplacement(result, replacement); |
|
449 } |
|
450 |
|
451 m.appendTail(result); |
|
452 |
|
453 return result.toString(); |
|
454 } |
|
455 |
|
456 private void writeToConsoleOutput(final String string) { |
|
457 // Writes a string to the console output view |
|
458 |
|
459 Display.getDefault().asyncExec(new Runnable() { |
|
460 public void run() { |
|
461 ConsoleOutput.addText(string); |
|
462 } |
|
463 }); |
|
464 } |
|
465 } |