001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.cnd.makewizard;
043:
044: import java.awt.Dimension;
045: import java.awt.GridBagConstraints;
046: import java.awt.GridBagLayout;
047: import java.awt.Insets;
048: import java.awt.event.FocusEvent;
049: import java.awt.event.FocusListener;
050: import java.io.File;
051: import java.util.ArrayList;
052: import java.util.StringTokenizer;
053: import javax.swing.JLabel;
054: import javax.swing.JPanel;
055: import javax.swing.JScrollPane;
056: import javax.swing.JTextArea;
057: import javax.swing.JTextField;
058: import javax.swing.event.DocumentEvent;
059: import javax.swing.event.DocumentListener;
060:
061: /**
062: * Create a panel used for gathering the binary name and output directory for
063: * the simple application cases (all Makefile types other than complex).
064: */
065:
066: public class MakeTargetPanel extends MakefileWizardPanel implements
067: FocusListener {
068:
069: /** Serial version number */
070: static final long serialVersionUID = -8864738441088422274L;
071:
072: /** the main panel */
073: private JPanel panel;
074:
075: /** the constraints used in that panel */
076: private GridBagConstraints grid;
077:
078: /** share the insets rather than create a bunch of them */
079: Insets insets;
080:
081: // the fields in the first panel...
082: private JTextField targetName;
083: private JTextField dependsOn;
084: private JTextField subdirectory;
085: private JTextField makeFlags;
086: private JTextArea commandDisplay;
087: private boolean enableCommandSelection;
088:
089: private String tname;
090: private String depends;
091: private String subdir;
092: private String mflags;
093:
094: private int row;
095: private boolean initialized;
096:
097: /** Store the target key */
098: private int key;
099:
100: /**
101: * Constructor for the make target panel.
102: */
103: MakeTargetPanel(MakefileWizard wd) {
104: super (wd);
105: String subtitle = new String(getString("LBL_MakeTargetPanel")); // NOI18N
106: setSubTitle(subtitle);
107: this .getAccessibleContext().setAccessibleDescription(subtitle);
108: initialized = false;
109: }
110:
111: /** Defer widget creation until the panel needs to be displayed */
112: private void create() {
113:
114: setLayout(new GridBagLayout());
115:
116: insets = new Insets(10, 0, 0, 0);
117: grid = new GridBagConstraints();
118: grid.anchor = GridBagConstraints.NORTHWEST;
119: grid.insets = insets;
120:
121: tname = new String(""); // NOI18N
122: depends = new String(""); // NOI18N
123: subdir = new String(""); // NOI18N
124: mflags = new String(""); // NOI18N
125: row = 0;
126:
127: JPanel tpanel = createTextFields();
128: insets.top = 0;
129: insets.left = 0;
130: grid.gridx = 0;
131: grid.gridy = 0;
132: grid.insets = insets;
133: add(tpanel, grid);
134: Dimension tsize = tpanel.getPreferredSize();
135: Dimension psize = getPreferredSize();
136: Dimension csize = new Dimension(psize.width, psize.height
137: - tsize.height);
138:
139: createCommandDisplay(csize, "LBL_CommandDisplay",
140: "MNEM_CommandDisplay"); // NOI18N
141:
142: setupListeners();
143: }
144:
145: /** Put the textfields in a JPanel */
146: private JPanel createTextFields() {
147:
148: JPanel tpanel = new JPanel(new GridBagLayout());
149:
150: targetName = createTextField(tpanel, "LBL_TargetName",
151: "MNEM_TargetName"); // NOI18N
152: dependsOn = createTextField(tpanel, "LBL_DependsOn",
153: "MNEM_DependsOn"); // NOI18N
154: subdirectory = createTextField(tpanel, "LBL_Subdirectory",
155: "MNEM_Subdirectory"); // NOI18N
156: makeFlags = createTextField(tpanel, "LBL_MakeFlags",
157: "MNEM_MakeFlags"); // NOI18N
158:
159: return tpanel;
160: }
161:
162: /** Create a textfield and its label */
163: private JTextField createTextField(JPanel tpanel, String label,
164: String mnem) {
165:
166: // Create the textfield components.
167: JLabel nueLabel = new JLabel(getString(label));
168: JTextField nueText = new JTextField();
169:
170: // Set the GridBagLayout constraints.
171: insets.left = 0;
172: grid.gridx = 0;
173: grid.gridy = row++;
174: grid.gridwidth = 1;
175: grid.weightx = 0.0;
176: tpanel.add(nueLabel, grid);
177:
178: insets.left = 5;
179: grid.gridx = 1;
180: grid.gridwidth = GridBagConstraints.REMAINDER;
181: grid.weightx = 1.0;
182: grid.fill = GridBagConstraints.HORIZONTAL;
183: tpanel.add(nueText, grid);
184:
185: nueLabel.setDisplayedMnemonic(getString(mnem).charAt(0));
186: nueLabel.setLabelFor(nueText);
187:
188: return nueText;
189: }
190:
191: private void createCommandDisplay(Dimension size, String label,
192: String mnem) {
193:
194: // Create and add the components to the JPanel
195: JLabel nueLabel = new JLabel(getString(label));
196: nueLabel.setDisplayedMnemonic(getString(mnem).charAt(0));
197: insets.top = 16;
198: grid.gridx = 0;
199: grid.gridy = 1;
200: grid.gridwidth = 1;
201: add(nueLabel, grid);
202: size.setSize(size.getWidth(), size.getHeight() - insets.top
203: - nueLabel.getPreferredSize().getHeight());
204:
205: commandDisplay = new JTextArea();
206: commandDisplay.setEditable(false);
207: commandDisplay.setBackground(getBackground());
208: commandDisplay.addFocusListener(this );
209: JScrollPane s = new JScrollPane(commandDisplay);
210: s
211: .setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
212: s
213: .setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
214: size.height = size.height - insets.top
215: - nueLabel.getPreferredSize().height;
216: s.setPreferredSize(size);
217: nueLabel.setLabelFor(commandDisplay);
218:
219: insets.top = 0;
220: grid.gridy = 2;
221: grid.gridwidth = GridBagConstraints.REMAINDER;
222: grid.gridheight = GridBagConstraints.REMAINDER;
223: add(s, grid);
224:
225: enableCommandSelection = false;
226: }
227:
228: public void focusGained(FocusEvent evt) {
229: // don't select text when panel is first displayed otherwise
230: // the text appears to "flash"
231: if (enableCommandSelection) {
232: commandDisplay.selectAll();
233: }
234: enableCommandSelection = true;
235: }
236:
237: public void focusLost(FocusEvent evt) {
238: commandDisplay.setSelectionEnd(0);
239: }
240:
241: /** Setup the document listeners for each textfield */
242: private void setupListeners() {
243:
244: targetName.getDocument().addDocumentListener(
245: new DocumentListener() {
246: public void changedUpdate(DocumentEvent e) {
247: tname = targetName.getText();
248: commandDisplay.setText(getCommandDisplay());
249: updateButtons();
250: }
251:
252: public void insertUpdate(DocumentEvent e) {
253: tname = targetName.getText();
254: commandDisplay.setText(getCommandDisplay());
255: updateButtons();
256: }
257:
258: public void removeUpdate(DocumentEvent e) {
259: tname = targetName.getText();
260: commandDisplay.setText(getCommandDisplay());
261: updateButtons();
262: }
263: });
264:
265: dependsOn.getDocument().addDocumentListener(
266: new DocumentListener() {
267: public void changedUpdate(DocumentEvent e) {
268: depends = dependsOn.getText();
269: commandDisplay.setText(getCommandDisplay());
270: updateButtons();
271: }
272:
273: public void insertUpdate(DocumentEvent e) {
274: depends = dependsOn.getText();
275: commandDisplay.setText(getCommandDisplay());
276: updateButtons();
277: }
278:
279: public void removeUpdate(DocumentEvent e) {
280: depends = dependsOn.getText();
281: commandDisplay.setText(getCommandDisplay());
282: updateButtons();
283: }
284: });
285:
286: subdirectory.getDocument().addDocumentListener(
287: new DocumentListener() {
288: public void changedUpdate(DocumentEvent e) {
289: subdir = subdirectory.getText();
290: commandDisplay.setText(getCommandDisplay());
291: updateButtons();
292: }
293:
294: public void insertUpdate(DocumentEvent e) {
295: subdir = subdirectory.getText();
296: commandDisplay.setText(getCommandDisplay());
297: updateButtons();
298: }
299:
300: public void removeUpdate(DocumentEvent e) {
301: subdir = subdirectory.getText();
302: commandDisplay.setText(getCommandDisplay());
303: updateButtons();
304: }
305: });
306:
307: makeFlags.getDocument().addDocumentListener(
308: new DocumentListener() {
309: public void changedUpdate(DocumentEvent e) {
310: mflags = makeFlags.getText();
311: commandDisplay.setText(getCommandDisplay());
312: updateButtons();
313: }
314:
315: public void insertUpdate(DocumentEvent e) {
316: mflags = makeFlags.getText();
317: commandDisplay.setText(getCommandDisplay());
318: updateButtons();
319: }
320:
321: public void removeUpdate(DocumentEvent e) {
322: mflags = makeFlags.getText();
323: commandDisplay.setText(getCommandDisplay());
324: updateButtons();
325: }
326: });
327: }
328:
329: private void updateButtons() {
330: MakefileWizard mw = MakefileWizard.getMakefileWizard();
331:
332: if (tname.length() > 0 || depends.length() > 0
333: || subdir.length() > 0 || mflags.length() > 0) {
334: mw.getNextButton().setEnabled(true);
335: if (mw.getMakefileData().isComplete(true)) {
336: mw.getFinishButton().setEnabled(true);
337: }
338: } else {
339: mw.getNextButton().setEnabled(false);
340: mw.getFinishButton().setEnabled(false);
341: }
342: }
343:
344: public boolean isPanelValid() {
345: if (tname != null && depends != null && subdir != null
346: && mflags != null) {
347: return tname.length() > 0 || depends.length() > 0
348: || subdir.length() > 0 || mflags.length() > 0;
349: } else {
350: return false;
351: }
352: }
353:
354: /** Put together the command display string based on current input */
355: private String getCommandDisplay() {
356: return getCommandDisplay(-1);
357: }
358:
359: /**
360: * Put together the command display string based on current input.
361: * This method can be called during target definition, in which case we
362: * get the target via getCurrentTarget(). It can also be called after
363: * target definition has been completed. In that case we must pass the
364: * target key.
365: */
366: private String getCommandDisplay(int key) {
367: StringBuffer buf = new StringBuffer(512);
368: TargetData target;
369: String[] dirs;
370:
371: if (key < 0) {
372: target = (TargetData) getMakefileData().getCurrentTarget();
373: } else {
374: target = (TargetData) getMakefileData().getTarget(key);
375: }
376:
377: buf.append(target.getName());
378: buf.append(": "); // NOI18N
379: if (depends.length() > 0) {
380: buf.append(depends);
381: }
382:
383: dirs = getSubDirList();
384: for (int i = 0; i < dirs.length; i++) {
385: buf.append("\n\t"); // NOI18N
386: if (dirs[i].length() > 0) {
387: buf.append("cd ").append(dirs[i]).append("; "); // NOI18N
388: }
389:
390: buf.append("$(MAKE) "); // NOI18N
391: if (mflags.length() > 0) {
392: buf.append(mflags).append(' ');
393: }
394: if (tname.length() > 0) {
395: buf.append(tname);
396: }
397: }
398:
399: return buf.toString();
400: }
401:
402: private String[] getSubDirList() {
403: String[] dirs;
404:
405: if (subdir.length() < 1 || subdir.equals(".")) { // NOI18N
406: dirs = new String[1];
407: dirs[0] = new String(""); // NOI18N
408: } else {
409: StringTokenizer tok = new StringTokenizer(subdir, " "); // NOI18N
410: int count = tok.countTokens();
411: int i = 0;
412:
413: dirs = new String[count];
414: while (tok.hasMoreTokens()) {
415: dirs[i++] = tok.nextToken();
416: }
417: }
418:
419: return dirs;
420: }
421:
422: /** Validate the binary name and output directory */
423: public void validateData(ArrayList msgs, int key) {
424: TargetData target = (TargetData) getMakefileData().getTarget(
425: key);
426: String cwd = getMakefileData().getBaseDirectory(
427: MakefileData.EXPAND);
428: File sd = null;
429:
430: if (subdir.length() > 0 && !subdir.equals(".")) { // NOI18N
431: if (subdir.startsWith(File.separator)) {
432: sd = new File(subdir);
433: } else {
434: sd = new File(cwd, subdir);
435: }
436: if (sd.getPath().equals(cwd)) {
437: sd = null; // Don't test it. Its a variation of '.'
438: }
439: }
440:
441: if (sd != null) {
442: if (!sd.exists()) {
443: // check subdir for nonexistant directory
444: warn(msgs, WARN_SUBDIR_DOES_NOT_EXIST, subdir, tname);
445: } else if (!sd.canWrite()) {
446: // check subdir for unwritable directory
447: warn(msgs, WARN_SUBDIR_NOT_WRITABLE, subdir, tname);
448: }
449: } else {
450: // if subdir is blank check for infinite recursion
451: ArrayList tlist = getMakefileData().getTargetList();
452: for (int i = 0; i < tlist.size(); i++) {
453: if (tname.equals(((TargetData) tlist.get(i)).getName())) {
454: warn(msgs, WARN_INFINITE_RECURSION, tname);
455: }
456: }
457: }
458:
459: // check makeFlags for unmatched quotes
460: if (!isValidMakeFlags()) {
461: warn(msgs, WARN_INVALID_MAKEFLAGS);
462: }
463: }
464:
465: /** Verify the Make Flags. Currently we only check for unmatched quotes */
466: private boolean isValidMakeFlags() {
467: char c;
468: char lastChar = 0;
469: int squote = 0;
470: int dquote = 0;
471:
472: for (int i = 0; i < mflags.length(); i++) {
473: c = mflags.charAt(i);
474: if (lastChar != '\\') {
475: if (c == '\'') {
476: squote++;
477: }
478: if (c == '"') {
479: dquote++;
480: }
481: }
482: lastChar = c;
483: }
484:
485: if ((squote % 2) == 1 || (dquote % 2) == 1) {
486: return false;
487: } else {
488: return true;
489: }
490: }
491:
492: /** Create and initialize the target */
493: public void addNotify() {
494: TargetData target = (TargetData) getMakefileData()
495: .getCurrentTarget();
496: int i;
497:
498: if (!initialized) {
499: create();
500: initialized = true;
501: }
502:
503: key = target.getKey();
504: targetName.setText(tname);
505: dependsOn.setText(depends);
506: subdirectory.setText(subdir);
507: makeFlags.setText(mflags);
508: commandDisplay.setText(getCommandDisplay());
509: updateButtons();
510: super .addNotify();
511: }
512:
513: /** Get the data from the panel and update the target */
514: public void removeNotify() {
515: super .removeNotify();
516:
517: TargetData target = getMakefileData().getTarget(key);
518: target.setTargetName(tname);
519: target.setDependsOn(depends);
520: target.setSubdirectory(subdir);
521: target.setMakeFlags(mflags);
522: }
523: }
|