001: package ca.draisey.free.tprolog;
002:
003:
004:
005:
006:
007: import java.awt.BorderLayout;
008: import java.awt.event.ActionEvent;
009: import java.awt.event.ActionListener;
010: import java.awt.event.WindowAdapter;
011: import java.awt.event.WindowEvent;
012: import javax.swing.Box;
013: import javax.swing.BoxLayout;
014: import javax.swing.JButton;
015: import javax.swing.JFrame;
016: import javax.swing.JLabel;
017: import javax.swing.JTextField;
018: import javax.swing.JTextArea;
019: import javax.swing.JTree;
020: import javax.swing.JPanel;
021: import javax.swing.JScrollPane;
022: import javax.swing.JSplitPane;
023: import javax.swing.Timer;
024: import javax.swing.border.BevelBorder;
025: import javax.swing.border.SoftBevelBorder;
026: import javax.swing.text.Document;
027: import javax.swing.text.PlainDocument;
028: import javax.swing.tree.TreeModel;
029: import javax.swing.tree.DefaultTreeModel;
030: import javax.swing.tree.TreeNode;
031: import javax.swing.tree.MutableTreeNode;
032: import javax.swing.tree.DefaultMutableTreeNode;
033: import javax.swing.tree.TreePath;
034: import javax.swing.SwingUtilities;
035:
036:
037: public final class PrologNewGUI {
038:
039:
040: public static void main( final String[] argv )
041: {
042:
043: try {
044: final java.io.FileReader ginDefault = new java.io.FileReader( argv[0] );
045: final java.io.FileReader dinDefault = new java.io.FileReader( argv[1] );
046:
047: new PrologNewGUI().mainSingleton( ginDefault, dinDefault );
048: }
049: catch( java.io.FileNotFoundException x ) {
050: }
051: }
052:
053:
054:
055: final Inter interpreter = new Inter();
056:
057:
058:
059: final JFrame mainFrame = new JFrame( "Trivial Prolog" );
060: {
061: mainFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
062: mainFrame.setSize( 800, 600 );
063: }
064:
065: final JPanel mainPanel = new JPanel();
066: {
067: mainPanel.setLayout( new BorderLayout() );
068: mainFrame.getContentPane().add( mainPanel );
069: }
070:
071: final JTextField goalText = new JTextField();
072: {
073: goalText.setBorder( new SoftBevelBorder( BevelBorder.LOWERED ) );
074: goalText.addActionListener( new ActionListener() {
075: public void actionPerformed( ActionEvent e )
076: {
077: interpreter.queryGoal( goalText.getText() );
078: }
079: } );
080: }
081:
082: final JButton querButton = new JButton( "Query!" );
083: {
084: querButton.setBorder( new SoftBevelBorder( BevelBorder.RAISED ) );
085: querButton.addActionListener( new ActionListener() {
086: public void actionPerformed( ActionEvent e )
087: {
088: interpreter.queryGoal( goalText.getText() );
089: }
090: } );
091: }
092: {
093: final Box goalPanel = Box.createHorizontalBox();
094: {
095: goalPanel.add( new JLabel( "Goal:" ) );
096: goalPanel.add( goalText );
097: goalPanel.add( querButton );
098: }
099: mainPanel.add( goalPanel, BorderLayout.NORTH );
100: }
101:
102: final JTree dictTree = new JTree( new DefaultMutableTreeNode( "empty" ) );
103: {
104:
105: dictTree.setRootVisible( false );
106: dictTree.setShowsRootHandles( true );
107: }
108:
109: final JTree querTree = new JTree( new DefaultMutableTreeNode() );
110: {
111:
112: querTree.setRootVisible( false );
113: querTree.setShowsRootHandles( true );
114: }
115:
116: final DefaultTreeModel querTreeModel()
117: {
118: return (DefaultTreeModel) querTree.getModel();
119: }
120: final void querTreeReroot( DefaultMutableTreeNode rootNode )
121: {
122: querTreeModel().setRoot( rootNode );
123: }
124:
125: final JLabel querStatus = new JLabel( "ready." );
126: {
127: querStatus.setBorder( new SoftBevelBorder( BevelBorder.LOWERED ) );
128: }
129: final JButton pausButton = new JButton( "Pause!" );
130: final JButton aborButton = new JButton( "Abort!" );
131: {
132: pausButton.setBorder( new SoftBevelBorder( BevelBorder.RAISED ) );
133: pausButton.setEnabled( false );
134: pausButton.addActionListener( new ActionListener() {
135: public void actionPerformed( ActionEvent e )
136: {
137: interpreter.togglePaused();
138: }
139: } );
140: aborButton.setBorder( new SoftBevelBorder( BevelBorder.RAISED ) );
141: aborButton.setEnabled( false );
142: aborButton.addActionListener( new ActionListener() {
143: public void actionPerformed( ActionEvent e )
144: {
145: interpreter.abort();
146: }
147: } );
148: }
149: final JButton nextButton = new JButton( "Next Result!" );
150: final JButton omniButton = new JButton( "All Results!" );
151: {
152: nextButton.setBorder( new SoftBevelBorder( BevelBorder.RAISED ) );
153: nextButton.setEnabled( false );
154: nextButton.addActionListener( new ActionListener() {
155: public void actionPerformed( ActionEvent e )
156: {
157: interpreter.next();
158: }
159: } );
160: omniButton.setBorder( new SoftBevelBorder( BevelBorder.RAISED ) );
161: omniButton.setEnabled( false );
162: omniButton.addActionListener( new ActionListener() {
163: public void actionPerformed( ActionEvent e )
164: {
165: interpreter.omni();
166: }
167: } );
168: }
169:
170: final void guiStatus( String state, boolean q, boolean p, boolean r, boolean a, boolean n )
171: {
172: querStatus.setText( state );
173: querButton.setEnabled( q );
174: pausButton.setEnabled( p );
175: if( r ) pausButton.setText( "Resume!" );
176: else pausButton.setText( "Pause!" );
177: aborButton.setEnabled( a );
178: nextButton.setEnabled( n );
179: omniButton.setEnabled( n );
180: }
181:
182: {
183: final JSplitPane centerPanel = new JSplitPane();
184: centerPanel.setResizeWeight( 0.5 );
185: centerPanel.setOneTouchExpandable( true );
186: centerPanel.setContinuousLayout( true );
187: {
188: final JPanel dictPanel = new JPanel();
189:
190: dictPanel.setLayout( new BorderLayout() );
191: dictPanel.add( new JLabel( "Dictionary:" ), BorderLayout.NORTH );
192: dictPanel.add( new JScrollPane( dictTree ), BorderLayout.CENTER );
193: centerPanel.setLeftComponent( dictPanel );
194: }
195: {
196: final JPanel querPanel = new JPanel();
197:
198: querPanel.setLayout( new BorderLayout() );
199: querPanel.add( new JLabel( "Result of Query:" ), BorderLayout.NORTH );
200: querPanel.add( new JScrollPane( querTree ), BorderLayout.CENTER );
201: {
202: final Box querControls = Box.createHorizontalBox();
203: querControls.add( Box.createGlue() );
204: querControls.add( nextButton );
205: querControls.add( omniButton );
206: querPanel.add( querControls, BorderLayout.SOUTH );
207: }
208: centerPanel.setRightComponent( querPanel );
209: }
210: mainPanel.add( centerPanel, BorderLayout.CENTER );
211: }
212:
213: {
214: final Box statPanel = Box.createHorizontalBox();
215: statPanel.add( new JLabel( "Interpreter:" ) );
216: statPanel.add( querStatus );
217: statPanel.add( Box.createGlue() );
218: statPanel.add( pausButton );
219: statPanel.add( aborButton );
220: mainPanel.add( statPanel, BorderLayout.SOUTH );
221: }
222:
223:
224: final void mainSingleton( java.io.Reader ginDefault, java.io.Reader dinDefault )
225: {
226: try {
227: Parse.database( dinDefault, interpreter.database );
228: }
229: catch( IllegalArgumentException x ) {
230: }
231: ( (DefaultTreeModel) dictTree.getModel() ).setRoot( interpreter.database.viewDatabase() );
232:
233: interpreter.queryGoal( ginDefault );
234: mainFrame.setVisible( true );
235: interpreter.mainLoop();
236: }
237:
238:
239:
240: final class Inter {
241:
242:
243: final GUIDatabase database = new GUIDatabase();
244:
245:
246: Sentence runningQuery = null;
247:
248:
249: boolean shortcircuited = false;
250:
251:
252: int userState = READY;
253:
254: static final int READY = 0;
255: static final int RUNNING = 1;
256: static final int WAITING = 2;
257: static final int PAUSED = 3;
258:
259: int runningState = READY;
260:
261:
262: DefaultMutableTreeNode successNode = null;
263:
264:
265: final Runnable guiOut = new Runnable() {
266: public void run()
267: {
268: if( successNode != null ) {
269: final DefaultTreeModel qM = querTreeModel();
270: final DefaultMutableTreeNode qR = (DefaultMutableTreeNode) qM.getRoot();
271: qM.insertNodeInto( successNode, qR, qR.getChildCount() );
272: querTree.expandPath( new TreePath( successNode.getPath() ) );
273: successNode = null;
274: synchronized( Inter.this ) {
275: Inter.this.notifyAll();
276: }
277: }
278: }
279: };
280:
281: final Runnable guiRunningState = new Runnable() {
282: public void run()
283: {
284: switch( runningState ) {
285: case READY:
286: guiStatus( "ready.", true, false, false, false, false );
287: return;
288: case RUNNING:
289: guiStatus( "running.", false, true, false, true, false );
290: guiTicker.start();
291: return;
292: case WAITING:
293: guiStatus( "waiting.", false, false, false, true, true );
294: return;
295: case PAUSED:
296: guiStatus( "paused.", false, true, true, true, false );
297: return;
298: }
299: }
300: };
301:
302: final Timer guiTicker = new Timer( 1000, new ActionListener() {
303: public void actionPerformed( final ActionEvent e )
304: {
305: if( runningState == RUNNING && ticker < 10 ) {
306: querStatus.setText( querStatus.getText() + "." );
307: ++ticker;
308: }
309: else {
310: guiTicker.stop();
311: ticker = 0;
312: }
313: }
314: int ticker = 0;
315: } );
316:
317:
318:
319: final void queryGoal( final String g )
320: {
321: queryGoal( new java.io.StringReader( g ) );
322: }
323: final void queryGoal( final java.io.Reader gin )
324: {
325: try {
326: final Sentence query = Parse.goal( gin );
327: goalText.setText( query.toString() );
328: queryGoal( query );
329: }
330: catch( IllegalArgumentException x ) {
331: }
332: }
333: final synchronized void queryGoal( final Sentence query )
334: {
335: if( runningQuery == null ) {
336: final DefaultMutableTreeNode qR = new DefaultMutableTreeNode();
337: qR.add( new DefaultMutableTreeNode( query.toString(), false ) );
338: querTreeReroot( qR );
339: userState = RUNNING;
340: runningQuery = query;
341: notifyAll();
342: }
343: expandALevel( querTree );
344: }
345: final synchronized void togglePaused()
346: {
347: if( runningState == RUNNING ) {
348: userState = PAUSED;
349: guiStatus( "pausing...", false, false, true, false, false );
350: }
351: else if( runningState == PAUSED ) {
352: userState = RUNNING;
353: notifyAll();
354: }
355: }
356: final synchronized void abort()
357: {
358: userState = READY;
359: guiStatus( "aborting...", false, false, false, false, false );
360: notifyAll();
361: }
362: final synchronized void next()
363: {
364: userState = RUNNING;
365: notifyAll();
366: }
367: final synchronized void omni()
368: {
369: userState = RUNNING;
370: shortcircuited = true;
371: notifyAll();
372: }
373:
374:
375:
376: final void mainLoop()
377: {
378: mainloop: for(;;) {
379: synchronized( this ) {
380: while( runningQuery == null ) uwait();
381: runningState = RUNNING;
382: shortcircuited = false;
383: }
384: SwingUtilities.invokeLater( guiRunningState );
385: database.viewableQuery( runningQuery, database.new GUISuccession() {
386:
387: void out( final int s, final DefaultMutableTreeNode snode )
388: {
389:
390: synchronized( Inter.this ) {
391: while( successNode != null ) Inter.this.uwait();
392: }
393: successNode = snode;
394: SwingUtilities.invokeLater( guiOut );
395: }
396:
397: void next()
398: {
399: if( ! shortcircuited )
400: synchronized( Inter.this ) {
401: if( userState != READY ) {
402: userState = runningState = WAITING;
403: SwingUtilities.invokeLater( guiRunningState );
404: synchronized( Inter.this ) {
405: while( userState == WAITING ) Inter.this.uwait();
406: }
407: }
408: }
409: monitor();
410: }
411:
412: void monitor()
413: {
414: Thread.yield();
415: if( userState == PAUSED ) {
416: synchronized( Inter.this ) {
417: runningState = PAUSED;
418: SwingUtilities.invokeLater( guiRunningState );
419: synchronized( Inter.this ) {
420: while( userState == PAUSED ) Inter.this.uwait();
421: }
422: }
423: }
424: if( userState == READY ) throw new MonitorException();
425: if( runningState != RUNNING ) {
426: runningState = RUNNING;
427: SwingUtilities.invokeLater( guiRunningState );
428: }
429: }
430: } );
431: synchronized( this ) {
432: userState = runningState = READY;
433: runningQuery = null;
434: shortcircuited = false;
435: }
436: SwingUtilities.invokeLater( guiRunningState );
437: }
438:
439: }
440:
441: final void uwait()
442: {
443: try {
444: wait();
445: }
446: catch( InterruptedException x ) {
447: throw new RuntimeException( "Annoying InterruptedException", x );
448: }
449: }
450: }
451:
452:
453:
454: static void expandALevel( final JTree tree )
455: {
456: final DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree.getModel().getRoot();
457: for( int i = 0, n = root.getChildCount(); i < n; ++i ) {
458: tree.expandPath( new TreePath(
459: ( (DefaultMutableTreeNode) root.getChildAt( i ) ).getPath()
460: ) );
461: }
462: }
463: }
464:
465: