View Javadoc

1   /*
2   	Copyright (c) 2009 Olivier Chafik, All Rights Reserved
3   	
4   	This file is part of JNAerator (http://jnaerator.googlecode.com/).
5   	
6   	JNAerator is free software: you can redistribute it and/or modify
7   	it under the terms of the GNU Lesser General Public License as published by
8   	the Free Software Foundation, either version 3 of the License, or
9   	(at your option) any later version.
10  	
11  	JNAerator is distributed in the hope that it will be useful,
12  	but WITHOUT ANY WARRANTY; without even the implied warranty of
13  	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  	GNU Lesser General Public License for more details.
15  	
16  	You should have received a copy of the GNU Lesser General Public License
17  	along with JNAerator.  If not, see <http://www.gnu.org/licenses/>.
18  */
19  package com.ochafik.lang.jnaerator.studio;
20  
21  import java.awt.BorderLayout;
22  import java.awt.Component;
23  import java.awt.Dimension;
24  import java.awt.GridLayout;
25  import java.awt.event.ActionEvent;
26  import java.awt.event.ActionListener;
27  import java.awt.event.InputEvent;
28  import java.awt.event.ItemEvent;
29  import java.awt.event.ItemListener;
30  import java.awt.event.KeyEvent;
31  import java.awt.event.MouseAdapter;
32  import java.awt.event.MouseEvent;
33  import java.awt.event.MouseWheelEvent;
34  import java.awt.event.MouseWheelListener;
35  import java.awt.event.WindowAdapter;
36  import java.awt.event.WindowEvent;
37  import java.io.File;
38  import java.io.IOException;
39  import java.io.PrintStream;
40  import java.io.PrintWriter;
41  import java.io.StringWriter;
42  import java.net.URL;
43  import java.util.ArrayList;
44  import java.util.prefs.Preferences;
45  
46  import javax.swing.AbstractAction;
47  import javax.swing.Action;
48  import javax.swing.BorderFactory;
49  import javax.swing.Box;
50  import javax.swing.JButton;
51  import javax.swing.JCheckBox;
52  import javax.swing.JComboBox;
53  import javax.swing.JComponent;
54  import javax.swing.JFrame;
55  import javax.swing.JLabel;
56  import javax.swing.JOptionPane;
57  import javax.swing.JPanel;
58  import javax.swing.JProgressBar;
59  import javax.swing.JScrollPane;
60  import javax.swing.JSplitPane;
61  import javax.swing.JTabbedPane;
62  import javax.swing.JTextArea;
63  import javax.swing.JTextField;
64  import javax.swing.JToolBar;
65  import javax.swing.JTree;
66  import javax.swing.SwingUtilities;
67  import javax.swing.UIManager;
68  import javax.swing.event.DocumentEvent;
69  import javax.swing.event.TreeSelectionEvent;
70  import javax.swing.event.TreeSelectionListener;
71  import javax.swing.tree.TreePath;
72  
73  import com.ochafik.io.JTextAreaOutputStream;
74  import com.ochafik.io.ReadText;
75  import com.ochafik.io.WriteText;
76  import com.ochafik.lang.SyntaxUtils;
77  import com.ochafik.lang.compiler.MemoryFileManager;
78  import com.ochafik.lang.jnaerator.ClassOutputter;
79  import com.ochafik.lang.jnaerator.JNAerator;
80  import com.ochafik.lang.jnaerator.JNAeratorCommandLineArgs;
81  import com.ochafik.lang.jnaerator.JNAeratorConfig;
82  import com.ochafik.lang.jnaerator.Result;
83  import com.ochafik.lang.jnaerator.SourceFiles;
84  import com.ochafik.lang.jnaerator.JNAerator.Feedback;
85  import com.ochafik.swing.SimpleDocumentAdapter;
86  import com.ochafik.swing.UndoRedoUtils;
87  import com.ochafik.swing.syntaxcoloring.CCTokenMarker;
88  import com.ochafik.swing.syntaxcoloring.JEditTextArea;
89  import com.ochafik.swing.syntaxcoloring.JavaTokenMarker;
90  import com.ochafik.swing.syntaxcoloring.TokenMarker;
91  import com.ochafik.util.SystemUtils;
92  import com.ochafik.util.listenable.ListenableCollections;
93  import com.ochafik.util.listenable.ListenableComboModel;
94  import com.ochafik.util.listenable.ListenableList;
95  
96  /*
97  include com/ochafik/lang/jnaerator/examples/*.h
98   */
99  /// https://jna.dev.java.net/servlets/ReadMsg?list=users&msgNo=1988
100 @SuppressWarnings("serial")
101 public class JNAeratorStudio extends JPanel {
102 	private static final long serialVersionUID = -6061806156049213635L;
103 	private static final String PREF_RADIX = "JNAeratorStudio.";
104 	JEditTextArea sourceArea = textArea(new JavaTokenMarker());
105 	JEditTextArea resultArea = textArea(new CCTokenMarker());
106 	JTextField libraryName = new JTextField("test");
107 	JLabel classCountLabel = new JLabel("JNAerated class :");
108 //	JList resultsList = new JList();
109 	JComboBox resultsListCombo = new JComboBox();
110 	JCheckBox directCallingCb = new JCheckBox("Direct Calling (experimental)", false),
111 		structsAsTopLevelClassesCb = new JCheckBox("Structs as Top-Level classes", true),
112 		noCommentNoManglingCb = new JCheckBox("No comment & no mangling", false);
113 		
114 	JTextArea errorsArea = new JTextArea();
115 	JSplitPane sp;
116 	ListenableList<ResultContent> results = ListenableCollections.listenableList(new ArrayList<ResultContent>());
117 	MemoryFileManager memoryFileManager;
118 	static MouseWheelListener mouseWheelListener = new MouseWheelListener() {
119 
120 		@Override
121 		public void mouseWheelMoved(MouseWheelEvent e) {
122 			JEditTextArea ta = SyntaxUtils.as(e.getSource(), JEditTextArea.class);
123 			if (ta == null)
124 				return;
125 			
126 			int line = ta.getFirstLine();
127 			if (e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL) {
128 				int u = e.getUnitsToScroll();
129 				line += u > 0 ? 1 : -1;
130 				if (line < 0)
131 					line = 0;
132 				else if (line >= ta.getLineCount())
133 					line = ta.getLineCount() - 1;
134 				
135 				ta.setFirstLine(line);
136 			}
137 		}
138 		
139 	};
140 	public void error(String title, String message, Throwable th) {
141 		error(this, title, message, th);
142 	}
143 	public static void error(Component parent, String title, String message, Throwable th) {
144 		StringWriter sw = new StringWriter();
145 		th.printStackTrace(new PrintWriter(sw));
146 		JScrollPane jsp = new JScrollPane(new JTextArea(sw.toString())) {
147 			public Dimension getMaximumSize() {
148 				return new Dimension(500, 500);
149 			};
150 		};
151 //		jsp.setMaximumSize(new Dimension(500, 500));
152 		JOptionPane.showMessageDialog(
153 			parent,
154 			new Object[] {
155 				message, 
156 				jsp
157 			},
158 			title == null ? "JNAerator Error" : title,
159 			-1
160 		);
161 	}
162 	public File getDir(String name) {
163 		File dir = new File(getDir(), name);
164 		dir.mkdirs();
165 		return dir;
166 	}
167 	public File getDir() {
168 		File dir = new File(System.getProperty("user.home"));
169 		dir = new File(dir, ".jnaeratorStudio");
170 		dir = new File(dir, "pad");
171 		dir.mkdirs();
172 		return dir;
173 	}
174 	public File getInputFile() {
175 		return new File(getDir(), "input.h");
176 	}
177 	public File getOutputJarFile() {
178 		String lib = libraryName.getText().trim();
179 		if (lib.length() == 0)
180 			lib = "out";
181 		return new File(getDir(), lib + ".jar");
182 	}
183 	void save() throws IOException {
184 		WriteText.writeText(sourceArea.getText(), getInputFile());
185 	}
186 	static JEditTextArea textArea(TokenMarker marker) {
187 		JEditTextArea ta = new JEditTextArea() {
188 			private static final long serialVersionUID = 1L;
189 //			int lastCode, lastLocation;
190 //			char lastChar = 0;
191 			
192 			@Override
193 			public void processKeyEvent(KeyEvent evt) {
194 				if (SystemUtils.isMacOSX()) {
195 					int m = evt.getModifiers();
196 					if ((m & InputEvent.META_MASK) != 0) {
197 						m = (m & ~InputEvent.META_MASK) | InputEvent.CTRL_MASK;
198 						evt = new KeyEvent(evt.getComponent(), evt.getID(), evt.getWhen(), m, evt.getKeyCode(), evt.getKeyChar(), evt.getKeyLocation());
199 						if (evt.getID() == KeyEvent.KEY_TYPED)
200 							return;
201 					}
202 				}
203 				
204 				super.processKeyEvent(evt);
205 			}
206 			@Override
207 			public Dimension getMinimumSize() {
208 				return new Dimension(100, 100);
209 			}
210 		};
211 		ta.setBorder(BorderFactory.createLoweredBevelBorder());
212 		ta.setFocusTraversalKeysEnabled(false);
213 		ta.addMouseWheelListener(mouseWheelListener);
214 		ta.setPreferredSize(new Dimension(200, 300));
215 		ta.setTokenMarker(marker);
216 		return ta;
217 	}
218 	//static final File FILE = new File(".jnaeratorStudio.cpp");
219 	
220 	public void close() {
221 		try {
222 			save();
223 		} catch (Exception ex) {
224 			error(null, "Error while closing", ex);
225 		}
226 	}
227 	JTabbedPane sourceTabs = new JTabbedPane(JTabbedPane.TOP), resultTabs = new JTabbedPane(JTabbedPane.TOP);
228 	//JButton actButton = new JButton("JNAerate !");
229 	
230 	void switchOrientation() {
231 		boolean hor = sp.getOrientation() == JSplitPane.HORIZONTAL_SPLIT;
232 		int l = sp.getDividerLocation(), d = hor ? sp.getWidth() : sp.getHeight();
233 		sp.setOrientation(hor ? JSplitPane.VERTICAL_SPLIT : JSplitPane.HORIZONTAL_SPLIT);
234 		if (d != 0)
235 			sp.setDividerLocation(l / (double)d);
236 	}
237 	
238 	Action 
239 		switchOrientationAction = new AbstractAction("Switch Orientation") {
240 			@Override
241 			public void actionPerformed(ActionEvent e) {
242 				switchOrientation();
243 			}
244 		},
245 		generateAction = new AbstractAction("JNAerate !") {
246 			@Override
247 			public void actionPerformed(ActionEvent e) {
248 				generate();
249 				generateButton.requestFocus();
250 			}
251 		},
252 		aboutJNAeratorAction = new AbstractAction("About JNAerator") {
253 			@Override
254 			public void actionPerformed(ActionEvent e) {
255 				try {
256 					URL url = new URL("http://code.google.com/p/jnaerator/wiki/AboutJNAerator");
257 					System.out.println("About JNAerator: " + url);
258 					SystemUtils.runSystemOpenURL(url);
259 				} catch (Exception ex) {
260 					error(null, "Error while opening about page", ex);
261 				}
262 			}
263 		},
264 		aboutJNAAction = new AbstractAction("About JNA") {
265 			@Override
266 			public void actionPerformed(ActionEvent e) {
267 				try {
268 					URL url = new URL("http://jna.dev.java.net/");
269 					System.out.println("About JNA: " + url);
270 					SystemUtils.runSystemOpenURL(url);
271 				} catch (Exception ex) {
272 					error(null, "Error while opening about page", ex);
273 				}
274 			}
275 		},
276 		showExampleAction = new AbstractAction("Open Example") {
277 			@Override
278 			public void actionPerformed(ActionEvent e) {
279 				if (sourceArea.getText().trim().length() > 0) {
280 					if (JOptionPane.showConfirmDialog(JNAeratorStudio.this, "This is going to overwrite the contents of your source text area.\nProceed ?", "Open Example", JOptionPane.OK_CANCEL_OPTION) != JOptionPane.OK_OPTION) {
281 						return;
282 					}
283 					doShowExample(true);
284 				}
285 			}
286 		}
287 	;
288 	Object lastJNAeratedArtifact;
289 	//JLabel statusLabel = new JLabel("", JLabel.RIGHT);
290 	JButton showJarButton;
291 	JPanel errorsPane = new JPanel(new BorderLayout());
292 	JProgressBar statusBar = new JProgressBar();
293 	private JButton generateButton;
294 	public JNAeratorStudio() {
295 		super(new BorderLayout());
296 		resultsListCombo.setModel(new ListenableComboModel<ResultContent>(results));
297 		
298 		//animator.setAcceleration(.2f); 
299 		//animator.setDeceleration(.2f);
300 		
301 		JToolBar tb = new JToolBar();
302 		generateButton = tb.add(generateAction);
303 		tb.add(showExampleAction);
304 		tb.add(switchOrientationAction);
305 		tb.add(aboutJNAeratorAction);
306 		tb.add(aboutJNAAction);
307 		//tb.setOrientation(JToolBar.VERTICAL);
308 		add("North", tb);
309 		
310 		sourceArea.getDocument().addDocumentListener(new SimpleDocumentAdapter() {
311 
312 			@Override
313 			public void updated(DocumentEvent e) {
314 				setReadyToJNAerate();
315 			}
316 			
317 		});
318 		
319 		add("South", statusBar);
320 		
321 		//statusBar.setBorder(BorderFactory.createLoweredBevelBorder());
322 		
323 		JComponent sourcePane = new JPanel(new BorderLayout()), resultPane = new JPanel(new BorderLayout());
324 		Box libBox = Box.createHorizontalBox();
325 		showJarButton = new JButton("Show JAR");
326 		showJarButton.setEnabled(false);
327 		showJarButton.addActionListener(new ActionListener() {
328 			@Override
329 			public void actionPerformed(ActionEvent e) {
330 				if (lastJNAeratedArtifact == null || !(lastJNAeratedArtifact instanceof File))
331 					return;
332 				
333 				File file = (File)lastJNAeratedArtifact;
334 				try {
335 					if (file.isDirectory())
336 						SystemUtils.runSystemOpenDirectory(file);
337 					else
338 						SystemUtils.runSystemOpenFileParent(file);
339 				} catch (Exception e1) {
340 					showJarButton.setEnabled(false);
341 					showJarButton.setToolTipText(e1.toString());
342 				}
343 			}
344 		});
345 		statusBar.addMouseListener(new MouseAdapter() {
346 			@Override
347 			public void mouseClicked(MouseEvent e) {
348 				if (lastJNAeratedArtifact != null && lastJNAeratedArtifact instanceof Throwable)
349 					error(null, null, (Throwable)lastJNAeratedArtifact);
350 				else
351 					generateAction.actionPerformed(null);
352 			}
353 		});
354 		libBox.add(new JLabel("Library Name :", JLabel.RIGHT));
355 		libBox.add(libraryName);
356 		
357 		
358 		Box optBox = Box.createVerticalBox();
359 		optBox.add(libBox);
360 		
361 		JPanel optPanel = new JPanel(new GridLayout(2, 2));
362 		optPanel.add(directCallingCb);
363 		optPanel.add(noCommentNoManglingCb);
364 		optPanel.add(structsAsTopLevelClassesCb);
365 		
366 		optBox.add(optPanel);
367 		for (Component c : optBox.getComponents())
368 			((JComponent)c).setAlignmentX(0);
369 		
370 		sourcePane.add("North", optBox);//raryName);
371 		sourcePane.add("Center", sourceArea);
372 		sourceTabs.addTab("Source", sourcePane);
373 		
374 		
375 		Box resChoiceBox = Box.createHorizontalBox();
376 		resChoiceBox.add(classCountLabel);
377 		resChoiceBox.add(resultsListCombo);
378 		resChoiceBox.add(showJarButton);
379 		
380 		resultPane.add("North", resChoiceBox);
381 		resultPane.add("Center", resultArea);
382 		sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, sourceTabs, resultTabs);
383 		sp.setOneTouchExpandable(true);
384 		sp.setResizeWeight(0.5);
385 		//sp.setDividerLocation(0.5);
386 		
387 		errorsPane.add("Center", new JScrollPane(errorsArea));
388 		
389 		resultTabs.add("JNAeration Results", resultPane);
390 		resultTabs.add("Logs", errorsPane);
391 		add("Center", sp);
392 		//add("Center", new JSplitPane(JSplitPane.VERTICAL_SPLIT, sp, new JScrollPane(errorsArea)));
393 
394 		resultsListCombo.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) {
395 			ResultContent c = (ResultContent)resultsListCombo.getSelectedItem();
396 			resultArea.setText(c == null ? "" : c.getContent());
397 			resultArea.scrollTo(0, 0);
398 		}});
399 		
400 		try {
401 			sourceArea.setText(ReadText.readText(getInputFile()));
402 			sourceArea.scrollTo(0, 0);
403 		} catch (Exception ex) {}
404 		
405 		if (sourceArea.getText().trim().length() == 0)
406 			doShowExample(false);
407 		
408 		UndoRedoUtils.registerNewUndoManager(sourceArea, sourceArea.getDocument());
409 	}
410 	void setReadyToJNAerate() {
411 		statusBar.setToolTipText("Click to JNAerate !");
412 		statusBar.setMaximum(1);
413 		statusBar.setMinimum(0);
414 		statusBar.setValue(0);
415 		statusBar.setStringPainted(true);
416 		statusBar.setString("Ready to JNAerate");
417 		statusBar.setIndeterminate(false);
418 	}
419 	
420 	private void doShowExample(boolean generate) {
421 
422 		try {
423 			sourceArea.setText(ReadText.readText(getClass().getClassLoader().getResourceAsStream("com/ochafik/lang/jnaerator/examples/example.h")));
424 			sourceArea.scrollTo(0, 0);
425 			if (generate)
426 				generate();
427 		} catch (Exception e1) {
428 			e1.printStackTrace();
429 		}
430 	}
431 	
432 //	interface ProgressCallbacks {
433 //		void sourcesParsed(SourceFiles sf);
434 //		void log(String s);
435 //		void filesGenerated(File outputDir);
436 //	}
437 	protected void generate() {
438 
439 		try {
440 			save();
441 		} catch (IOException e1) {
442 			error(null, "Error while saving file", e1);
443 			return;
444 		}
445 		JNAeratorStudio.this.setEnabled(false);
446 		errorsArea.setText("");
447 		results.clear();
448 		resultArea.setText("");
449 		generateAction.setEnabled(false);
450 		showJarButton.setEnabled(false);
451 		showJarButton.setToolTipText(null);
452 		statusBar.setIndeterminate(true);
453 		statusBar.setToolTipText("JNAerating...");
454 		lastJNAeratedArtifact = null;
455 		
456 		new Thread() {
457 			public void run() {
458 				JNAeratorConfig config = new JNAeratorConfig();
459 				config.outputJar = getOutputJarFile();
460 				config.compile = true;
461 				config.useJNADirectCalls = directCallingCb.isSelected();
462 				config.putTopStructsInSeparateFiles = structsAsTopLevelClassesCb.isSelected();
463 				config.noComments = config.noMangling = noCommentNoManglingCb.isSelected();
464 				config.defaultLibrary = libraryName.getText();
465 				config.libraryForElementsInNullFile = libraryName.getText();
466 //				config.addFile(getFile(), "");
467 				config.preprocessorConfig.includeStrings.add(sourceArea.getText());
468 				config.genCPlusPlus = config.genCPlusPlus || sourceArea.getText().contains("//@" + JNAeratorCommandLineArgs.OptionDef.CPlusPlusGen.clSwitch);
469 				config.cacheDir = getDir("cache");
470 				
471 				final PrintStream out = System.out;
472 				final PrintStream err = System.err;
473 				JTextAreaOutputStream to = new JTextAreaOutputStream(errorsArea);
474 				PrintStream pto = new PrintStream(to);
475 				System.setOut(pto);
476 				System.setErr(pto);
477 				
478 				Feedback feedback = new Feedback() {
479 					
480 					@Override
481 					public void setStatus(final String string) {
482 						SwingUtilities.invokeLater(new Runnable() { public void run() {
483 							statusBar.setString(string);
484 							statusBar.setToolTipText(string);
485 						}});
486 					}
487 					
488 					@Override
489 					public void setFinished(final File toOpen) {
490 						lastJNAeratedArtifact = toOpen;
491 						SwingUtilities.invokeLater(new Runnable() { public void run() {
492 							statusBar.setToolTipText("Click to re-JNAerate !");
493 							statusBar.setString("JNAeration completed");
494 							showJarButton.setEnabled(true);
495 							showJarButton.setToolTipText(toOpen.getAbsolutePath());
496 							statusBar.setValue(statusBar.getMaximum());
497 							statusBar.setIndeterminate(false);
498 						}});
499 					}
500 
501 					@Override
502 					public void setFinished(Throwable e) {
503 						statusBar.setToolTipText("Click to examine the JNAeration error report");
504 						lastJNAeratedArtifact = e;
505 						setStatus("JNAeration failed : " + e.toString());
506 						statusBar.setValue(statusBar.getMinimum());
507 						statusBar.setIndeterminate(false);
508 						error(null, null, e);
509 					}
510 					@Override
511 					public void wrappersGenerated(final Result result) {
512 						SwingUtilities.invokeLater(new Runnable() { public void run() {
513 							if (resultsListCombo.getItemCount() > 0)
514 								resultsListCombo.setSelectedIndex(0);
515 						}});
516 					}
517 					@Override
518 					public void sourcesParsed(SourceFiles sourceFiles) {
519 						final SourceFiles sourceFilesClone = sourceFiles;
520 						SwingUtilities.invokeLater(new Runnable() { public void run() {
521 							String title = "Parsing Tree";
522 							for (int i = sourceTabs.getTabCount(); i-- != 0;) {
523 								if (title.equals(sourceTabs.getTitleAt(i))) {
524 									sourceTabs.removeTabAt(i);
525 									break;
526 								}
527 							}
528 									
529 							final JTree parsedTree = new JTree(new ElementNode(null, "ROOT", sourceFilesClone));
530 							final JEditTextArea selectionContent = textArea(new CCTokenMarker());
531 							
532 							parsedTree.addTreeSelectionListener(new TreeSelectionListener() { public void valueChanged(TreeSelectionEvent e) {
533 								TreePath selectionPath = parsedTree.getSelectionPath();
534 								AbstractNode c = selectionPath == null ? null : (AbstractNode)selectionPath.getLastPathComponent();
535 								selectionContent.setText(c == null ? "" : c.getContent());
536 								selectionContent.scrollTo(0, 0);
537 							}});
538 							JPanel parsePane = new JPanel(new BorderLayout());
539 							parsePane.add("West", new JScrollPane(parsedTree));
540 							parsePane.add("Center", selectionContent);
541 							
542 							sourceTabs.addTab(title, parsePane);
543 						}});
544 					}
545 				};
546 				try {
547 					new JNAerator(config) {
548 						public PrintWriter getClassSourceWriter(final ClassOutputter outputter, final String className) throws IOException {
549 							ResultContent c = new ResultContent(className) {
550 								protected void closed() {
551 									try {
552 										PrintWriter w = outputter.getClassSourceWriter(className);
553 										w.write(this.getContent());
554 										w.close();
555 									} catch (Exception ex) {
556 										ex.printStackTrace();
557 									}
558 								};
559 							};
560 							results.add(c);
561 							return c.getPrintWriter(); 
562 						};
563 					}.jnaerate(feedback);
564 				} finally {
565 					SwingUtilities.invokeLater(new Runnable() { public void run() {
566 						generateAction.setEnabled(true);
567 						sourceArea.scrollTo(0, 0);
568 						JNAeratorStudio.this.setEnabled(true);
569 						System.setOut(out);
570 						System.setErr(err);
571 						classCountLabel.setText("JNAerated classes (" + results.size() + ") :");
572 						setTabTitle(resultTabs, errorsPane, "Logs (" + (errorsArea.getLineCount() - 1) + " lines)");
573 						
574 					}});	
575 				}
576 			}
577 		}.start();
578 	}
579 
580 	public static class SyntaxException extends Exception {
581 		public SyntaxException(String message) {
582 			super(message);
583 		}
584 	}
585 
586 //	private void displayError(Exception e) {
587 //		JOptionPane.showMessageDialog(this, e.toString(), "Error", JOptionPane.ERROR_MESSAGE);
588 //	}
589 	private static void setTabTitle(JTabbedPane tabs, Component c, String string) {
590 		for (int i = tabs.getTabCount(); i-- != 0;) {
591 			Component tc = tabs.getComponent(i);//tabs.getTabComponentAt(i); 
592 			if (tc == c) {
593 				tabs.setTitleAt(i, string);
594 				return;
595 			}
596 				
597 		}
598 	}
599 
600 	static Preferences prefNode() {
601 		return Preferences.userNodeForPackage(JNAeratorStudio.class);
602 	}
603 	public static String getPref(String name, String defaultValue) {
604 		return prefNode().get(JNAeratorStudio.PREF_RADIX + name, defaultValue);
605 	}	
606 	public static void setPref(String name, String value) {
607 		prefNode().put(JNAeratorStudio.PREF_RADIX + name, value);
608 	}
609 	public static void setPref(String name, boolean value) {
610 		prefNode().putBoolean(JNAeratorStudio.PREF_RADIX + name, value);
611 	}
612 	public static boolean getPref(String name, boolean defaultValue) {
613 		return prefNode().getBoolean(JNAeratorStudio.PREF_RADIX + name, defaultValue);
614 	}
615 	public static void setPref(String name, double value) {
616 		prefNode().putDouble(JNAeratorStudio.PREF_RADIX + name, value);
617 	}
618 	public static double getPref(String name, double defaultValue) {
619 		return prefNode().getDouble(JNAeratorStudio.PREF_RADIX + name, defaultValue);
620 	}
621 	public static void setPref(String name, int value) {
622 		prefNode().putInt(JNAeratorStudio.PREF_RADIX + name, value);
623 	}
624 	public static int getPref(String name, int defaultValue) {
625 		return prefNode().getInt(JNAeratorStudio.PREF_RADIX + name, defaultValue);
626 	}
627 	
628 	public static void main(String[] args) {
629 		String[] prefArgs = JNAerator.getJNAeratorArgsFromPref();
630 		if (args.length > 0 || prefArgs != null)
631 		{
632 			String[] nargs = null;
633 			if (prefArgs != null)
634 				nargs = new String[0];
635 			else if (args.length == 1) {
636 				nargs = new String[] {"@", args[0], "-gui"};
637 			} else if (args.length == 2 && args[0].equals("-open")) {
638 				nargs = new String[] {"@", args[1], "-gui"};
639 			}
640 			if (nargs != null) {
641 				JNAerator.main(nargs);
642 				return;
643 			}
644 		}
645 		try {
646 			System.setProperty("apple.laf.useScreenMenuBar", "true");
647 			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
648 		} catch(Exception e) {
649 			System.out.println("Error setting native LAF: " + e);
650 		}
651 		
652 		String ver = "";
653 		try {
654 			ver = " " + ReadText.readText(JNAeratorStudio.class.getClassLoader().getResourceAsStream("VERSION"));
655 		} catch (Exception ex) {}
656 		
657 		final JFrame f = new JFrame((JNAeratorStudio.class.getSimpleName() + ver).trim());
658 		final JNAeratorStudio js = new JNAeratorStudio();
659 		f.getContentPane().add("Center", js);
660 		//f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
661 		
662 		try {
663 			js.libraryName.setText(getPref("options.libraryName", "test"));
664 			js.directCallingCb.setSelected(getPref("options.direct", false));
665 			js.structsAsTopLevelClassesCb.setSelected(getPref("options.topLevelStructs", true));
666 			js.noCommentNoManglingCb.setSelected(getPref("options.noCommentNoMangling", false));
667 			
668 			js.sp.setOrientation(getPref("splitPane.orientation", JSplitPane.HORIZONTAL_SPLIT));
669 			js.sp.setDividerLocation(getPref("splitPane.dividedLocation", 0.5));
670 			f.setSize(getPref("window.width", 800), getPref("height", 600));
671 			f.setExtendedState(getPref("window.extendedState", JFrame.NORMAL));
672 			
673 		} catch (Exception ex) {
674 			ex.printStackTrace();
675 			f.setExtendedState(JFrame.MAXIMIZED_BOTH);
676 			f.setSize(800, 800);
677 		}
678 		
679 		Runtime.getRuntime().addShutdownHook(new Thread() {
680 			public void run() {
681 				try {
682 					setPref("window.width", f.getWidth());
683 					setPref("window.height", f.getHeight());
684 					setPref("window.extendedState", f.getExtendedState());
685 					setPref("options.libraryName", js.libraryName.getText());
686 					setPref("options.direct", js.directCallingCb.isSelected());
687 					setPref("options.topLevelStructs", js.structsAsTopLevelClassesCb.isSelected());
688 					setPref("options.noCommentNoMangling", js.noCommentNoManglingCb.isSelected());
689 					setPref("splitPane.orientation", js.sp.getOrientation());
690 					setPref("splitPane.dividedLocation", getProportionalDividerLocation(js.sp));
691 					prefNode().flush();
692 				} catch (Exception ex) {
693 					ex.printStackTrace();
694 				}
695 			}
696 		});
697 		f.addWindowListener(new WindowAdapter() {
698 			@Override
699 			public void windowClosing(WindowEvent e) {
700 				System.exit(0);
701 			}
702 		});
703 		Runtime.getRuntime().addShutdownHook(new Thread() { public void run() {
704 			js.close();	
705 		}});
706 		
707 		f.setVisible(true);
708 		
709 	}
710 	protected static double getProportionalDividerLocation(JSplitPane sp) {
711 		boolean hor = sp.getOrientation() == JSplitPane.HORIZONTAL_SPLIT;
712 		int l = sp.getDividerLocation(), d = hor ? sp.getWidth() : sp.getHeight();
713 		sp.setOrientation(hor ? JSplitPane.VERTICAL_SPLIT : JSplitPane.HORIZONTAL_SPLIT);
714 		return d != 0 ? l / (double)d : 0.5;
715 	}
716 }