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.Component;
045: import java.awt.GridBagConstraints;
046: import java.awt.GridBagLayout;
047: import java.awt.GridLayout;
048: import java.awt.Insets;
049: import java.awt.event.ActionEvent;
050: import java.awt.event.ActionListener;
051: import java.awt.event.FocusEvent;
052: import java.awt.event.FocusListener;
053: import java.io.File;
054: import java.util.ArrayList;
055: import javax.swing.ButtonGroup;
056: import javax.swing.DefaultListModel;
057: import javax.swing.JButton;
058: import javax.swing.JDialog;
059: import javax.swing.JFileChooser;
060: import javax.swing.JLabel;
061: import javax.swing.JList;
062: import javax.swing.JPanel;
063: import javax.swing.JRadioButton;
064: import javax.swing.JScrollPane;
065: import javax.swing.JTextField;
066: import javax.swing.event.DocumentEvent;
067: import javax.swing.event.DocumentListener;
068: import javax.swing.event.ListSelectionEvent;
069: import javax.swing.event.ListSelectionListener;
070: import org.netbeans.modules.cnd.api.utils.IpeUtils;
071:
072: /**
073: * Create the third panel in the Makefile wizard.
074: */
075:
076: public class CreateTargetsPanel extends MakefileWizardPanel implements
077: FocusListener {
078:
079: /** Serial version number */
080: static final long serialVersionUID = -8649616207466524363L;
081:
082: // the fields in the first panel...
083: private JLabel nameLabel;
084: private JTextField nameText;
085: private JButton nameChooser;
086: private JRadioButton executable;
087: private JRadioButton archive;
088: private JRadioButton sharedLib;
089: private JRadioButton recursiveMake;
090: private JRadioButton customTarget;
091: private ButtonGroup typeBG;
092: private JButton addBtn;
093: private JButton removeBtn;
094: private JButton changeBtn;
095: private JLabel listLabel;
096: private JScrollPane listSP;
097: private JList list;
098:
099: private boolean initialized;
100:
101: /** The nextButton is set if we are dynamically setting the default */
102: private JButton nextButton;
103:
104: private int newKey;
105:
106: /** Keep a pointer to the MakefileWizard */
107: private MakefileWizard wiz;
108:
109: /** Store the file (possibly customized) file chooser */
110: protected JFileChooser fc;
111:
112: /**
113: * Constructor for the Makefile name panel. Remember, most of the panel is
114: * inherited from WizardDescriptor.
115: */
116: CreateTargetsPanel(MakefileWizard wiz) {
117: super (wiz);
118: this .wiz = wiz;
119: String subtitle = getString("LBL_CreateTargetsPanel"); // NOI18N
120: setSubTitle(subtitle);
121: this .getAccessibleContext().setAccessibleDescription(subtitle);
122:
123: nextButton = null;
124: initialized = false;
125: }
126:
127: /** Defer widget creation until the panel needs to be displayed */
128: private void create() {
129:
130: setLayout(new GridBagLayout());
131: GridBagConstraints grid = new GridBagConstraints();
132: grid.anchor = GridBagConstraints.WEST;
133: grid.gridx = 0;
134: grid.gridy = 0;
135: Insets defaultInsets = grid.insets;
136:
137: nextButton = MakefileWizard.getMakefileWizard().getNextButton();
138:
139: // Create the components.
140: nameLabel = new JLabel(getString("LBL_TargetName")); // NOI18N
141: nameLabel.setDisplayedMnemonic(getString("MNEM_TargetName")
142: .charAt(0)); // NOI18N
143: add(nameLabel, grid);
144:
145: nameText = new JTextField();
146: grid.anchor = GridBagConstraints.WEST;
147: grid.gridx = 1;
148: grid.gridy = GridBagConstraints.RELATIVE;
149: grid.weightx = 100.0;
150: grid.fill = GridBagConstraints.HORIZONTAL;
151: grid.insets = new Insets(0, 11, 0, 5);
152: add(nameText, grid);
153: nameLabel.setLabelFor(nameText);
154:
155: nameChooser = new JButton(getString("BTN_Chooser")); // NOI18N
156: nameChooser.setMnemonic(getString("MNEM_Chooser").charAt(0)); // NOI18N
157: grid.gridx = 2;
158: grid.weightx = 0.0;
159: grid.fill = GridBagConstraints.NONE;
160: grid.insets = new Insets(0, 0, 0, 0);
161: add(nameChooser, grid);
162: createChooser(nameChooser);
163:
164: // Create the RadioButtons
165: grid.gridx = 0;
166: grid.gridwidth = GridBagConstraints.REMAINDER;
167: grid.insets = new Insets(12, 0, 0, 0);
168: executable = new JRadioButton(getString("RB_Executable")); // NOI18N
169: executable.setSelected(true);
170: executable.setMnemonic(getString("MNEM_Executable").charAt(0)); // NOI18N
171: add(executable, grid);
172:
173: grid.insets = defaultInsets;
174: archive = new JRadioButton(getString("RB_StaticLibrary")); // NOI18N
175: archive.setMnemonic(getString("MNEM_StaticLibrary").charAt(0)); // NOI18N
176: add(archive, grid);
177:
178: sharedLib = new JRadioButton(getString("RB_SharedLibrary")); // NOI18N
179: sharedLib
180: .setMnemonic(getString("MNEM_SharedLibrary").charAt(0)); // NOI18N
181: add(sharedLib, grid);
182:
183: recursiveMake = new JRadioButton(getString("RB_RecursiveMake"));// NOI18N
184: recursiveMake.setMnemonic(getString("MNEM_RecursiveMake")
185: .charAt(0)); // NOI18N
186: add(recursiveMake, grid);
187:
188: customTarget = new JRadioButton(getString("RB_CustomTarget")); // NOI18N
189: customTarget.setMnemonic(getString("MNEM_CustomTarget").charAt(
190: 0)); // NOI18N
191: add(customTarget, grid);
192:
193: typeBG = new ButtonGroup();
194: typeBG.add(executable);
195: typeBG.add(archive);
196: typeBG.add(sharedLib);
197: typeBG.add(recursiveMake);
198: typeBG.add(customTarget);
199:
200: JPanel bpanel = createButtonPanel();
201: grid.insets = new Insets(5, 0, 0, 0);
202: add(bpanel, grid);
203:
204: listLabel = new JLabel(getString("LBL_List")); // NOI18N
205: listLabel
206: .setDisplayedMnemonic(getString("MNEM_List").charAt(0)); // NOI18N
207: grid.insets = new Insets(11, 0, 0, 0);
208: add(listLabel, grid);
209:
210: list = new JList(new DefaultListModel());
211: listSP = new JScrollPane(list);
212: grid.weightx = 100.0;
213: grid.weighty = 100.0;
214: grid.fill = GridBagConstraints.BOTH;
215: grid.insets = defaultInsets;
216: add(listSP, grid);
217: listLabel.setLabelFor(list);
218:
219: setupListeners();
220: newKey = 0;
221:
222: // a11y
223: list.getAccessibleContext().setAccessibleDescription(
224: getString("ACSD_List") // NOI18N
225: );
226: nameText.getAccessibleContext().setAccessibleDescription(
227: getString("ACSD_TargetNameTF") // NOI18N
228: );
229: addBtn.getAccessibleContext().setAccessibleDescription(
230: getString("ACSD_CreateTargetsPanelAddBtn") // NOI18N
231: );
232: removeBtn.getAccessibleContext().setAccessibleDescription(
233: getString("ACSD_CreateTargetsPanelRemoveBtn") // NOI18N
234: );
235: changeBtn.getAccessibleContext().setAccessibleDescription(
236: getString("ACSD_CreateTargetsPanelChangeBtn") // NOI18N
237: );
238: nameChooser.getAccessibleContext().setAccessibleDescription(
239: getString("ACSD_CreateTargetsPanelBrowseBtn") // NOI18N
240: );
241: }
242:
243: private JPanel createButtonPanel() {
244: JPanel bpanel = new JPanel();
245: bpanel.setLayout(new GridLayout(1, 3, 6, 0));
246:
247: addBtn = new JButton(getString("BTN_Add")); // NOI18N
248: addBtn.setMnemonic(getString("MNEM_Add").charAt(0)); // NOI18N
249: addBtn.setEnabled(false);
250: bpanel.add(addBtn);
251:
252: removeBtn = new JButton(getString("BTN_Remove")); // NOI18N
253: removeBtn.setMnemonic(getString("MNEM_Remove").charAt(0)); // NOI18N
254: removeBtn.setEnabled(false);
255: bpanel.add(removeBtn);
256:
257: changeBtn = new JButton(getString("BTN_Change")); // NOI18N
258: changeBtn.setMnemonic(getString("MNEM_Change").charAt(0)); // NOI18N
259: changeBtn.setEnabled(false);
260: bpanel.add(changeBtn);
261:
262: return bpanel;
263: }
264:
265: /**
266: * Create a FileChoose for the text field.
267: */
268: protected void createChooser(JButton chooser) {
269:
270: chooser.addActionListener(new ActionListener() {
271: public void actionPerformed(ActionEvent evt) {
272:
273: if (fc == null) {
274: fc = new JFileChooser();
275: fc.setApproveButtonText(getString("BTN_Approve")); // NOI18N
276: fc
277: .setDialogTitle(getString("DLG_FILE_CHOOSER_TITLE")); // NOI18N
278: }
279:
280: // See if the user has already typed a directory. If so use it.
281: File f = null;
282: String cur = nameText.getText();
283: if (cur.length() > 0) {
284: f = new File(cur);
285: }
286:
287: if (f != null && f.isDirectory()) {
288: fc.setCurrentDirectory(f);
289: } else {
290: fc.setCurrentDirectory(new File(getMakefileData()
291: .getBaseDirectory(MakefileData.EXPAND)));
292: }
293: int returnVal = fc.showDialog(CreateTargetsPanel.this ,
294: null);
295:
296: if (returnVal == JFileChooser.APPROVE_OPTION) {
297: File file = fc.getSelectedFile();
298: //String cwd = getMakefileData().getBaseDirectory(MakefileData.EXPAND);
299: //String path = IpeUtils.getRelativePath(cwd, file.getPath());
300: //addTarget(path);
301: nameText.setText(file.getName());
302: setupButtons();
303: /*
304: addTarget(file.getName()); // Add only name (?)
305: nameText.setText(null);
306: addBtn.setEnabled(false);
307: */
308: }
309: }
310: });
311: }
312:
313: /** The valid state is anytime we have at least a single target */
314: public boolean isPanelValid() {
315:
316: if (!initialized
317: || ((DefaultListModel) list.getModel()).size() == 0) {
318: return false;
319: } else {
320: return true;
321: }
322: }
323:
324: public void updatePanels() {
325: wiz.updatePanels(MakefileData.COMPLEX_MAKEFILE_TYPE);
326: }
327:
328: private int getCurrentType() {
329:
330: if (executable.isSelected()) {
331: return TargetData.COMPLEX_EXECUTABLE;
332: } else if (archive.isSelected()) {
333: return TargetData.COMPLEX_ARCHIVE;
334: } else if (sharedLib.isSelected()) {
335: return TargetData.COMPLEX_SHAREDLIB;
336: } else if (recursiveMake.isSelected()) {
337: return TargetData.COMPLEX_MAKE_TARGET;
338: } else if (customTarget.isSelected()) {
339: return TargetData.COMPLEX_CUSTOM_TARGET;
340: } else {
341: return 0;
342: }
343: }
344:
345: /**
346: * Add the target to both the JList and target list. Create the new steps
347: * and add them to the steps list.
348: */
349: private void addTarget(String name) {
350: ArrayList tlist = getMakefileData().getTargetList();
351: TargetData target;
352: String dir;
353: int type;
354:
355: // Get the data for the target
356: type = getCurrentType();
357: if (tlist.isEmpty()) {
358: dir = getMakefileData().defaultOutputDirectory();
359: } else {
360: // Use the outputDirectory from the last target as a default
361: dir = ((TargetData) tlist.get(tlist.size() - 1))
362: .getOutputDirectory();
363: }
364:
365: // Get the target name, unless it was passed in
366: if (name == null) {
367: name = nameText.getText().trim();
368: }
369:
370: // Now make sure its not aready a defined target
371: if (!((DefaultListModel) list.getModel()).contains(name)) {
372: // Add the target to the target list in MakefileData
373: target = new TargetData(type, name, dir, newKey);
374: tlist.add(target);
375:
376: // Now add the target to the JList in the panel.
377: ((DefaultListModel) list.getModel()).addElement(name);
378: list.clearSelection();
379:
380: // Finally, add the target panels to MakefileWizard.
381: wiz.addTarget(type, name, newKey++);
382: }
383: /*
384: if (UsageTracking.enabled) {
385: String tstring;
386:
387: if (type == TargetData.COMPLEX_EXECUTABLE) {
388: tstring = new String("COMPLEX_EXECUTABLE"); // NOI18N
389: } else if (type == TargetData.COMPLEX_ARCHIVE) {
390: tstring = new String("COMPLEX_ARCHIVE"); // NOI18N
391: } else if (type == TargetData.COMPLEX_SHAREDLIB) {
392: tstring = new String("COMPLEX_SHAREDLIB"); // NOI18N
393: } else if (type == TargetData.COMPLEX_MAKE_TARGET) {
394: tstring = new String("COMPLEX_MAKE_TARGET"); // NOI18N
395: } else if (type == TargetData.COMPLEX_CUSTOM_TARGET) {
396: tstring = new String("COMPLEX_CUSTOM_TARGET"); // NOI18N
397: } else {
398: tstring = new String("<Unknown>"); // NOI18N
399: }
400: UsageTracking.sendAction("Create Target: Type " + // NOI18N
401: tstring, null);
402: }
403: */
404: }
405:
406: /** Remove 1 or more targets, including associated steps */
407: private void deleteTargets(int[] indices) {
408:
409: ArrayList tlist = getMakefileData().getTargetList();
410: int sel;
411: DefaultListModel model = (DefaultListModel) list.getModel();
412: while (indices.length > 0) {
413: sel = indices[0];
414: wiz.deleteTarget(((TargetData) tlist.get(sel)).getKey());
415: tlist.remove(sel);
416: model.removeElementAt(sel);
417: indices = list.getSelectedIndices();
418: }
419:
420: /*
421: if (UsageTracking.enabled) {
422: UsageTracking.sendAction("Remove Target", null); // NOI18N
423: }
424: */
425: }
426:
427: /** Change a target, either name or type */
428: private void changeTarget(int idx, String name) {
429: ArrayList tlist = getMakefileData().getTargetList();
430: TargetData target = (TargetData) tlist.get(idx);
431:
432: if (name.charAt(name.length() - 1) == File.separatorChar) {
433: name = IpeUtils.trimpath(name);
434: nameText.setText(name);
435: ((DefaultListModel) list.getModel()).set(idx, name);
436: }
437: wiz.changeTarget(((TargetData) tlist.get(idx)).getKey(), name,
438: getCurrentType());
439: int ctype = getCurrentType();
440: if (ctype != target.getTargetType()) {
441: target = new TargetData(ctype, name, target
442: .getOutputDirectory(), target.getKey());
443: tlist.remove(idx);
444: tlist.add(idx, target);
445: } else {
446: target.setName(name);
447: }
448:
449: /*
450: if (UsageTracking.enabled) {
451: UsageTracking.sendAction("Change Target", null); // NOI18N
452: }
453: */
454: }
455:
456: /**
457: * Setup listeners for nameText and list. This needs to be done after all
458: * components are created so its not done in the create* methods.
459: */
460: private void setupListeners() {
461: final DefaultListModel model = (DefaultListModel) list
462: .getModel();
463:
464: nameText.getDocument().addDocumentListener(
465: new DocumentListener() {
466: public void changedUpdate(DocumentEvent e) {
467: setupButtons();
468: }
469:
470: public void insertUpdate(DocumentEvent e) {
471: setupButtons();
472: }
473:
474: public void removeUpdate(DocumentEvent e) {
475: setupButtons();
476: }
477: });
478:
479: addBtn.addActionListener(new ActionListener() {
480: public void actionPerformed(ActionEvent e) {
481: String name = nameText.getText().trim();
482: if (getMakefileData().validateTargetName(name,
483: getCurrentType())) {
484: addTarget(name);
485: nameText.setText(null);
486: setupButtons();
487: } else {
488: ; // FIXUP What to do?
489: }
490: }
491: });
492:
493: changeBtn.addActionListener(new ActionListener() {
494: public void actionPerformed(ActionEvent e) {
495: model.set(list.getMinSelectionIndex(), nameText
496: .getText());
497: changeTarget(list.getMinSelectionIndex(), nameText
498: .getText());
499: }
500: });
501:
502: removeBtn.addActionListener(new ActionListener() {
503: public void actionPerformed(ActionEvent e) {
504: int min = list.getMinSelectionIndex();
505: int max = list.getMaxSelectionIndex();
506: int[] indices = list.getSelectedIndices();
507:
508: deleteTargets(indices);
509: if (model.isEmpty()) {
510: nextButton.setEnabled(false);
511: } else if (min >= 0 && min < model.getSize()) {
512: list.setSelectedIndex(min);
513: } else {
514: int newSel = min;
515: if (min >= model.getSize()) {
516: newSel = model.getSize() - 1;
517: }
518: list.setSelectedIndex(newSel);
519: }
520: setupButtons();
521: }
522: });
523:
524: list.addListSelectionListener(new ListSelectionListener() {
525: public void valueChanged(ListSelectionEvent e) {
526: // Ignore any calls while value is being adjusted (ie, dragged)
527: if (!e.getValueIsAdjusting()) {
528: int min = list.getMinSelectionIndex();
529: int max = list.getMaxSelectionIndex();
530:
531: if (min >= 0 && max >= 0
532: && list.getModel().getSize() > 0) {
533: if (min == max) {
534: // Single line selections:
535:
536: // Set selected value in the text field and enable
537: // the change button.
538: nameText.setText(model.get(min).toString());
539: setTargetType(model.get(min).toString());
540: }
541: }
542: setupButtons();
543: }
544: }
545: });
546:
547: list.addFocusListener(this );
548: }
549:
550: private void setupButtons() {
551: int min = list.getMinSelectionIndex();
552: int max = list.getMaxSelectionIndex();
553: String name = nameText.getText().trim();
554: addBtn.setEnabled(name.length() > 0);
555: if (min < 0) {
556: changeBtn.setEnabled(false);
557: removeBtn.setEnabled(false);
558: } else if (min == max) {
559: changeBtn.setEnabled(name.length() > 0);
560: removeBtn.setEnabled(true);
561: } else {
562: changeBtn.setEnabled(false);
563: removeBtn.setEnabled(true);
564: }
565: if (inFocus == list || name.length() == 0) {
566: getRootPane().setDefaultButton(nextButton);
567: } else {
568: getRootPane().setDefaultButton(addBtn);
569: }
570: }
571:
572: // --------------------------
573: // implemetns FocusListener
574: // --------------------------
575: private Component inFocus = null;
576:
577: public void focusGained(FocusEvent evt) {
578: Component comp = evt.getComponent();
579: inFocus = comp;
580: if (inFocus == list) {
581: DefaultListModel model = (DefaultListModel) list.getModel();
582: if (!model.isEmpty() && list.getLeadSelectionIndex() < 0) {
583: list.setSelectedIndex(0);
584: }
585: }
586: }
587:
588: public void focusLost(FocusEvent evt) {
589: inFocus = null;
590: }
591:
592: /** set the target type radio button */
593: private void setTargetType(String tname) {
594: ArrayList tlist = getMakefileData().getTargetList();
595: TargetData target;
596:
597: for (int i = 0; i < tlist.size(); i++) {
598: target = (TargetData) tlist.get(i);
599:
600: if (tname.equals(target.getName())) {
601: setTargetType(target.getTargetType());
602: return;
603: }
604: }
605: }
606:
607: /** set the target type radio button */
608: private void setTargetType(int type) {
609:
610: switch (type) {
611: case TargetData.COMPLEX_EXECUTABLE:
612: typeBG.setSelected(executable.getModel(), true);
613: break;
614:
615: case TargetData.COMPLEX_ARCHIVE:
616: typeBG.setSelected(archive.getModel(), true);
617: break;
618:
619: case TargetData.COMPLEX_SHAREDLIB:
620: typeBG.setSelected(sharedLib.getModel(), true);
621: break;
622:
623: case TargetData.COMPLEX_MAKE_TARGET:
624: typeBG.setSelected(recursiveMake.getModel(), true);
625: break;
626:
627: case TargetData.COMPLEX_CUSTOM_TARGET:
628: typeBG.setSelected(customTarget.getModel(), true);
629: break;
630: }
631: repaint();
632: }
633:
634: /** Create the widgets if not initialized. Also update the panel fields */
635: public void addNotify() {
636: ArrayList tlist = getMakefileData().getTargetList();
637: TargetData target;
638:
639: // Create the gui and initialize the fields
640: if (!initialized) {
641: create();
642:
643: if (tlist.size() > 0) {
644: target = (TargetData) tlist.get(tlist.size() - 1);
645: setTargetType(target.getTargetType());
646:
647: DefaultListModel model = (DefaultListModel) list
648: .getModel();
649: for (int i = 0; i < tlist.size(); i++) {
650: model.addElement(((TargetData) tlist.get(i))
651: .getName());
652: }
653: } else {
654: executable.setEnabled(true);
655: }
656: initialized = true;
657: }
658:
659: // If we have an existing target, does it need converting to a new type?
660: // Is the target a SIMPLE_*? If so try and convert it.
661: if (tlist.size() > 0
662: && (target = (TargetData) tlist.get(0)).getTargetType() < MakefileData.COMPLEX_MAKEFILE_TYPE) {
663: target.convert();
664: if (newKey == 0) {
665: newKey++; // so the next key isn't 0
666: }
667:
668: // Does a Create step exist? If it does it means this target
669: // has been converted more than once.
670: if (!wiz.targetExists(target.getKey())) {
671: wiz.addTarget(target.getTargetType(), target.getName(),
672: target.getKey());
673: }
674: }
675:
676: super .addNotify();
677: nameText.selectAll();
678: IpeUtils.requestFocus(nameText);
679: }
680:
681: /** Remove the file chooser if its showing */
682: public void removeNotify() {
683: super .removeNotify();
684:
685: if (fc != null && fc.isShowing()) {
686: Object o = fc.getTopLevelAncestor();
687: if (o != null && o instanceof JDialog) {
688: ((JDialog) o).dispose();
689: }
690: }
691: }
692: }
|