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.jellytools;
043:
044: import java.awt.Component;
045: import java.awt.Container;
046: import java.awt.Point;
047: import java.awt.Rectangle;
048: import java.lang.reflect.InvocationTargetException;
049: import javax.swing.JLabel;
050: import javax.swing.table.JTableHeader;
051: import javax.swing.tree.TreePath;
052:
053: import org.netbeans.core.projects.SettingChildren.FileStateProperty;
054:
055: import org.netbeans.jellytools.actions.Action;
056: import org.netbeans.jellytools.actions.OptionsViewAction;
057: import org.netbeans.jellytools.properties.PropertySheetOperator;
058: import org.netbeans.jemmy.ComponentChooser;
059: import org.netbeans.jemmy.ComponentSearcher;
060: import org.netbeans.jemmy.EventTool;
061: import org.netbeans.jemmy.JemmyException;
062: import org.netbeans.jemmy.TimeoutExpiredException;
063: import org.netbeans.jemmy.Timeouts;
064: import org.netbeans.jemmy.Waitable;
065: import org.netbeans.jemmy.Waiter;
066: import org.netbeans.jemmy.operators.ComponentOperator;
067: import org.netbeans.jemmy.operators.JButtonOperator;
068: import org.netbeans.jemmy.operators.JComboBoxOperator;
069: import org.netbeans.jemmy.operators.JDialogOperator;
070: import org.netbeans.jemmy.operators.JLabelOperator;
071: import org.netbeans.jemmy.operators.Operator.StringComparator;
072:
073: /**
074: * Provides access to the Options window and it's subcomponents.
075: * Use PropertySheet class to access properties.
076: * treeTable() method returns TreeTable operator for
077: * options list accessing.
078: */
079: public class OptionsOperator extends NbDialogOperator {
080:
081: /**
082: * Constant used for indication of user property definition level
083: * (first column after ">>").
084: */
085: public static final int USER_LEVEL = 2;
086:
087: /**
088: * Constant used for indication of default property definition level
089: * (second column after ">>").
090: */
091: public static final int DEFAULT_LEVEL = 3;
092:
093: private static final Action invokeAction = new OptionsViewAction();
094:
095: private static final long BEFORE_EDITING_TIMEOUT = 2000;
096:
097: private static int DEFINE_HERE = 0;
098:
099: private static final String CLASSIC_VIEW_LABEL = Bundle
100: .getStringTrimmed("org.netbeans.modules.options.Bundle",
101: "CTL_Classic");
102: private static final String MODERN_VIEW_LABEL = Bundle
103: .getStringTrimmed("org.netbeans.modules.options.Bundle",
104: "CTL_Modern");
105:
106: /**
107: * Waits for the Options window opened
108: */
109: public OptionsOperator() {
110: super (waitJDialog(optionsSubchooser));
111: // wait until settings are loaded
112: // "Loading Settings ..."
113: String loadingLabel = Bundle.getString(
114: "org.netbeans.modules.options.Bundle",
115: "CTL_Loading_Options");
116: long waitTimeout = this .getTimeouts().getTimeout(
117: "ComponentOperator.WaitComponentTimeout");
118: try {
119: this .getTimeouts().setTimeout(
120: "ComponentOperator.WaitComponentTimeout", 5000);
121: new JLabelOperator(this , loadingLabel)
122: .waitComponentShowing(false);
123: } catch (TimeoutExpiredException e) {
124: // ignore - options already loaded
125: } finally {
126: // set previous timeout
127: this .getTimeouts().setTimeout(
128: "ComponentOperator.WaitComponentTimeout",
129: waitTimeout);
130: }
131: }
132:
133: /**
134: * Invoces Options window by the menu operation.
135: * @return OptionsOperator instance
136: */
137: public static OptionsOperator invoke() {
138: invokeAction.perform();
139: return new OptionsOperator();
140: }
141:
142: static {
143: Timeouts.initDefault("OptionsOperator.BeforeEditingTimeout",
144: BEFORE_EDITING_TIMEOUT);
145: }
146:
147: //subcomponents
148:
149: /** Returns operator of "Classic View" button.
150: * @return JButtonOperator instance of "Classic View" button
151: */
152: public JButtonOperator btClassicView() {
153: // we cannot cache oeprator because everytime a new dialog is created
154: return new JButtonOperator(this , CLASSIC_VIEW_LABEL);
155: }
156:
157: /** Returns operator of "Modern View" button.
158: * @return JButtonOperator instance of "Modern View" button
159: */
160: public JButtonOperator btModernView() {
161: // we cannot cache oeprator because everytime a new dialog is created
162: return new JButtonOperator(this , MODERN_VIEW_LABEL);
163: }
164:
165: /** Getter for table containing property list and
166: * property definition levels.
167: * @return TreeTableOperator instance
168: */
169: public TreeTableOperator treeTable() {
170: // we cannot cache oeprator because everytime a new dialog is created
171: return new TreeTableOperator(this );
172: }
173:
174: //shortcuts
175: /** Selects an option in the options tree.
176: * @param optionPath Path to the option in left (tree-like) column.
177: * @return row index of selected node (starts at 0)
178: */
179: public int selectOption(String optionPath) {
180: TreePath path = treeTable().tree().findPath(optionPath, "|");
181: if (!treeTable().tree().isPathSelected(path)) {
182: treeTable().tree().selectPath(path);
183: }
184: int result = treeTable().tree().getRowForPath(path);
185: treeTable().scrollToCell(result, 0);
186: new EventTool().waitNoEvent(500);
187: return (result);
188: }
189:
190: /** Selects an option in the options tree, waits for property sheet
191: * corresponding to selected node and returns instance of PropertySheetOperator.
192: * @param optionPath Path to the option in left (tree-like) column.
193: * @return PropertySheetOperator of selected option
194: */
195: public PropertySheetOperator getPropertySheet(String optionPath) {
196: selectOption(optionPath);
197: // wait for property sheet corresponding with selected node
198: final String nodeName = treeTable().tree().getSelectionPath()
199: .getLastPathComponent().toString();
200: try {
201: return (PropertySheetOperator) new Waiter(new Waitable() {
202: public Object actionProduced(Object optionsOper) {
203: PropertySheetOperator pso = new PropertySheetOperator(
204: (OptionsOperator) optionsOper);
205: return pso.getDescriptionHeader().equals(nodeName) ? pso
206: : null;
207: }
208:
209: public String getDescription() {
210: return ("Wait Property sheet for \"" + nodeName + "\" is showing.");
211: }
212: }).waitAction(this );
213: } catch (InterruptedException e) {
214: throw new JemmyException("Interrupted.", e);
215: }
216: }
217:
218: //definition levels
219:
220: /**
221: * Shows definition levels column by clicking on the "<<" table
222: * column title.
223: */
224: public void showLevels() {
225: if (treeTable().getColumnCount() == 2) {
226: clickOnSecondHeader();
227: }
228: }
229:
230: /**
231: * Hides definition levels column by clicking on the ">>" table
232: * column title.
233: */
234: public void hideLevels() {
235: if (treeTable().getColumnCount() > 2) {
236: clickOnSecondHeader();
237: }
238: }
239:
240: /**
241: * Sets definition level for the option.
242: * @param optionPath Path to the option in left (tree-like) column.
243: * @param level One of the USER_LEVEL or DEFAULT_LEVEL
244: */
245: public void setLevel(String optionPath, final int level) {
246: showLevels();
247: int curLevel = getLevel(optionPath);
248: getOutput().printLine(
249: "Setting " + level + " level for \"" + optionPath
250: + "\" option. \nCurrent level: " + curLevel);
251: final int row = selectOption(optionPath);
252: if (level > curLevel) {
253: produceNoBlocking(new NoBlockingAction(
254: "Setting property definition level") {
255: public Object doAction(Object param) {
256: setLevel(row, level);
257: return (null);
258: }
259: });
260: JDialogOperator question = new JDialogOperator(Bundle
261: .getString("org.openide.Bundle",
262: "NTF_QuestionTitle"));
263: new JButtonOperator(question, Bundle.getString(
264: "org.openide.Bundle", "CTL_YES")).push();
265: } else if (level < curLevel) {
266: setLevel(row, level);
267: }
268: }
269:
270: /**
271: * Gets definition level for the option.
272: * @param optionPath Path to the option in left (tree-like) column.
273: * @return level One of the USER_LEVEL or DEFAULT_LEVEL
274: */
275: public int getLevel(String optionPath) {
276: int row = selectOption(optionPath);
277: if (getValue(row, USER_LEVEL) == DEFINE_HERE) {
278: return USER_LEVEL;
279: } else if (getValue(row, DEFAULT_LEVEL) == DEFINE_HERE) {
280: return DEFAULT_LEVEL;
281: }
282: return -1;
283: }
284:
285: /** Make an option to be difined on the user level.
286: * @param optionPath Path to the option in left (tree-like) column.
287: */
288: public void setUserLevel(String optionPath) {
289: setLevel(optionPath, USER_LEVEL);
290: }
291:
292: /** Make an option to be difined on the default level.
293: * @param optionPath Path to the option in left (tree-like) column.
294: */
295: public void setDefaultLevel(String optionPath) {
296: setLevel(optionPath, DEFAULT_LEVEL);
297: }
298:
299: //protected
300:
301: /** Sets a level for the row index.
302: * @param row row index in the table
303: * @param level level value
304: */
305: protected void setLevel(int row, int level) {
306: if (level == USER_LEVEL) {
307: defineHere(row, level);
308: } else if (level == DEFAULT_LEVEL) {
309: revertLevel(row, level);
310: }
311: }
312:
313: /** Gets a value of the level definition mark.
314: * @param row row index in the table
315: * @param column column index in the table
316: * @return value of the level definition mark
317: */
318: protected int getValue(int row, int column) {
319: try {
320: FileStateProperty property = ((FileStateProperty) treeTable()
321: .getValueAt(row, column));
322: return (((Integer) property.getValue()).intValue());
323: } catch (IllegalAccessException e) {
324: throw new JemmyException("Can not access value!", e);
325: } catch (InvocationTargetException e) {
326: throw new JemmyException("Can not access value!", e);
327: }
328: }
329:
330: /** Chooses "Revert Def" from the combobox.
331: * @param row row index in the table
332: * @param colIndex column index in the table
333: */
334: protected void revertLevel(final int row, final int colIndex) {
335: editLevel(row, colIndex, Bundle.getString(
336: "org.netbeans.core.projects.Bundle",
337: "LBL_action_revert"));
338: }
339:
340: /** Chooses "Define Here" from the combobox.
341: * @param row row index in the table
342: * @param colIndex column index in the table
343: */
344: protected void defineHere(int row, int colIndex) {
345: editLevel(row, colIndex, Bundle.getString(
346: "org.netbeans.core.projects.Bundle",
347: "LBL_action_define"));
348: }
349:
350: /**
351: * Causes table editing and chooses a value in the combobox.
352: * @param rowIndex Row index.
353: * @param colIndex Column index. One of the columns containing
354: * level definition marks.
355: * @param value String value to be choosed in the combobox.
356: */
357: protected void editLevel(int rowIndex, int colIndex, String value) {
358: Point pnt = treeTable().getPointToClick(rowIndex, colIndex);
359: treeTable().clickOnCell(rowIndex, colIndex);
360: JComboBoxOperator combo = new JComboBoxOperator(treeTable());
361: getTimeouts().sleep("OptionsOperator.BeforeEditingTimeout");
362: combo.selectItem(value);
363: }
364:
365: /**
366: * Clicks on "<<" column header.
367: */
368: protected void clickOnSecondHeader() {
369: JTableHeader header = treeTable().getTableHeader();
370: Rectangle rect = header.getHeaderRect(1);
371: new ComponentOperator(header).clickMouse(rect.x + rect.width
372: / 2, rect.y + rect.height / 2, 1);
373: }
374:
375: // Modern view Options
376:
377: /** Switch to classic view of options. */
378: public void switchToClassicView() {
379: if (JButtonOperator.findJButton((Container) this .getSource(),
380: CLASSIC_VIEW_LABEL, true, true) != null) {
381: btClassicView().push();
382: }
383: sourceInternal = new OptionsOperator().getSource();
384: }
385:
386: private Component sourceInternal;
387:
388: /** Returns component.
389: * @return component.
390: */
391: public Component getSource() {
392: if (sourceInternal == null) {
393: sourceInternal = super .getSource();
394: }
395: return sourceInternal;
396: }
397:
398: /** Switch to modern view of options. */
399: public void switchToModernView() {
400: if (JButtonOperator.findJButton((Container) this .getSource(),
401: MODERN_VIEW_LABEL, true, true) != null) {
402: btModernView().push();
403: }
404: sourceInternal = new OptionsOperator().getSource();
405: }
406:
407: /** Selects a category with given name.
408: * @param name name of category to be selected
409: */
410: public void selectCategory(final String name) {
411: final StringComparator comparator = this .getComparator();
412: new JLabelOperator(this , new ComponentChooser() {
413: public boolean checkComponent(Component comp) {
414: if (comp
415: .getClass()
416: .getName()
417: .equals(
418: "org.netbeans.modules.options.OptionsPanel$CategoryButton")) { // NOI18N
419: if (((JLabel) comp).getText() != null) {
420: return comparator.equals(((JLabel) comp)
421: .getText(), name);
422: }
423: }
424: return false;
425: }
426:
427: public String getDescription() {
428: return "OptionsPanel$CategoryButton with text " + name; // NOI18N
429: }
430: }).clickMouse();
431: }
432:
433: /** Selects General category. */
434: public void selectGeneral() {
435: Bundle.getStringTrimmed(
436: "org.netbeans.modules.options.advanced.Bundle",
437: "CTL_Advanced_Options");
438: selectCategory(Bundle.getStringTrimmed(
439: "org.netbeans.core.ui.options.general.Bundle",
440: "CTL_General_Options"));
441: }
442:
443: /** Selects Editor category. */
444: public void selectEditor() {
445: selectCategory(Bundle.getStringTrimmed(
446: "org.netbeans.modules.options.editor.Bundle",
447: "CTL_Editor"));
448: }
449:
450: /** Selects Fonts & Colors category. */
451: public void selectFontAndColors() {
452: selectCategory(Bundle.getStringTrimmed(
453: "org.netbeans.modules.options.colors.Bundle",
454: "CTL_Font_And_Color_Options"));
455: }
456:
457: /** Selects Keymap category. */
458: public void selectKeymap() {
459: selectCategory(Bundle.getStringTrimmed(
460: "org.netbeans.modules.options.keymap.Bundle",
461: "CTL_Keymap_Options"));
462: }
463:
464: /** Selects Miscellaneous category. */
465: public void selectMiscellaneous() {
466: selectCategory(Bundle.getStringTrimmed(
467: "org.netbeans.modules.options.advanced.Bundle",
468: "CTL_Advanced_Options"));
469: }
470:
471: /** Performs verification by accessing all sub-components */
472: public void verify() {
473: btClose();
474: btHelp();
475: treeTable().verify();
476: }
477:
478: /** SubChooser to determine Options or Advanced Options dialog.
479: * Used in constructor.
480: */
481: private static final ComponentChooser optionsSubchooser = new ComponentChooser() {
482: public boolean checkComponent(Component comp) {
483: return null != new ComponentSearcher((Container) comp)
484: .findComponent(new ComponentChooser() {
485: public boolean checkComponent(Component comp) {
486: return comp.getClass().getName().endsWith(
487: "OptionsPanel"); //NOI18N
488: }
489:
490: public String getDescription() {
491: return "org.netbeans.core.actions.OptionsAction$OptionsPanel or "
492: + // NOI18N
493: "org.netbeans.modules.options.OptionsPanel"; // NOI18N
494: }
495: });
496: }
497:
498: public String getDescription() {
499: return "Options"; // NOI18N
500: }
501: };
502: }
|