KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > neu > ccs > jmk > awt > MakeWindow


1 // $Id: MakeWindow.java,v 1.3 2002/01/28 13:06:31 ramsdell Exp $
2

3 // The make window class
4

5 /*
6  * Copyright 1997 by John D. Ramsdell
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  */

22
23 package edu.neu.ccs.jmk.awt;
24
25 import java.io.*;
26 import java.awt.*;
27 import java.awt.datatransfer.*;
28 import java.awt.event.*;
29 import java.text.DateFormat JavaDoc;
30 import java.util.*;
31 import edu.neu.ccs.jmk.*;
32
33 /**
34  * A window for displaying the results of running Make.
35  * @version November 1997
36  * @author John D. Ramsdell
37  */

38 public class MakeWindow
39 extends TextArea
40 implements ActionListener, ClipboardOwner
41 {
42   private final static String JavaDoc JMK_PROPERTIES = "jmk";
43   private final static String JavaDoc DEFAULT_FONT = "monoSpaced";
44   private final static int DEFAULT_COLUMNS = 72;
45   private final static int DEFAULT_ROWS = 22;
46
47   private final static int MAX_TEXT_AREA = 16384;
48   private final static int TRUNCATED_TEXT_AREA = MAX_TEXT_AREA / 2;
49   private final String JavaDoc nl = System.getProperty("line.separator");
50   // private final String nl = "\n"; // Which is right?
51

52   private Make make;
53   private String JavaDoc[] targets;
54   private final RunQueue tasks = new RunQueue();
55
56   /**
57    * Create a make window.
58    * @param make the make object
59    * @param targets the initial set of targets for make
60    * @param rows the number of rows
61    * @param columns the number of columns
62    */

63   MakeWindow(Make make, String JavaDoc[] targets,
64          int rows, int columns) {
65     this.make = make;
66     this.targets = targets;
67     setRows(rows);
68     setColumns(columns);
69     // Create make writer
70
make.setOut(new PrintWriter(new MakeWriter(), true));
71     new Thread JavaDoc(tasks).start();
72   }
73
74   /**
75    * This routine appends a line to the panel without breaking long lines.
76    * This routine should only be called by appendLongLine.
77    * @param line the line to be appended
78    */

79   void appendLine(String JavaDoc s) {
80     append(s + nl);
81     setCaretPosition(Integer.MAX_VALUE);
82     String JavaDoc area = getText();
83     int n = area.length(); // Truncate saved text if needed
84
if (n > MAX_TEXT_AREA) {
85       int truncSize = area.indexOf('\n', n - TRUNCATED_TEXT_AREA);
86       area = area.substring(truncSize);
87       setText(area);
88     }
89   }
90
91   /**
92    * This routine breaks long lines as they are added to the panel.
93    * This routine should only be called by a MakeWriter.
94    * @param line the line to be broken
95    */

96   void appendLongLine(String JavaDoc line) {
97     int columns = getColumns() - 5;
98     String JavaDoc prefix = ""; // String to add at start of line
99
int cc = 0; // Current column
100
int ls = 0; // Index of the last space
101
int s = 0; // Start index
102
int n = line.length(); // End index
103
for (int i = 0; i < n; i++) {
104       if (line.charAt(i) == '\n') {
105     cc = 0;
106     ls = i + 1; // Advance ls to this line
107
}
108       else if (Character.isSpaceChar(line.charAt(i))) {
109     ls = i;
110     cc++;
111       }
112       else if (cc >= columns && Character.isSpaceChar(line.charAt(ls))) {
113     appendLine(prefix + line.substring(s, ls) + " \\");
114     cc = 0; // Break a line
115
i = ls; // Reset line index here!
116
ls = i + 1; // Advance ls to this line
117
s = ls; // New start
118
prefix = " "; // Set continuation prefix
119
}
120       else
121     cc++;
122     }
123     if (s < n) { // Insert the remainder
124
appendLine(prefix + line.substring(s, n));
125     }
126   }
127
128   class MakeWriter
129   extends Writer
130   {
131     StringBuffer JavaDoc buffer = new StringBuffer JavaDoc(DEFAULT_COLUMNS);
132     boolean eol = false;
133     boolean closed = false;
134
135     public void write (char cbuf[], int off, int len)
136      throws IOException
137     {
138       if (closed)
139     throw new IOException("Write of a closed writer");
140       for (int i = off; i < len; i++) {
141     char ch = cbuf[i];
142     if (eol) {
143       eol = false;
144       if (ch == '\n')
145         continue;
146     }
147     if (ch == '\n' || ch == '\r') {
148       if (ch == '\r')
149         eol = true;
150       appendLongLine(buffer.toString());
151       buffer.setLength(0);
152     }
153     else {
154       buffer.append(ch);
155     }
156       }
157     }
158
159     public void flush()
160      throws IOException
161     {
162       if (closed)
163     throw new IOException("Flush of a closed writer");
164     }
165
166     public void close()
167      throws IOException
168     {
169       if (!closed) {
170     flush();
171     closed = true;
172       }
173     }
174   }
175
176   private String JavaDoc cachedTargetString;
177
178   /**
179    * Handle input from the input window.
180    * Sets the target list and then starts a make.
181    * @see edu.neu.ccs.jmk.awt.MakeInput
182    */

183   public void actionPerformed(ActionEvent e) {
184     String JavaDoc targetString = e.getActionCommand().trim();
185     if (!cachedTargetString.equals(targetString)) {
186       cachedTargetString = targetString;
187       targets = string2String_array(targetString);
188     }
189     make();
190   }
191
192   /**
193    * Break a string into an array of strings.
194    * A space character marks a breaking point.
195    */

196   private static String JavaDoc[] string2String_array(String JavaDoc str) {
197     Vector v = new Vector();
198     int s = 0; // s is the start index
199

200     while (s < str.length()) {
201       if (str.charAt(s) == ' ')
202     s++;
203       else {
204     int e = str.indexOf(' ', s); // e is the end index
205
if (e < 0) {
206       v.addElement(str.substring(s));
207       break;
208     }
209     v.addElement(str.substring(s, e));
210     s = e + 1;
211       }
212     }
213
214     String JavaDoc[] str_array = new String JavaDoc[v.size()];
215     v.copyInto(str_array);
216     return str_array;
217   }
218
219   /**
220    * Get the current target list as a string.
221    */

222   private String JavaDoc getTargetString() {
223     if (cachedTargetString == null) {
224       if (targets.length > 0) {
225     cachedTargetString = targets[0];
226     for (int i = 1; i < targets.length; i++)
227       cachedTargetString += " " + targets[i];
228       }
229       else
230     cachedTargetString = "";
231     }
232     return cachedTargetString;
233   }
234
235   /**
236    * Run make and print any error messages.
237    */

238   private void makeTask(String JavaDoc[] args, String JavaDoc targetString) {
239     try {
240       if (!make.make(args))
241     make.getOut().println("Nothing to make");
242     }
243     catch (CommandFailedException ex) {
244       make.getOut().println("Command failed: " + ex.getMessage());
245     }
246     if (targetString.equals(""))
247       targetString = "Make";
248     else
249       targetString = "Made " + targetString;
250     make.getOut().println(targetString + " at " + now());
251   }
252
253   private DateFormat JavaDoc formatter;
254
255   private String JavaDoc now() {
256     if (formatter == null) {
257       formatter = DateFormat.getTimeInstance();
258       formatter.setTimeZone(TimeZone.getDefault());
259     }
260     return formatter.format(new Date());
261   }
262
263   /**
264    * Enqueue a make task.
265    */

266   private void make() {
267     final String JavaDoc targetString = getTargetString();
268     final String JavaDoc[] args = targets;
269     tasks.add(new Runnable JavaDoc() {
270       public void run() {
271     makeTask(args, targetString);
272       }
273     });
274   }
275
276   /**
277    * Load the makefile given in the make object
278    * and print any error messages.
279    */

280   private void loadTask() {
281     String JavaDoc fileName = make.getFile().getPath();
282     try {
283       make.load();
284       make.getOut().println("Loaded " + fileName + " at " + now());
285     }
286     catch (FileNotFoundException ex) {
287       make.getOut().println("Cannot find makefile " + fileName);
288     }
289     catch (ParseError pe) {
290       make.getOut().println(pe.getFileName() + ":" + pe.getLineNumber()
291                 + ": Parse error: " + pe.getMessage());
292     }
293   }
294
295   /**
296    * Enqueue a load task.
297    */

298   private void load() {
299     tasks.add(new Runnable JavaDoc() {
300       public void run() {
301     loadTask();
302       }
303     });
304   }
305
306   /**
307    * Cancel queued tasks.
308    */

309   private void cancel() {
310     tasks.removeAll();
311     make.setInterruptEnabled(true);
312     make.getOut().println("Cancel requested");
313   }
314
315   /**
316    * Creates the make frame and all the windows that it contains.
317    */

318   public static void createMakeWindow(Make make, String JavaDoc[] targets) {
319     loadResources();
320     Frame f = new Frame(Make.getVersion());
321     f.addWindowListener(new WindowAdapter() {
322       public void windowClosing(WindowEvent e) {
323     System.exit(0);
324       }
325     });
326     f.setFont(Font.decode(getFontResource()));
327
328     Label label = new Label(makefileLabel(make));
329     f.add(label, "North");
330     MakeWindow mw = new MakeWindow(make, targets,
331                    getRowsResource(),
332                    getColumnsResource());
333     mw.setEditable(false);
334     f.add(mw, "Center");
335     f.setMenuBar(createMenuBar(mw, make, f, label));
336     Panel panel = new Panel(new BorderLayout());
337     Label targetLabel = new Label(" Targets:");
338     MakeInput field = new MakeInput(mw.getTargetString());
339     field.addActionListener(mw);
340     panel.add(targetLabel, "West");
341     panel.add(field, "Center");
342     f.add(panel, "South");
343     label.addFocusListener(field);
344     mw.addFocusListener(field);
345     panel.addFocusListener(field);
346     targetLabel.addFocusListener(field);
347
348     f.pack();
349     f.show();
350     field.requestFocus();
351     mw.load();
352   }
353
354   private static String JavaDoc makefileLabel(Make make) {
355     return " Makefile: " + make.getFile().getPath();
356   }
357
358   private static MenuBar createMenuBar(final MakeWindow mw,
359                        final Make make,
360                        final Frame frame,
361                        final Label label) {
362     MenuBar mb = new MenuBar();
363     Menu m = new Menu("File");
364     mb.add(m);
365     MenuItem mi;
366     mi = new MenuItem("Reload", new MenuShortcut(KeyEvent.VK_R));
367     mi.addActionListener(new ActionListener() {
368       public void actionPerformed(ActionEvent e) {
369     mw.load();
370       }
371     });
372     m.add(mi);
373     mi = new MenuItem("File load", new MenuShortcut(KeyEvent.VK_F));
374     mi.addActionListener(makefileDialog(mw, make, frame, label));
375     m.add(mi);
376     mi = new MenuItem("Exit", new MenuShortcut(KeyEvent.VK_X));
377     mi.addActionListener(new ActionListener() {
378       public void actionPerformed(ActionEvent e) {
379     System.exit(0);
380       }
381     });
382     m.add(mi);
383     m = new Menu("Commands");
384     mb.add(m);
385     // Changed the short cut from VK_M to VK_A because
386
// VK_M invoked make twice.
387
mi = new MenuItem("Make", new MenuShortcut(KeyEvent.VK_A));
388     mi.addActionListener(new ActionListener() {
389       public void actionPerformed(ActionEvent e) {
390     mw.make();
391       }
392     });
393     m.add(mi);
394     mi = new MenuItem("Cancel", new MenuShortcut(KeyEvent.VK_C));
395     mi.addActionListener(new ActionListener() {
396       public void actionPerformed(ActionEvent e) {
397     mw.cancel();
398       }
399     });
400     m.add(mi);
401     mi = new MenuItem("To Clipboard", new MenuShortcut(KeyEvent.VK_T));
402     mi.addActionListener(copyTranscriptAction(mw));
403     m.add(mi);
404     m = new Menu("Options");
405     mb.add(m);
406     CheckboxMenuItem cmi = new CheckboxMenuItem("Verbose", make.isVerbose());
407     cmi.addItemListener(new ItemListener() {
408       public void itemStateChanged(ItemEvent e) {
409     make.setVerbose(e.getStateChange() == ItemEvent.SELECTED);
410       }
411     });
412     m.add(cmi);
413     cmi = new CheckboxMenuItem("Just Print", make.isJustPrinting());
414     cmi.addItemListener(new ItemListener() {
415       public void itemStateChanged(ItemEvent e) {
416     make.setJustPrinting(e.getStateChange() == ItemEvent.SELECTED);
417       }
418     });
419     m.add(cmi);
420     return mb;
421   }
422
423   private static ActionListener makefileDialog(final MakeWindow mw,
424                            final Make make,
425                            final Frame frame,
426                            final Label label) {
427     return new ActionListener() {
428       public void actionPerformed(ActionEvent e) {
429     FileDialog fd = new FileDialog(frame, "Select makefile name");
430     fd.setFile(make.getFile().getPath());
431     fd.show();
432     String JavaDoc makefile = fd.getFile();
433     if (makefile != null) {
434       makefile = fd.getDirectory() + makefile;
435       make.setFile(new File(makefile));
436       label.setText(makefileLabel(make));
437       mw.load();
438     }
439       }
440     };
441   }
442
443   private static ActionListener copyTranscriptAction(final MakeWindow mw) {
444     final Clipboard clipboard = mw.getToolkit().getSystemClipboard();
445     return new ActionListener() {
446       public void actionPerformed(ActionEvent e) {
447     String JavaDoc srcData;
448     if (mw.getSelectionStart() < mw.getSelectionEnd())
449       srcData = mw.getSelectedText();
450     else {
451       mw.selectAll();
452       srcData = mw.getText();
453     }
454     if (srcData != null) {
455       StringSelection contents = new StringSelection(srcData);
456       clipboard.setContents(contents, mw);
457     }
458       }
459     };
460   }
461
462   /**
463    * Action on loss of clipboard.
464    */

465   public void lostOwnership(Clipboard clipboard, Transferable contents) {
466     select(0, 0); // Deselect all text
467
}
468
469  /**
470    * Resource functions.
471    */

472
473   private static ResourceBundle resources;
474
475   /**
476    * load resources
477    */

478   private static void loadResources() {
479     if (resources == null) {
480       try {
481     resources = ResourceBundle.getBundle(JMK_PROPERTIES);
482       }
483       catch (MissingResourceException mre) {
484     // Ignore errors. Defaults will be used for missing properties.
485
}
486     }
487   }
488
489   /**
490    * Get a string from a ResourceBundle.
491    * @param nm name of key
492    * @return resource as a string or defaultValue on error
493    */

494   private static String JavaDoc getResourceString(String JavaDoc nm, String JavaDoc defaultValue) {
495     if (resources == null)
496       return defaultValue;
497     try {
498       return resources.getString(nm);
499     }
500     catch (MissingResourceException mre) {
501       return defaultValue;
502     }
503   }
504
505   /**
506    * Get an integer from a ResourceBundle.
507    * @param nm name of key
508    * @param defaultValue value on error
509    * @return resource as an integer or default value on error
510    */

511   private static int getResourceInt(String JavaDoc nm, int defaultValue) {
512     if (resources == null)
513       return defaultValue;
514     String JavaDoc str;
515     try {
516       str = resources.getString(nm);
517     }
518     catch (MissingResourceException mre) {
519       return defaultValue;
520     }
521     if (str == null)
522       return defaultValue;
523     try {
524       return Integer.parseInt(str);
525     }
526     catch (NumberFormatException JavaDoc ex) {
527       return defaultValue;
528     }
529   }
530
531   private static String JavaDoc getFontResource() {
532     return getResourceString("jmk.font", DEFAULT_FONT);
533   }
534
535   private static int getColumnsResource() {
536     return getResourceInt("jmk.columns", DEFAULT_COLUMNS);
537   }
538
539   private static int getRowsResource() {
540     return getResourceInt("jmk.rows", DEFAULT_ROWS);
541   }
542
543   /**
544    * A main entry point for running Make in a window.
545    * The first arg is the name of the makefile
546    * and the remaining args are the initial targets.
547    */

548   public static void main(String JavaDoc[] args) {
549     try {
550       Make make = new Make();
551       if (args.length > 0) {
552     String JavaDoc[] targets = new String JavaDoc[args.length - 1];
553     for (int i = 0; i < targets.length; i++)
554       targets[i] = args[i + 1];
555     make.setFile(new File(args[0]));
556     MakeWindow.createMakeWindow(make, targets);
557       }
558       else {
559     System.out.println("Usage: java " + MakeWindow.class.getName() +
560                " makefile [ target ]*");
561     System.exit(1);
562       }
563     }
564     catch (Throwable JavaDoc t) {
565       System.err.println("Internal error: " + t.getMessage());
566       t.printStackTrace();
567       System.exit(1);
568     }
569   }
570 }
571
Popular Tags