KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > swing > tabcontrol > plaf > AbstractViewTabDisplayerUI


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.swing.tabcontrol.plaf;
21
22 import java.awt.Component JavaDoc;
23 import java.awt.Dimension JavaDoc;
24 import java.awt.Font JavaDoc;
25 import java.awt.FontMetrics JavaDoc;
26 import java.awt.Graphics JavaDoc;
27 import java.awt.Graphics2D JavaDoc;
28 import java.awt.GraphicsConfiguration JavaDoc;
29 import java.awt.GraphicsEnvironment JavaDoc;
30 import java.awt.Image JavaDoc;
31 import java.awt.KeyboardFocusManager JavaDoc;
32 import java.awt.Point JavaDoc;
33 import java.awt.Polygon JavaDoc;
34 import java.awt.Rectangle JavaDoc;
35 import javax.swing.AbstractAction JavaDoc;
36 import javax.swing.Action JavaDoc;
37 import javax.swing.JPanel JavaDoc;
38 import javax.swing.event.ListDataEvent JavaDoc;
39 import org.netbeans.swing.tabcontrol.TabData;
40 import org.netbeans.swing.tabcontrol.TabDataModel;
41 import org.netbeans.swing.tabcontrol.TabDisplayer;
42 import org.netbeans.swing.tabcontrol.TabDisplayerUI;
43
44 import javax.swing.event.ChangeEvent JavaDoc;
45 import javax.swing.event.ChangeListener JavaDoc;
46 import java.awt.event.ActionEvent JavaDoc;
47 import java.awt.event.InputEvent JavaDoc;
48 import java.awt.event.KeyEvent JavaDoc;
49 import java.awt.event.MouseAdapter JavaDoc;
50 import java.awt.event.MouseEvent JavaDoc;
51 import java.awt.event.MouseMotionListener JavaDoc;
52 import java.awt.image.BufferedImage JavaDoc;
53 import java.beans.PropertyChangeEvent JavaDoc;
54 import java.beans.PropertyChangeListener JavaDoc;
55 import javax.swing.Icon JavaDoc;
56 import javax.swing.JComponent JavaDoc;
57 import javax.swing.JLabel JavaDoc;
58 import javax.swing.KeyStroke JavaDoc;
59 import javax.swing.SingleSelectionModel JavaDoc;
60 import javax.swing.SwingUtilities JavaDoc;
61 import javax.swing.ToolTipManager JavaDoc;
62 import javax.swing.UIManager JavaDoc;
63 import org.netbeans.swing.tabcontrol.event.ComplexListDataEvent;
64 import org.netbeans.swing.tabcontrol.event.ComplexListDataListener;
65 import org.openide.windows.TopComponent;
66
67 /**
68  * Basic UI class for view tabs - non scrollable tabbed displayer, which shows all
69  * tabs equally sized, proportionally. This class is independent on specific
70  * L&F, acts as base class for specific L&F descendants.
71  * <p>
72  * XXX eventually this class should be deleted and a subclass of BasicTabDisplayer can be used;
73  * currently this is simply a port of the original code to the new API. Do not introduce any new
74  * subclasses of this.
75  *
76  * @author Dafe Simonek
77  *
78  */

79 public abstract class AbstractViewTabDisplayerUI extends TabDisplayerUI {
80
81     private TabDataModel dataModel;
82
83     private ViewTabLayoutModel layoutModel;
84
85     private FontMetrics JavaDoc fm;
86
87     private Font JavaDoc txtFont;
88     
89     private Component JavaDoc controlButtons;
90
91     protected Controller controller;
92     
93     private TabControlButton btnClose;
94     private TabControlButton btnAutoHidePin;
95     private TabControlButton btnMaximizeRestore;
96     
97     /** Pin action */
98     private final Action JavaDoc pinAction = new PinAction();
99     private static final String JavaDoc PIN_ACTION = "pinAction";
100     
101     public AbstractViewTabDisplayerUI (TabDisplayer displayer) {
102         super (displayer);
103         displayer.setLayout(null);
104     }
105
106     public void installUI(JComponent JavaDoc c) {
107         super.installUI(c);
108         ToolTipManager.sharedInstance().registerComponent(displayer);
109         controller = createController();
110         dataModel = displayer.getModel();
111         layoutModel = new ViewTabLayoutModel(dataModel, displayer);
112         dataModel.addChangeListener (controller);
113         dataModel.addComplexListDataListener(controller);
114         displayer.addPropertyChangeListener (controller);
115         selectionModel.addChangeListener (controller);
116         displayer.addMouseListener(controller);
117         displayer.addMouseMotionListener(controller);
118         installControlButtons();
119     }
120     
121     protected void installControlButtons() {
122         if( null != getControlButtons() )
123             displayer.add( getControlButtons() );
124     }
125     
126     private static final int ICON_X_PAD = 1;
127     
128     /**
129      * @return A component that holds all control buttons (maximize/restor,
130      * slide/pin, close) that are displayed in the active tab or null if
131      * control buttons are not supported.
132      */

133     protected Component JavaDoc getControlButtons() {
134         if( null == controlButtons ) {
135             JPanel JavaDoc buttonsPanel = new JPanel JavaDoc( null );
136             buttonsPanel.setOpaque( false );
137
138             int width = 0;
139             int height = 0;
140             //create maximize/restore button
141
// if( null != displayer.getWinsysInfo() ) {
142
// btnMaximizeRestore = TabControlButtonFactory.createMaximizeRestoreButton( displayer );
143
// buttonsPanel.add( btnMaximizeRestore );
144
// Icon icon = btnMaximizeRestore.getIcon();
145
// btnMaximizeRestore.setBounds( 0, 0, icon.getIconWidth(), icon.getIconHeight() );
146
// width += icon.getIconWidth();
147
// }
148

149             //create autohide/pin button
150
if( null != displayer.getWinsysInfo() ) {
151                 btnAutoHidePin = TabControlButtonFactory.createSlidePinButton( displayer );
152                 buttonsPanel.add( btnAutoHidePin );
153                 
154                 Icon JavaDoc icon = btnAutoHidePin.getIcon();
155                 if( 0 != width )
156                     width += ICON_X_PAD;
157                 btnAutoHidePin.setBounds( width, 0, icon.getIconWidth(), icon.getIconHeight() );
158                 width += icon.getIconWidth();
159             }
160
161             //create close button
162
btnClose = TabControlButtonFactory.createCloseButton( displayer );
163             buttonsPanel.add( btnClose );
164
165             Icon JavaDoc icon = btnClose.getIcon();
166             if( 0 != width )
167                 width += ICON_X_PAD;
168             btnClose.setBounds( width, 0, icon.getIconWidth(), icon.getIconHeight() );
169             width += icon.getIconWidth();
170             height = icon.getIconHeight();
171             
172             Dimension JavaDoc size = new Dimension JavaDoc( width, height );
173             buttonsPanel.setMinimumSize( size );
174             buttonsPanel.setSize( size );
175             buttonsPanel.setPreferredSize( size );
176             buttonsPanel.setMaximumSize( size );
177             
178             controlButtons = buttonsPanel;
179         }
180         return controlButtons;
181     }
182
183     public void uninstallUI(JComponent JavaDoc c) {
184         super.uninstallUI(c);
185         ToolTipManager.sharedInstance().unregisterComponent(displayer);
186         displayer.removePropertyChangeListener (controller);
187         dataModel.removeChangeListener(controller);
188         dataModel.removeComplexListDataListener(controller);
189         selectionModel.removeChangeListener(controller);
190         displayer.removeMouseListener(controller);
191         displayer.removeMouseMotionListener(controller);
192         if (controlButtons != null) {
193             displayer.remove(controlButtons);
194             controlButtons = null;
195         }
196         layoutModel = null;
197         selectionModel = null;
198         dataModel = null;
199         controller = null;
200     }
201
202     protected Controller createController() {
203         return new Controller();
204     }
205
206     public void paint(Graphics JavaDoc g, JComponent JavaDoc c) {
207
208         ColorUtil.setupAntialiasing(g);
209
210         TabData tabData;
211         int x, y, width, height;
212         String JavaDoc text;
213
214         for (int i = 0; i < dataModel.size(); i++) {
215             // gather data
216
tabData = dataModel.getTab(i);
217             x = layoutModel.getX(i);
218             y = layoutModel.getY(i);
219             width = layoutModel.getW(i);
220             height = layoutModel.getH(i);
221             text = tabData.getText();
222             // perform paint
223
if (g.hitClip(x, y, width, height)) {
224                 paintTabBackground(g, i, x, y, width, height);
225                 paintTabContent(g, i, text, x, y, width, height);
226                 paintTabBorder(g, i, x, y, width, height);
227             }
228         }
229     }
230
231     protected final TabDataModel getDataModel() {
232         return dataModel;
233     }
234
235     public final TabLayoutModel getLayoutModel() {
236         return layoutModel;
237     }
238
239     protected final TabDisplayer getDisplayer() {
240         return displayer;
241     }
242
243     protected final SingleSelectionModel JavaDoc getSelectionModel() {
244         return selectionModel;
245     }
246
247     public Controller getController() {
248         return controller;
249     }
250
251     protected final boolean isSelected(int index) {
252         return selectionModel.getSelectedIndex() == index;
253     }
254
255     protected final boolean isActive() {
256         return displayer.isActive();
257     }
258
259     protected final boolean isFocused(int index) {
260         return isSelected(index) && isActive();
261     }
262
263     protected final SingleSelectionModel JavaDoc createSelectionModel() {
264         return new DefaultTabSelectionModel (displayer.getModel());
265     }
266
267     public int dropIndexOfPoint(Point JavaDoc p) {
268         int result = 0;
269         for (int i=0; i < displayer.getModel().size(); i++) {
270             int x = getLayoutModel().getX(i);
271             int w = getLayoutModel().getW(i);
272             if (p.x >= x && p.x <= x + w) {
273                 if (i == displayer.getModel().size() - 1) {
274                     if (p.x > x + (w / 2)) {
275                         result = displayer.getModel().size();
276                         break;
277                     } else {
278                         result = i;
279                         break;
280                     }
281                 } else {
282                     result = i;
283                     break;
284                 }
285             }
286         }
287         return result;
288     }
289
290     /**
291      * Specifies font to use for text and font metrics. Subclasses may override
292      * to specify their own text font
293      */

294     protected Font JavaDoc getTxtFont() {
295         if (txtFont == null) {
296             txtFont = (Font JavaDoc) UIManager.get("windowTitleFont");
297             if (txtFont == null) {
298                 txtFont = new Font JavaDoc("Dialog", Font.PLAIN, 11);
299             } else if (txtFont.isBold()) {
300                 // don't use deriveFont() - see #49973 for details
301
txtFont = new Font JavaDoc(txtFont.getName(), Font.PLAIN, txtFont.getSize());
302             }
303         }
304         return txtFont;
305     }
306
307     protected final FontMetrics JavaDoc getTxtFontMetrics() {
308         if (fm == null) {
309             JComponent JavaDoc control = getDisplayer();
310             fm = control.getFontMetrics(getTxtFont());
311         }
312         return fm;
313     }
314
315     protected abstract void paintTabContent(Graphics JavaDoc g, int index, String JavaDoc text,
316                                             int x, int y, int width,
317                                             int height);
318
319     protected abstract void paintTabBorder(Graphics JavaDoc g, int index, int x, int y,
320                                            int width, int height);
321
322     protected abstract void paintTabBackground(Graphics JavaDoc g, int index, int x,
323                                                int y, int width, int height);
324
325
326
327     /** Registers shortcut for enable/ disable auto-hide functionality */
328     public void unregisterShortcuts(JComponent JavaDoc comp) {
329         comp.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).
330             remove(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE,
331                                 InputEvent.CTRL_DOWN_MASK));
332         comp.getActionMap().remove(PIN_ACTION);
333     }
334
335     /** Registers shortcut for enable/ disable auto-hide functionality */
336     public void registerShortcuts(JComponent JavaDoc comp) {
337         comp.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).
338             put(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE,
339                                 InputEvent.CTRL_DOWN_MASK), PIN_ACTION);
340         comp.getActionMap().put(PIN_ACTION, pinAction);
341     }
342     
343     public Polygon JavaDoc getExactTabIndication(int index) {
344         // TBD - the same code is copied in ScrollableTabsUI, should be shared
345
// if will not differ
346
// GeneralPath indication = new GeneralPath();
347
JComponent JavaDoc control = getDisplayer();
348         int height = control.getHeight();
349
350         TabLayoutModel tlm = getLayoutModel();
351
352         int tabXStart = tlm.getX(index);
353
354         int tabXEnd = tabXStart + tlm.getW(index);
355
356         int[] xpoints = new int[4];
357         int[] ypoints = new int[4];
358         xpoints[0] = tabXStart;
359         ypoints[0] = 0;
360         xpoints[1] = tabXEnd;
361         ypoints[1] = 0;
362         xpoints[2] = tabXEnd;
363         ypoints[2] = height - 1;
364         xpoints[3] = tabXStart;
365         ypoints[3] = height - 1;
366
367         return new EqualPolygon(xpoints, ypoints);
368     }
369
370     public Polygon JavaDoc getInsertTabIndication(int index) {
371         EqualPolygon indication = new EqualPolygon();
372         JComponent JavaDoc control = getDisplayer();
373         int height = control.getHeight();
374         int width = control.getWidth();
375         TabLayoutModel tlm = getLayoutModel();
376
377         int tabXStart;
378         int tabXEnd;
379         if (index == 0) {
380             tabXStart = 0;
381             tabXEnd = tlm.getW(0) / 2;
382         } else if (index >= getDataModel().size()) {
383             tabXStart = tlm.getX(index - 1) + tlm.getW(index - 1) / 2;
384             tabXEnd = tabXStart + tlm.getW(index - 1);
385             if (tabXEnd > width) {
386                 tabXEnd = width;
387             }
388         } else {
389             tabXStart = tlm.getX(index - 1) + tlm.getW(index - 1) / 2;
390             tabXEnd = tlm.getX(index) + tlm.getW(index) / 2;
391         }
392
393         indication.moveTo(tabXStart, 0);
394         indication.lineTo(tabXEnd, 0);
395         indication.lineTo(tabXEnd, height - 1);
396         indication.lineTo(tabXStart, height - 1);
397         return indication;
398     }
399
400     /** Paints the rectangle occupied by a tab into an image and returns the result */
401     public Image JavaDoc createImageOfTab(int index) {
402         TabData td = displayer.getModel().getTab(index);
403         
404         JLabel JavaDoc lbl = new JLabel JavaDoc(td.getText());
405         int width = lbl.getFontMetrics(lbl.getFont()).stringWidth(td.getText());
406         int height = lbl.getFontMetrics(lbl.getFont()).getHeight();
407         width = width + td.getIcon().getIconWidth() + 6;
408         height = Math.max(height, td.getIcon().getIconHeight()) + 5;
409         
410         GraphicsConfiguration JavaDoc config = GraphicsEnvironment.getLocalGraphicsEnvironment()
411                                         .getDefaultScreenDevice().getDefaultConfiguration();
412         
413         BufferedImage JavaDoc image = config.createCompatibleImage(width, height);
414         Graphics2D JavaDoc g = image.createGraphics();
415         g.setColor(lbl.getForeground());
416         g.setFont(lbl.getFont());
417         td.getIcon().paintIcon(lbl, g, 0, 0);
418         g.drawString(td.getText(), 18, height / 2);
419         
420         
421         return image;
422     }
423
424     public Rectangle JavaDoc getTabRect(int index, Rectangle JavaDoc destination) {
425         if (destination == null) {
426             destination = new Rectangle JavaDoc();
427         }
428         if (index < 0 || index > displayer.getModel().size()) {
429             destination.setBounds (0,0,0,0);
430             return destination;
431         }
432         destination.x = layoutModel.getX(index);
433         destination.width = layoutModel.getW(index);
434         destination.height = layoutModel.getH(index);
435         destination.y = Math.min (0, displayer.getHeight() - destination.height);
436         return destination;
437     }
438     
439     public int tabForCoordinate(Point JavaDoc p) {
440         int max = displayer.getModel().size();
441         if (max == 0 || p.y > displayer.getHeight() || p.y < 0 || p.x < 0 ||
442             p.x > displayer.getWidth()) {
443                 
444             return -1;
445         }
446         
447         for (int i=0; i < max; i++) {
448             int left = layoutModel.getX(i);
449             int right = left + layoutModel.getW(i);
450             if (p.x > left && p.x < right) {
451                 return i;
452             }
453         }
454         
455         return -1;
456     }
457     
458     protected int createRepaintPolicy () {
459         return TabState.REPAINT_SELECTION_ON_ACTIVATION_CHANGE
460                 | TabState.REPAINT_ON_SELECTION_CHANGE
461                 | TabState.REPAINT_ON_MOUSE_ENTER_TAB
462                 | TabState.REPAINT_ON_MOUSE_ENTER_CLOSE_BUTTON
463                 | TabState.REPAINT_ON_MOUSE_PRESSED;
464     }
465     
466     protected final TabState tabState = new ViewTabState();
467     
468     private class ViewTabState extends TabState {
469     public ViewTabState () {}
470     
471         public int getRepaintPolicy(int tab) {
472             return createRepaintPolicy();
473         }
474         
475         public void repaintAllTabs() {
476             displayer.repaint();
477         }
478         
479         public void repaintTab (int tab) {
480             if (tab < 0 || tab >= displayer.getModel().size()) {
481                 //This can happen because we can be notified
482
//of a change on a tab that has just been removed
483
//from the model
484
return;
485             }
486             Rectangle JavaDoc r = getTabRect(tab, null);
487             displayer.repaint(r);
488         }
489     }
490     
491     /**
492      * Determine if the tab should be flashing
493      */

494     protected boolean isAttention (int tab) {
495         return (tabState.getState(tab) & TabState.ATTENTION) != 0;
496     }
497     
498
499     protected void requestAttention (int tab) {
500         tabState.addAlarmTab(tab);
501     }
502     
503     protected void cancelRequestAttention (int tab) {
504         tabState.removeAlarmTab(tab);
505     }
506
507     /**
508      * Listen to mouse events and handles selection behaviour and close icon
509      * button behaviour.
510      */

511     class Controller extends MouseAdapter JavaDoc
512             implements MouseMotionListener JavaDoc, ChangeListener JavaDoc, PropertyChangeListener JavaDoc, ComplexListDataListener {
513
514         /**
515          * true when selection is changed as a result of mouse press
516          */

517         private boolean selectionChanged;
518
519         protected boolean shouldReact(MouseEvent JavaDoc e) {
520             boolean isLeft = SwingUtilities.isLeftMouseButton(e);
521             return isLeft;
522         }
523
524         public void stateChanged (ChangeEvent JavaDoc ce) {
525             displayer.repaint();
526         }
527
528         public void propertyChange (PropertyChangeEvent JavaDoc pce) {
529             if (TabDisplayer.PROP_ACTIVE.equals (pce.getPropertyName())) {
530                 displayer.repaint();
531             }
532         }
533         
534         /**
535          * @param p Mouse point location
536          * @return True if the point is in the control buttons panel.
537          */

538         public boolean inControlButtonsRect( Point JavaDoc p ) {
539             if( null != controlButtons ) {
540                 Point JavaDoc p2 = SwingUtilities.convertPoint(displayer, p, controlButtons);
541                 return controlButtons.contains(p2);
542             }
543             return false;
544         }
545
546         public void mousePressed(MouseEvent JavaDoc e) {
547             Point JavaDoc p = e.getPoint();
548             int i = getLayoutModel().indexOfPoint(p.x, p.y);
549             tabState.setPressed(i);
550             SingleSelectionModel JavaDoc sel = getSelectionModel();
551             selectionChanged = i != sel.getSelectedIndex();
552             // invoke possible selection change
553
if ((i != -1) || !selectionChanged) {
554                 boolean change = shouldPerformAction(TabDisplayer.COMMAND_SELECT,
555                     i, e);
556                 if (change) {
557                     getSelectionModel().setSelectedIndex(i);
558                     tabState.setSelected(i);
559                     Component JavaDoc tc = getDataModel().getTab(i).getComponent();
560                     if( null != tc && tc instanceof TopComponent
561                         && !((TopComponent)tc).isAncestorOf( KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner() ) ) {
562                         ((TopComponent)tc).requestActive();
563                     }
564                 }
565             }
566             if ((i != -1) && e.isPopupTrigger()) {
567                 //Post a popup menu show request
568
shouldPerformAction(TabDisplayer.COMMAND_POPUP_REQUEST, i, e);
569             }
570         }
571
572         public void mouseClicked (MouseEvent JavaDoc e) {
573             if (e.getClickCount() >= 2 && !e.isPopupTrigger()) {
574                 Point JavaDoc p = e.getPoint();
575                 int i = getLayoutModel().indexOfPoint(p.x, p.y);
576                 SingleSelectionModel JavaDoc sel = getSelectionModel();
577                 selectionChanged = i != sel.getSelectedIndex();
578                 // invoke possible selection change
579
if ((i != -1) || !selectionChanged) {
580                 boolean change = shouldPerformAction(TabDisplayer.COMMAND_SELECT,
581                     i, e);
582                     if (change) {
583                         getSelectionModel().setSelectedIndex(i);
584                     }
585                 }
586                 if (i != -1) {
587                     //Post a maximize request
588
shouldPerformAction(TabDisplayer.COMMAND_MAXIMIZE, i, e);
589                 }
590             }
591         }
592
593         public void mouseReleased(MouseEvent JavaDoc e) {
594             // close button must not be active when selection change was
595
// triggered by mouse press
596
tabState.setPressed(-1);
597             Point JavaDoc p = e.getPoint();
598             int i = getLayoutModel().indexOfPoint(p.x, p.y);
599             if ((i != -1) && e.isPopupTrigger()) {
600                 //Post a popup menu show request
601
shouldPerformAction(TabDisplayer.COMMAND_POPUP_REQUEST, i, e);
602             }
603         }
604
605         public void indicesAdded(ComplexListDataEvent e) {
606             tabState.indicesAdded(e);
607         }
608
609         /**
610          * Elements have been removed at the indices specified by the event's
611          * getIndices() value
612          *
613          * @param e The event
614          */

615         public void indicesRemoved(ComplexListDataEvent e) {
616             tabState.indicesRemoved(e);
617         }
618
619         /**
620          * Elements have been changed at the indices specified by the event's
621          * getIndices() value. If the changed data can affect display width (such
622          * as a text change or a change in icon size), the event's
623          * <code>isTextChanged()</code> method will return true.
624          *
625          * @param e The event
626          */

627         public void indicesChanged(ComplexListDataEvent e) {
628             tabState.indicesChanged(e);
629         }
630         
631         public void intervalAdded (ListDataEvent JavaDoc evt) {
632             tabState.intervalAdded(evt);
633         }
634         
635         public void intervalRemoved (ListDataEvent JavaDoc evt) {
636             tabState.intervalRemoved(evt);
637         }
638         
639         public void contentsChanged(ListDataEvent JavaDoc evt) {
640             tabState.contentsChanged(evt);
641         }
642
643         public void mouseDragged(MouseEvent JavaDoc e) {
644         }
645
646         public void mouseMoved(MouseEvent JavaDoc e) {
647         }
648     } // end of Controller
649

650     private class PinAction extends AbstractAction JavaDoc {
651         public void actionPerformed(ActionEvent JavaDoc e) {
652             if( null != btnAutoHidePin ) {
653                 btnAutoHidePin.performAction( null );
654             }
655         }
656     }
657 }
658
Popular Tags