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-2006 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.swing.tabcontrol.plaf;
043:
044: import java.awt.Component;
045: import java.awt.Image;
046: import java.awt.event.ActionEvent;
047: import java.awt.event.ActionListener;
048: import java.awt.event.FocusEvent;
049: import java.awt.event.MouseEvent;
050: import java.net.URL;
051: import java.util.HashMap;
052: import java.util.Map;
053: import java.util.logging.Level;
054: import java.util.logging.Logger;
055: import javax.imageio.ImageIO;
056: import javax.swing.Action;
057: import javax.swing.Icon;
058: import javax.swing.ImageIcon;
059: import javax.swing.Timer;
060: import javax.swing.ToolTipManager;
061: import org.netbeans.swing.tabcontrol.TabData;
062: import org.netbeans.swing.tabcontrol.TabDisplayer;
063: import org.netbeans.swing.tabcontrol.TabListPopupAction;
064: import org.netbeans.swing.tabcontrol.WinsysInfoForTabbed;
065:
066: /**
067: * A factory to create tab control buttons.
068: *
069: * @since 1.9
070: * @author S. Aubrecht
071: */
072: public class TabControlButtonFactory {
073:
074: private static IconLoader iconCache;
075:
076: private TabControlButtonFactory() {
077: }
078:
079: public static Icon getIcon(String iconPath) {
080: if (null == iconCache)
081: iconCache = new IconLoader();
082: return iconCache.obtainIcon(iconPath);
083: }
084:
085: /**
086: * Create default close button.
087: */
088: public static TabControlButton createCloseButton(
089: TabDisplayer displayer) {
090: return new CloseButton(displayer);
091: }
092:
093: /**
094: * Create default auto-hide/pin button. The button changes icons depending
095: * on the state of tab component.
096: */
097: public static TabControlButton createSlidePinButton(
098: TabDisplayer displayer) {
099: return new SlidePinButton(displayer);
100: }
101:
102: /**
103: * Create default maximize/restore button. The button changes icons depending
104: * on the state of tab component.
105: */
106: public static TabControlButton createMaximizeRestoreButton(
107: TabDisplayer displayer, boolean showBorder) {
108: return new MaximizeRestoreButton(displayer, showBorder);
109: }
110:
111: public static TabControlButton createScrollLeftButton(
112: TabDisplayer displayer, Action scrollAction,
113: boolean showBorder) {
114: TabControlButton button = new TimerButton(
115: TabControlButton.ID_SCROLL_LEFT_BUTTON, displayer,
116: scrollAction, showBorder);
117: button.setToolTipText(java.util.ResourceBundle.getBundle(
118: "org/netbeans/swing/tabcontrol/plaf/Bundle").getString(
119: "Tip_Scroll_Documents_Left"));
120: return button;
121: }
122:
123: public static TabControlButton createScrollRightButton(
124: TabDisplayer displayer, Action scrollAction,
125: boolean showBorder) {
126: TabControlButton button = new TimerButton(
127: TabControlButton.ID_SCROLL_RIGHT_BUTTON, displayer,
128: scrollAction, showBorder);
129: button.setToolTipText(java.util.ResourceBundle.getBundle(
130: "org/netbeans/swing/tabcontrol/plaf/Bundle").getString(
131: "Tip_Scroll_Documents_Right"));
132: return button;
133: }
134:
135: public static TabControlButton createDropDownButton(
136: TabDisplayer displayer, boolean showBorder) {
137: return new DropDownButton(displayer, showBorder);
138: }
139:
140: private static class CloseButton extends TabControlButton {
141:
142: public CloseButton(TabDisplayer displayer) {
143: super (TabControlButton.ID_CLOSE_BUTTON, displayer);
144: setToolTipText(java.util.ResourceBundle.getBundle(
145: "org/netbeans/swing/tabcontrol/plaf/Bundle")
146: .getString("Tip_Close_Window"));
147: }
148:
149: protected String getTabActionCommand(ActionEvent e) {
150: // if( (e.getModifiers() & ActionEvent.SHIFT_MASK) > 0 )
151: // return TabDisplayer.COMMAND_CLOSE_ALL;
152: // else if( (e.getModifiers() & ActionEvent.ALT_MASK) > 0 )
153: // return TabDisplayer.COMMAND_CLOSE_ALL_BUT_THIS;
154: return TabDisplayer.COMMAND_CLOSE;
155: }
156: }
157:
158: private static class SlidePinButton extends TabControlButton {
159:
160: public SlidePinButton(TabDisplayer displayer) {
161: super (displayer);
162: ToolTipManager toolTipManager = ToolTipManager
163: .sharedInstance();
164: toolTipManager.registerComponent(this );
165: }
166:
167: protected String getTabActionCommand(ActionEvent e) {
168: if (getButtonId() == TabControlButton.ID_PIN_BUTTON)
169: return TabDisplayer.COMMAND_DISABLE_AUTO_HIDE;
170: return TabDisplayer.COMMAND_ENABLE_AUTO_HIDE;
171: }
172:
173: protected int getButtonId() {
174: int retValue = TabControlButton.ID_PIN_BUTTON;
175: Component currentTab = getActiveTab(getTabDisplayer());
176: if (null != currentTab) {
177: WinsysInfoForTabbed winsysInfo = getTabDisplayer()
178: .getWinsysInfo();
179: if (null != winsysInfo) {
180: Object orientation = winsysInfo
181: .getOrientation(currentTab);
182: if (TabDisplayer.ORIENTATION_EAST
183: .equals(orientation))
184: retValue = TabControlButton.ID_SLIDE_RIGHT_BUTTON;
185: else if (TabDisplayer.ORIENTATION_WEST
186: .equals(orientation))
187: retValue = TabControlButton.ID_SLIDE_LEFT_BUTTON;
188: else if (TabDisplayer.ORIENTATION_SOUTH
189: .equals(orientation))
190: retValue = TabControlButton.ID_SLIDE_DOWN_BUTTON;
191: }
192: }
193:
194: return retValue;
195: }
196:
197: public String getToolTipText() {
198: if (getButtonId() == TabControlButton.ID_PIN_BUTTON)
199: return java.util.ResourceBundle.getBundle(
200: "org/netbeans/swing/tabcontrol/plaf/Bundle")
201: .getString("Tip_Pin");
202: return java.util.ResourceBundle.getBundle(
203: "org/netbeans/swing/tabcontrol/plaf/Bundle")
204: .getString("Tip_Minimize_Window");
205: }
206: }
207:
208: private static class MaximizeRestoreButton extends TabControlButton {
209:
210: public MaximizeRestoreButton(TabDisplayer displayer,
211: boolean showBorder) {
212: super (-1, displayer, showBorder);
213: ToolTipManager toolTipManager = ToolTipManager
214: .sharedInstance();
215: toolTipManager.registerComponent(this );
216: }
217:
218: protected String getTabActionCommand(ActionEvent e) {
219: return TabDisplayer.COMMAND_MAXIMIZE;
220: }
221:
222: protected int getButtonId() {
223: int retValue = TabControlButton.ID_MAXIMIZE_BUTTON;
224: Component currentTab = getActiveTab(getTabDisplayer());
225: if (null != currentTab) {
226: WinsysInfoForTabbed winsysInfo = getTabDisplayer()
227: .getWinsysInfo();
228: if (null != winsysInfo) {
229: if (winsysInfo.inMaximizedMode(currentTab)) {
230: retValue = TabControlButton.ID_RESTORE_BUTTON;
231: }
232: }
233: }
234:
235: return retValue;
236: }
237:
238: public String getToolTipText() {
239: if (getButtonId() == TabControlButton.ID_MAXIMIZE_BUTTON)
240: return java.util.ResourceBundle.getBundle(
241: "org/netbeans/swing/tabcontrol/plaf/Bundle")
242: .getString("Tip_Maximize_Window");
243: return java.util.ResourceBundle.getBundle(
244: "org/netbeans/swing/tabcontrol/plaf/Bundle")
245: .getString("Tip_Restore_Window");
246: }
247: }
248:
249: private static Component getActiveTab(TabDisplayer displayer) {
250: Component res = null;
251: int selIndex = displayer.getSelectionModel().getSelectedIndex();
252: if (selIndex >= 0) {
253: TabData tab = displayer.getModel().getTab(selIndex);
254: res = tab.getComponent();
255: }
256: return res;
257: }
258:
259: /**
260: * A convenience button class which will continue re-firing its action
261: * on a timer for as long as the button is depressed. Used for left-right scroll
262: * buttons.
263: */
264: private static class TimerButton extends TabControlButton implements
265: ActionListener {
266: Timer timer = null;
267:
268: public TimerButton(int buttonId, TabDisplayer displayer,
269: Action a, boolean showBorder) {
270: super (buttonId, displayer, showBorder);
271: setAction(a);
272: }
273:
274: private Timer getTimer() {
275: if (timer == null) {
276: timer = new Timer(400, this );
277: timer.setRepeats(true);
278: }
279: return timer;
280: }
281:
282: int count = 0;
283:
284: public void actionPerformed(ActionEvent e) {
285: count++;
286: if (count > 2) {
287: if (count > 5) {
288: timer.setDelay(75);
289: } else {
290: timer.setDelay(200);
291: }
292: }
293: performAction();
294: }
295:
296: private void performAction() {
297: if (!isEnabled()) {
298: stopTimer();
299: return;
300: }
301: getAction().actionPerformed(
302: new ActionEvent(this , ActionEvent.ACTION_PERFORMED,
303: getActionCommand()));
304: }
305:
306: private void startTimer() {
307: Timer t = getTimer();
308: if (t.isRunning()) {
309: return;
310: }
311: repaint();
312: t.setDelay(400);
313: t.start();
314: }
315:
316: private void stopTimer() {
317: if (timer != null) {
318: timer.stop();
319: }
320: repaint();
321: count = 0;
322: }
323:
324: protected void processMouseEvent(MouseEvent me) {
325: if (isEnabled() && me.getID() == me.MOUSE_PRESSED) {
326: startTimer();
327: } else if (me.getID() == me.MOUSE_RELEASED) {
328: stopTimer();
329: }
330: super .processMouseEvent(me);
331: }
332:
333: protected void processFocusEvent(FocusEvent fe) {
334: super .processFocusEvent(fe);
335: if (fe.getID() == fe.FOCUS_LOST) {
336: stopTimer();
337: }
338: }
339:
340: protected String getTabActionCommand(ActionEvent e) {
341: return null;
342: }
343: }
344:
345: /**
346: * A button for editor tab control to show a list of opened documents.
347: */
348: private static class DropDownButton extends TabControlButton {
349:
350: private boolean forcePressedIcon = false;
351:
352: public DropDownButton(TabDisplayer displayer, boolean showBorder) {
353: super (TabControlButton.ID_DROP_DOWN_BUTTON, displayer,
354: showBorder);
355: setAction(new TabListPopupAction(displayer));
356: setToolTipText(java.util.ResourceBundle.getBundle(
357: "org/netbeans/swing/tabcontrol/plaf/Bundle")
358: .getString("Tip_Show_Opened_Documents_List"));
359: }
360:
361: protected void processMouseEvent(MouseEvent me) {
362: super .processMouseEvent(me);
363: if (isEnabled() && me.getID() == me.MOUSE_PRESSED) {
364: forcePressedIcon = true;
365: repaint();
366: getAction()
367: .actionPerformed(
368: new ActionEvent(this ,
369: ActionEvent.ACTION_PERFORMED,
370: "pressed"));
371: } else if (isEnabled() && me.getID() == me.MOUSE_RELEASED) {
372: forcePressedIcon = false;
373: repaint();
374: }
375: }
376:
377: protected String getTabActionCommand(ActionEvent e) {
378: return null;
379: }
380:
381: void performAction(ActionEvent e) {
382: }
383:
384: public Icon getRolloverIcon() {
385: if (forcePressedIcon)
386: return getPressedIcon();
387:
388: return super .getRolloverIcon();
389: }
390:
391: public Icon getIcon() {
392: if (forcePressedIcon)
393: return getPressedIcon();
394:
395: return super .getIcon();
396: }
397: }
398:
399: /**
400: * Loader for icons. Caches loaded icons using hash map.
401: */
402: final private static class IconLoader {
403: /* mapping <String, Icon> from resource paths to icon objects, used as cache */
404: private Map<String, Icon> paths2Icons;
405:
406: /**
407: * Finds and returns icon instance from cache, if present. Otherwise
408: * loads icon using given resource path and stores icon into cache for
409: * next access.
410: *
411: * @return icon image
412: */
413: public Icon obtainIcon(String iconPath) {
414: if (paths2Icons == null) {
415: paths2Icons = new HashMap<String, Icon>(6);
416: }
417: Icon icon = paths2Icons.get(iconPath);
418: if (icon == null) {
419: // not yet in cache, load and store
420: Image image = loadImage(iconPath);
421: if (image == null) {
422: throw new IllegalArgumentException(
423: "Icon with resource path: "
424: + iconPath
425: + " can't be loaded, probably wrong path.");
426: }
427: icon = new ImageIcon(image);
428: paths2Icons.put(iconPath, icon);
429: }
430: return icon;
431: }
432:
433: } // end of IconLoader
434:
435: private static Image loadImage(String path) {
436: try {
437: URL url = TabControlButtonFactory.class.getResource("/"
438: + path);
439: return ImageIO.read(url);
440: } catch (Exception e) {
441: Logger.getLogger(TabControlButtonFactory.class.getName())
442: .log(Level.WARNING, "Cannot load image", e);
443: return null;
444: }
445: }
446: }
|