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.visualweb.gravy.properties;
043:
044: import java.awt.Component;
045: import java.awt.Frame;
046: import java.awt.Window;
047: import javax.swing.JComponent;
048: import org.netbeans.jellytools.Bundle;
049: import org.netbeans.modules.visualweb.gravy.Util;
050: import org.netbeans.modules.visualweb.gravy.MainWindowOperator;
051: import org.netbeans.modules.visualweb.gravy.TopComponentOperator;
052: import org.netbeans.modules.visualweb.gravy.actions.HelpAction;
053: import org.netbeans.modules.visualweb.gravy.actions.PropertiesAction;
054: import org.netbeans.modules.visualweb.gravy.actions.ShowDescriptionAreaAction;
055: import org.netbeans.modules.visualweb.gravy.actions.SortByCategoryAction;
056: import org.netbeans.modules.visualweb.gravy.actions.SortByNameAction;
057: import org.netbeans.jemmy.ComponentChooser;
058: import org.netbeans.jemmy.JemmyException;
059: import org.netbeans.jemmy.JemmyProperties;
060: import org.netbeans.jemmy.TestOut;
061: import org.netbeans.jemmy.Timeouts;
062: import org.netbeans.jemmy.Waitable;
063: import org.netbeans.jemmy.Waiter;
064: import org.netbeans.jemmy.operators.ContainerOperator;
065: import org.netbeans.jemmy.operators.JButtonOperator;
066: import org.netbeans.jemmy.operators.JLabelOperator;
067: import org.netbeans.jemmy.operators.JTabbedPaneOperator;
068: import org.netbeans.jemmy.operators.JTableOperator;
069: import org.netbeans.jemmy.operators.JTextAreaOperator;
070: import org.netbeans.jemmy.operators.WindowOperator;
071: import org.openide.explorer.propertysheet.PropertySheet;
072: import org.openide.windows.TopComponent;
073:
074: /**
075: * Handles org.openide.explorer.propertysheet.PropertySheet which
076: * represents IDE property sheet TopComponent.
077: * It includes JTable with properties and optional description area.
078: * Use {@link Property} class or its descendants to work with properties.
079: * <p>
080: * Usage:<br>
081: * <pre>
082: PropertySheetOperator pso = new PropertySheetOperator("Properties of MyClass");
083: new Property(pso, "Arguments").setValue("arg1 arg2");
084: pso.sortByName();
085: System.out.println("Number of properties="+pso.tblSheet().getRowCount());
086: pso.sortByCategory();
087: * </pre>
088: *
089: * @see Property
090: * @see PropertiesAction
091: * @see SortByCategoryAction
092: * @see SortByNameAction
093: * @see ShowDescriptionAreaAction
094: * @see HelpAction
095: */
096: public class PropertySheetOperator extends TopComponentOperator {
097: // In IDE PropertySheet extends JPanel (parent org.netbeans.core.NbSheet extends TopComponent).
098: /* In new window system global property sheet resides in main window and extends TopComponent.
099: * Other property sheets are opened in dialog and they do not behave as TopComponents.
100: */
101:
102: /** JTable representing property sheet. */
103: private JTableOperator _tblSheet;
104: private JLabelOperator _lblDescriptionHeader;
105: private JTextAreaOperator _txtDescription;
106: private JButtonOperator _btHelp;
107:
108: /** "No Properties" property sheet. */
109: public static final int MODE_NO_PROPERTIES = 0;
110: /** "Properties of" property sheet. */
111: public static final int MODE_PROPERTIES_OF_ONE_OBJECT = 1;
112: /** "Properties of Multiple Objects" property sheet. */
113: public static final int MODE_PROPERTIES_OF_MULTIPLE_OBJECTS = 2;
114:
115: /** "Properties" */
116: private static final String propertiesText = Bundle
117: .getStringTrimmed("org.openide.actions.Bundle",
118: "Properties");
119:
120: /** Generic constructor
121: * @param sheet instance of PropertySheet
122: */
123: public PropertySheetOperator(JComponent sheet) {
124: super (sheet);
125: }
126:
127: /** Waits for property sheet anywhere in IDE. */
128: public PropertySheetOperator() {
129: this (waitPropertySheet(null, 0));
130: }
131:
132: /** Waits for property sheet with name according to given mode ("No Properties",
133: * "Properties of" or "Properties of Multiple Objects").
134: * @param mode type of shown properties
135: * @see #MODE_NO_PROPERTIES
136: * @see #MODE_PROPERTIES_OF_ONE_OBJECT
137: * @see #MODE_PROPERTIES_OF_MULTIPLE_OBJECTS
138: */
139: public PropertySheetOperator(int mode) {
140: this (mode, "");
141: }
142:
143: /** Waits for property sheet with name according to given mode ("No Properties",
144: * "Properties of" or "Properties of Multiple Objects") plus objectName
145: * in case of one object property sheet. In case of usage
146: * <code>
147: * new PropertySheetOperator(PropertySheetOperator.MODE_PROPERTIES_OF_ONE_OBJECT, "MyClass");
148: * </code>
149: * will be searched property sheet with name "Properties of MyClass" (on
150: * English locale).
151: * @param mode type of shown properties
152: * @param objectName name of object for that properties are shown (e.g. "MyClass")
153: * @see #MODE_NO_PROPERTIES
154: * @see #MODE_PROPERTIES_OF_ONE_OBJECT
155: * @see #MODE_PROPERTIES_OF_MULTIPLE_OBJECTS
156: */
157: public PropertySheetOperator(int mode, String objectName) {
158: this (Bundle.getString("org.netbeans.core.Bundle",
159: "CTL_FMT_GlobalProperties", new Object[] {
160: new Integer(mode), objectName }));
161: }
162:
163: /** Waits for property sheet with given name. Typically sheet
164: * name is used as window title.
165: * @param sheetName name of sheet to find (e.g. "Properties of MyClass")
166: */
167: public PropertySheetOperator(String sheetName) {
168: this (waitPropertySheet(sheetName, 0));
169: }
170:
171: /** Waits for property sheet with given name in specified
172: * container.
173: * @param contOper where to find
174: * @param sheetName name of sheet to find (e.g. "Properties of MyClass")
175: */
176: public PropertySheetOperator(ContainerOperator contOper,
177: String sheetName) {
178: super ((JComponent) contOper
179: .waitSubComponent(new PropertySheetSubchooser(
180: sheetName, contOper.getComparator())));
181: copyEnvironment(contOper);
182: }
183:
184: /** Waits for property sheet in specified ContainerOperator.
185: * It is for example PropertySheet in Options window.
186: * @param contOper where to find
187: */
188: public PropertySheetOperator(ContainerOperator contOper) {
189: this (contOper, 0);
190: }
191:
192: /** Waits for index-th property sheet in specified ContainerOperator.
193: * @param contOper where to find
194: * @param index int index
195: */
196: public PropertySheetOperator(ContainerOperator contOper, int index) {
197: super ((JComponent) contOper.waitSubComponent(
198: new PropertySheetSubchooser(), index));
199: copyEnvironment(contOper);
200: }
201:
202: /** Invokes properties by default action on currently selected object.
203: * @return instance of PropertySheetOperator
204: * @see org.netbeans.modules.visualweb.gravy.actions.PropertiesAction
205: */
206: public static PropertySheetOperator invoke() {
207: new PropertiesAction().perform();
208: return new PropertySheetOperator();
209: }
210:
211: /** Returns JTableOperator representing SheetTable of this property sheet.
212: * @return instance of JTableOperator
213: */
214: public JTableOperator tblSheet() {
215: if (_tblSheet == null) {
216: _tblSheet = new JTableOperator(this );
217: }
218: return _tblSheet;
219: }
220:
221: /** Returns JLabelOperator representing header of description area.
222: * @return instance of JLabelOperator
223: */
224: public JLabelOperator lblDescriptionHeader() {
225: if (_lblDescriptionHeader == null) {
226: _lblDescriptionHeader = new JLabelOperator(this );
227: }
228: return _lblDescriptionHeader;
229: }
230:
231: /** Returns JTextAreaOperator representing text from description area.
232: * @return instance of JTextAreaOperator
233: */
234: public JTextAreaOperator txtDescription() {
235: if (_txtDescription == null) {
236: _txtDescription = new JTextAreaOperator(this );
237: }
238: return _txtDescription;
239: }
240:
241: /** Returns JButtonOperator representing help button of description area.
242: * @return instance of JButtonOperator
243: */
244: public JButtonOperator btHelp() {
245: if (_btHelp == null) {
246: _btHelp = new JButtonOperator(this );
247: }
248: return _btHelp;
249: }
250:
251: /** Gets JTabbedPaneOperator of this property sheet.
252: * @return instance of JTabbedPaneOperator
253: * @deprecated JTabbedPane is no more used in property sheet.
254: */
255: public JTabbedPaneOperator tbpPropertySheetTabbedPane() {
256: throw new JemmyException(
257: "Don't use this! JTabbedPane no more used in property sheet.");
258: /*
259: if(_tbpPropertySheetTabPane == null) {
260: _tbpPropertySheetTabPane = new JTabbedPaneOperator(this);
261: }
262: return _tbpPropertySheetTabPane;
263: */
264: }
265:
266: /** Gets PropertySheetTabOperator with given name. It selects requested tab
267: * if exist and it is not active.
268: * @param tabName name of tab to find.
269: * @return instance of PropertySheetTabOperator
270: * @deprecated will be removed because of property sheet rewrite
271: */
272: public PropertySheetTabOperator getPropertySheetTabOperator(
273: String tabName) {
274: return new PropertySheetTabOperator(this , tabName);
275: }
276:
277: /** Gets PropertySheetToolbarOperator for this property sheet.
278: * @return instance of PropertySheetToolbarOperator
279: * @deprecated Tool bar no more used in property sheet.
280: */
281: public PropertySheetToolbarOperator getToolbar() {
282: throw new JemmyException(
283: "Don't use this! Tool bar no more used in property sheet.");
284: //return new PropertySheetToolbarOperator(this);
285: }
286:
287: /** Gets text of header from description area.
288: * @return text of header from description area
289: */
290: public String getDescriptionHeader() {
291: return lblDescriptionHeader().getText();
292: }
293:
294: /** Gest description from description area.
295: * @return description from description area.
296: */
297: public String getDescription() {
298: return txtDescription().getText();
299: }
300:
301: /** Sorts properties by name by calling of popup menu on property sheet. */
302: public void sortByName() {
303: new SortByNameAction().perform(this );
304: }
305:
306: /** Sorts properties by category by calling of popup menu on property sheet. */
307: public void sortByCategory() {
308: new SortByCategoryAction().perform(this );
309: }
310:
311: /** Shows or hides description area depending on whether it is already shown
312: * or not. It just invokes Show description area popup menu item.
313: */
314: public void showDescriptionArea() {
315: new ShowDescriptionAreaAction().perform(this );
316: }
317:
318: /** Shows help by calling popup menu on property sheet. */
319: public void help() {
320: new HelpAction().performPopup(this );
321: }
322:
323: /** Performs verification by accessing all sub-components */
324: public void verify() {
325: tblSheet();
326: }
327:
328: /** Closes this property sheet and waits until
329: * it is not closed. In fact it closes container in which this property
330: * sheet is placed. It can be a TopComponent in the main window or in a separate
331: * frame, or a dialog.
332: */
333:
334: public void close() {
335: if (getSource() instanceof TopComponent) {
336: // run in dispatch thread
337: boolean canClose = runMapping(new MapBooleanAction(
338: "canClose") {
339: public boolean map() {
340: return ((TopComponent) getSource()).canClose(null,
341: true);
342: }
343: });
344: if (canClose) {
345: // if it is regular TopComponent and it can be closed
346: super .close();
347: return;
348: }
349: }
350: // close window where property sheet is hosted but not main window
351: if (getWindow() != Util.getMainWindow().getSource()) {
352: new WindowOperator(getWindow()).close();
353: }
354: }
355:
356: /** Finds property sheet anywhere in IDE. First it tries to find TopComponent
357: * representing global properties and if not found, it tries to find
358: * property sheet in all dialogs owned by Main Window or other frames in SDI.
359: * @param sheetName name of property sheet
360: * @param index index of property sheet
361: */
362: private static JComponent findPropertySheet(String sheetName,
363: int index) {
364: // try to find PS in MainWindow
365: JComponent comp = findTopComponent(null, sheetName, index,
366: new PropertySheetSubchooser());
367: if (comp != null) {
368: return comp;
369: }
370: /* mdk - isCompactMode
371: // Try to find PS in a dialog which is owned by Main window or by other
372: // frame in SDI.
373: Frame[] frames;
374: MainWindowOperator mwo = Util.getMainWindow();
375: if(mwo.isCompactMode()) {
376: frames = new Frame[] {(Frame)mwo.getSource()};
377: } else {
378: frames = Frame.getFrames();
379: }
380: for(int frameIndex=0;frameIndex<frames.length;frameIndex++) {
381: Window[] windows = frames[frameIndex].getOwnedWindows();
382: for(int i=0;i<windows.length;i++) {
383: if(windows[i].isShowing()) {
384: // only showing windows are interesting
385: // create windows operator for found window
386: WindowOperator wo = new WindowOperator(windows[i]);
387: // supress output
388: wo.setOutput(TestOut.getNullOutput());
389: // try to find PropertySheet subcomponent
390: comp = (JComponent)wo.findSubComponent(
391: new PropertySheetSubchooser(sheetName, mwo.getComparator()),
392: index);
393: if(comp != null) {
394: return comp;
395: }
396: }
397: }
398: }*/
399: return null;
400: }
401:
402: /** Waits for property sheet anywhere in IDE. First it tries to find TopComponent
403: * representing global properties and if not found, it tries to find
404: * property sheet in all dialogs owned by Main Window or other frames in SDI.
405: * @param sheetName name of property sheet
406: * @param index index of property sheet
407: */
408: private static JComponent waitPropertySheet(final String sheetName,
409: final int index) {
410: try {
411: Waiter waiter = new Waiter(new Waitable() {
412: public Object actionProduced(Object obj) {
413: return findPropertySheet(sheetName, index);
414: }
415:
416: public String getDescription() {
417: return ("Wait PropertySheet with name=" + sheetName
418: + " index=" + index + " loaded");
419: }
420: });
421: Timeouts times = JemmyProperties.getCurrentTimeouts()
422: .cloneThis();
423: times
424: .setTimeout(
425: "Waiter.WaitingTime",
426: times
427: .getTimeout("ComponentOperator.WaitComponentTimeout"));
428: waiter.setTimeouts(times);
429: waiter.setOutput(JemmyProperties.getCurrentOutput());
430: return (JComponent) waiter.waitAction(null);
431: } catch (InterruptedException e) {
432: throw new JemmyException("Interrupted.", e);
433: }
434: }
435:
436: /** SubChooser to determine find property sheet.
437: * Used in constructors.
438: */
439: private static final class PropertySheetSubchooser implements
440: ComponentChooser {
441:
442: private String sheetName;
443: private StringComparator comparator;
444:
445: public PropertySheetSubchooser() {
446: }
447:
448: public PropertySheetSubchooser(String sheetName,
449: StringComparator comparator) {
450: this .sheetName = sheetName;
451: this .comparator = comparator;
452: }
453:
454: public boolean checkComponent(Component comp) {
455: if (comp instanceof PropertySheet) {
456: if (sheetName == null) {
457: return true;
458: } else {
459: if (comp instanceof TopComponent) {
460: String name = ((TopComponent) comp).getName();
461: if (name == null) {
462: name = comp.getName();
463: }
464: return comparator.equals(name, sheetName);
465: }
466: }
467: }
468: return false;
469: }
470:
471: public String getDescription() {
472: return "org.openide.explorer.propertysheet.PropertySheet";
473: }
474: }
475: }
|