KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > core > output2 > ui > AbstractOutputWindow


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  * AbstractOutputWindow.java
21  *
22  * Created on May 14, 2004, 10:22 PM
23  */

24
25 package org.netbeans.core.output2.ui;
26
27 import javax.swing.border.Border JavaDoc;
28 import org.netbeans.core.output2.Controller;
29 import org.openide.util.Utilities;
30 import org.openide.windows.TopComponent;
31 import org.openide.awt.TabbedPaneFactory;
32
33 import javax.swing.*;
34 import javax.swing.event.ChangeEvent JavaDoc;
35 import javax.swing.event.ChangeListener JavaDoc;
36 import java.awt.*;
37 import java.util.ArrayList JavaDoc;
38 import java.beans.PropertyChangeListener JavaDoc;
39 import java.beans.PropertyChangeEvent JavaDoc;
40 import java.lang.reflect.Method JavaDoc;
41 import javax.swing.plaf.TabbedPaneUI JavaDoc;
42
43 /**
44  * A panel which, if more than one AbstractOutputTab is added to it, instead
45  * adds additional views to an internal tabbed pane.
46  *
47  * @author Tim Boudreau
48  */

49 public abstract class AbstractOutputWindow extends TopComponent implements ChangeListener JavaDoc, PropertyChangeListener JavaDoc {
50     protected JTabbedPane pane = TabbedPaneFactory.createCloseButtonTabbedPane();
51     private static final String JavaDoc ICON_PROP = "tabIcon"; //NOI18N
52
private JToolBar toolbar = null;
53     
54     /** Creates a new instance of AbstractOutputWindow */
55     public AbstractOutputWindow() {
56         pane.addChangeListener(this);
57         pane.addPropertyChangeListener(TabbedPaneFactory.PROP_CLOSE, this);
58         setFocusable(true);
59         setBackground(UIManager.getColor("text")); //NOI18N
60
toolbar = new JToolBar();
61         toolbar.setOrientation(JToolBar.VERTICAL);
62         toolbar.setLayout(new BoxLayout(toolbar, BoxLayout.Y_AXIS));
63         toolbar.setFloatable(false);
64         Insets ins = toolbar.getMargin();
65         JButton sample = new JButton();
66         sample.setBorderPainted(false);
67         sample.setOpaque(false);
68         sample.setText(null);
69         sample.setIcon(new Icon() {
70             public int getIconHeight() {
71                 return 16;
72             }
73             public int getIconWidth() {
74                 return 16;
75             }
76             public void paintIcon(Component c, Graphics g, int x, int y) {
77             }
78         });
79         toolbar.add(sample);
80         Dimension buttonPref = sample.getPreferredSize();
81         Dimension minDim = new Dimension(buttonPref.width + ins.left + ins.right, buttonPref.height + ins.top + ins.bottom);
82         toolbar.setMinimumSize(minDim);
83         toolbar.setPreferredSize(minDim);
84         toolbar.remove(sample);
85         setLayout(new BorderLayout());
86         add(toolbar, BorderLayout.WEST);
87         toolbar.setBorder(new VariableRightBorder(pane));
88         toolbar.setBorderPainted(true);
89     }
90     
91     public void propertyChange(PropertyChangeEvent JavaDoc pce) {
92         if (TabbedPaneFactory.PROP_CLOSE.equals(pce.getPropertyName())) {
93             AbstractOutputTab tab = (AbstractOutputTab) pce.getNewValue();
94             closeRequest(tab);
95         }
96     }
97     
98     protected abstract void closeRequest(AbstractOutputTab tab);
99     
100     protected abstract void removed(AbstractOutputTab view);
101     
102     protected void addImpl(Component c, Object JavaDoc constraints, int idx) {
103         setFocusable(false);
104         Component focusOwner =
105                 KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
106         boolean hadFocus = hasFocus() || isAncestorOf(focusOwner);
107         
108         synchronized (getTreeLock()) {
109             if (c instanceof AbstractOutputTab) {
110                 AbstractOutputTab aop = getInternalTab();
111                 if (aop != null) {
112                     if (aop == c) {
113                         return;
114                     }
115                     super.remove(aop);
116                     assert pane.getParent() != this;
117                     pane.add(aop);
118                     setTabIcon(aop, (Icon)aop.getClientProperty(ICON_PROP));
119                     pane.add(c);
120                     setTabIcon((AbstractOutputTab)c, (Icon)((AbstractOutputTab)c).getClientProperty(ICON_PROP));
121                     
122                     super.addImpl(pane, constraints, idx);
123                     updateSingletonName(null);
124                     revalidate();
125                 } else if (pane.getParent() == this) {
126                     pane.add(c);
127                     setTabIcon((AbstractOutputTab) c, (Icon)((AbstractOutputTab)c).getClientProperty(ICON_PROP));
128                     revalidate();
129                 } else {
130                     super.addImpl(c, constraints, idx);
131                     setTabIcon((AbstractOutputTab) c, (Icon)((AbstractOutputTab)c).getClientProperty(ICON_PROP));
132                     setToolbarButtons(((AbstractOutputTab)c).getToolbarButtons());
133                     //#48819 - a bit obscure usecase, but revalidate() is call in the if branches above as well..
134
revalidate();
135                 }
136                 if (hadFocus) {
137                     //Do not call c.requestFocus() directly, it can be
138
//discarded when adding tabs and focus will go to null.
139
//@see AbstractOutputWindow.requestFocus()
140
requestFocus();
141                 }
142                 
143                 return;
144             }
145             super.addImpl(c, constraints, idx);
146         }
147         if (getComponentCount() == 2 && getComponent(1) instanceof AbstractOutputTab) {
148             updateSingletonName(getComponent(1).getName());
149         }
150         revalidate();
151     }
152     
153     public final AbstractOutputTab[] getTabs() {
154         ArrayList JavaDoc al = new ArrayList JavaDoc(pane.getParent() == this ? pane.getTabCount() : getComponentCount());
155         if (pane.getParent() == this) {
156             int tabs = pane.getTabCount();
157             for (int i=0; i < tabs; i++) {
158                 Component c = pane.getComponentAt(i);
159                 if (c instanceof AbstractOutputTab) {
160                     al.add(c);
161                 }
162             }
163         } else {
164             Component[] c = getComponents();
165             for (int i=0; i < c.length; i++) {
166                 if (c[i] instanceof AbstractOutputTab) {
167                     al.add(c[i]);
168                 }
169             }
170         }
171         AbstractOutputTab[] result = new AbstractOutputTab[al.size()];
172         return (AbstractOutputTab[]) al.toArray(result);
173     }
174     
175     
176     public void remove(Component c) {
177         AbstractOutputTab removedSelectedView = null;
178         synchronized (getTreeLock()) {
179             if (c.getParent() == pane && c instanceof AbstractOutputTab) {
180                 if (c == pane.getSelectedComponent()) {
181                     if (Controller.LOG) Controller.log("Selected view is being removed: " + c.getName());
182                     removedSelectedView = (AbstractOutputTab) c;
183                 }
184                 checkWinXPLFBug();
185                 pane.remove(c);
186                 if (pane.getTabCount() == 1) {
187                     Component comp = pane.getComponentAt(0);
188                     pane.remove(comp);
189                     super.remove(pane);
190                     add(comp);
191                     updateSingletonName(c.getName());
192                     setToolbarButtons(((AbstractOutputTab)comp).getToolbarButtons());
193                     revalidate();
194                 }
195             } else {
196                 if (c == getSelectedTab()) {
197                     removedSelectedView = (AbstractOutputTab) c;
198                 }
199                 super.remove(c);
200                 setToolbarButtons(new JButton[0]);
201                 updateSingletonName(null);
202             }
203             if (removedSelectedView != null) {
204                 fire(removedSelectedView);
205             }
206         }
207         if (c instanceof AbstractOutputTab && c.getParent() == null) {
208             removed((AbstractOutputTab) c);
209         }
210         if (getComponentCount() == 2 && getComponent(1) instanceof AbstractOutputTab) {
211             updateSingletonName(getComponent(1).getName());
212         }
213         revalidate();
214         setFocusable(getComponentCount() == 1);
215     }
216     
217     private AbstractOutputTab getInternalTab() {
218         Component[] c = getComponents();
219         for (int i=0; i < c.length; i++) {
220             if (c[i] instanceof AbstractOutputTab) {
221                 return (AbstractOutputTab) c[i];
222             }
223         }
224         return null;
225     }
226     
227     public final AbstractOutputTab getSelectedTab() {
228         if (pane.getParent() == this) {
229             return (AbstractOutputTab) pane.getSelectedComponent();
230         } else {
231             return getInternalTab();
232         }
233     }
234     
235     public void setSelectedTab(AbstractOutputTab op) {
236         assert (op.getParent() == this || op.getParent() == pane);
237         if (Controller.LOG) {
238             Controller.log("SetSelectedTab: " + op + " parent is " + op.getParent());
239         }
240         if (pane.getParent() == this && op != pane.getSelectedComponent()) {
241             pane.setSelectedComponent(op);
242         }
243         
244         getActionMap().setParent(op.getActionMap());
245     }
246     
247     public void setTabTitle(AbstractOutputTab tab, String JavaDoc name) {
248         if (tab.getParent() == pane) {
249             pane.setTitleAt(pane.indexOfComponent(tab), name);
250         } else if (tab.getParent() == this) {
251             updateSingletonName(name);
252         }
253         tab.setName(name);
254     }
255     
256     public void setTabIcon(AbstractOutputTab tab, Icon icon) {
257         if (icon != null) {
258             tab.putClientProperty(ICON_PROP, icon);
259             if (pane.indexOfComponent(tab) != -1) {
260                 pane.setIconAt(pane.indexOfComponent(tab), icon);
261                 pane.setDisabledIconAt(pane.indexOfComponent(tab), icon);
262             }
263         }
264     }
265     
266     public void requestFocus() {
267         if (!isShowing()) {
268             return;
269         }
270         AbstractOutputTab tab = getSelectedTab();
271         if (tab != null && pendingFocusRunnable == null) {
272             //Adding the tab may yet need to be processed, so escape the
273
//current event loop via invokeLater()
274
pendingFocusRunnable = new Runnable JavaDoc() {
275                 public void run() {
276                     AbstractOutputTab tab = getSelectedTab();
277                     if (tab != null) {
278                         tab.requestFocus();
279                     }
280                     pendingFocusRunnable = null;
281                 }
282             };
283             SwingUtilities.invokeLater(pendingFocusRunnable);
284         } else {
285             super.requestFocus();
286         }
287     }
288     
289     private Runnable JavaDoc pendingFocusRunnable = null;
290     
291     /**
292      * Updates the component name to include the name of a tab. If passed null
293      * arguments, should update the name to the default which does not include the
294      * tab name.
295      *
296      * @param name A name for the tab
297      */

298     protected abstract void updateSingletonName(String JavaDoc name);
299     
300     
301     private AbstractOutputTab lastKnownSelection = null;
302     protected void fire(AbstractOutputTab formerSelection) {
303         AbstractOutputTab selection = getSelectedTab();
304         if (formerSelection != selection) {
305             selectionChanged(formerSelection, selection);
306             lastKnownSelection = selection;
307             if (selection != null) {
308                 setToolbarButtons(selection.getToolbarButtons());
309             } else {
310                 setToolbarButtons(new JButton[0]);
311             }
312         }
313     }
314     
315     private void setToolbarButtons(JButton[] buttons) {
316         toolbar.removeAll();
317         for (int i = 0; i < buttons.length; i++) {
318             toolbar.add(buttons[i]);
319         }
320         toolbar.revalidate();
321         toolbar.repaint();
322         
323     }
324     
325     public void stateChanged(ChangeEvent JavaDoc e) {
326         if (pane.getSelectedComponent() instanceof AbstractOutputPane) {
327             ((AbstractOutputPane) pane.getSelectedComponent()).ensureCaretPosition();
328         }
329         fire(lastKnownSelection);
330     }
331     
332     protected abstract void selectionChanged(AbstractOutputTab former, AbstractOutputTab current);
333     
334     private final boolean isGtk = "GTK".equals(UIManager.getLookAndFeel().getID()) || //NOI18N
335
UIManager.getLookAndFeel().getClass().getSuperclass().getName().indexOf("Synth") != -1; //NOI18N
336
/**
337      * Overridden to fill in the background color, since Synth/GTKLookAndFeel ignores
338      * setOpaque(true).
339      * @see http://www.netbeans.org/issues/show_bug.cgi?id=43024
340      */

341     public void paint(Graphics g) {
342         if (isGtk) {
343             //Presumably we can get this fixed for JDK 1.5.1
344
Color c = getBackground();
345             if (c == null) c = Color.WHITE;
346             g.setColor(c);
347             g.fillRect(0, 0, getWidth(), getHeight());
348         }
349         super.paint(g);
350     }
351     
352     /**
353      * Set next tab relatively to the given tab. If the give tab is the last one
354      * the first is selected.
355      *
356      * @param tab relative tab
357      */

358     public final void selectNextTab(AbstractOutputTab tab) {
359         AbstractOutputTab[] tabs = this.getTabs();
360         if (tabs.length > 1) {
361             int nextTabIndex = getSelectedTabIndex(tabs, tab) + 1;
362             if (nextTabIndex > (tabs.length - 1)) {
363                 nextTabIndex = 0;
364             }
365             this.setSelectedTab(tabs[nextTabIndex]);
366         }
367     }
368     
369     /**
370      * Set previous tab relatively to the given tab. If the give tab is the
371      * first one the last is selected.
372      *
373      * @param tab relative tab
374      */

375     public final void selectPreviousTab(AbstractOutputTab tab) {
376         AbstractOutputTab[] tabs = this.getTabs();
377         if (tabs.length > 1) {
378             int prevTabIndex = getSelectedTabIndex(tabs, tab) - 1;
379             if (prevTabIndex < 0) {
380                 prevTabIndex = tabs.length - 1;
381             }
382             this.setSelectedTab(tabs[prevTabIndex]);
383         }
384     }
385     
386     private int getSelectedTabIndex(AbstractOutputTab[] tabs, AbstractOutputTab tab) {
387         for (int i = 0; i < tabs.length; i++) {
388             if (tabs[i] == tab) {
389                 return i;
390             }
391         }
392         return -1;
393     }
394     
395     // JDK 1.5, Win L&F - removing a tab causes a relayout and that uses onl data in UI class,
396
// causing it to throw ArrayOutofbounds if removing the last one.
397
// hacking around it by resetting the bad old data before removal.
398
// #56628
399
private void checkWinXPLFBug() {
400         if ("Windows".equals(UIManager.getLookAndFeel().getID())) { //NOi18N
401
TabbedPaneUI JavaDoc ui = pane.getUI();
402             try {
403                 Method JavaDoc method = ui.getClass().getDeclaredMethod("setRolloverTab", new Class JavaDoc[] {Integer.TYPE}); //NOI18N
404
if (method != null) {
405                     method.setAccessible(true);
406                     method.invoke(ui, new Object JavaDoc[] { new Integer JavaDoc(-1) });
407                     method.setAccessible(false);
408                 }
409             } catch (Exception JavaDoc exc) {
410                 // well let's cross fingers and see..
411
}
412         }
413     }
414     
415     private class VariableRightBorder implements Border JavaDoc {
416         
417         private JTabbedPane pane;
418         
419         public VariableRightBorder(JTabbedPane pane) {
420             this.pane = pane;
421         }
422         
423         public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
424             if (pane.getParent() != AbstractOutputWindow.this) {
425                 Color old = g.getColor();
426                 g.setColor(getColor());
427                 g.drawLine(x + width - 1, y, x + width - 1, y + height);
428                 g.setColor(old);
429             }
430         }
431         
432         public Color getColor() {
433             if (Utilities.isMac()) {
434                 Color c1 = UIManager.getColor("controlShadow");
435                 Color c2 = UIManager.getColor("control");
436                 return new Color((c1.getRed() + c2.getRed()) / 2,
437                         (c1.getGreen() + c2.getGreen()) / 2,
438                         (c1.getBlue() + c2.getBlue()) / 2);
439             } else {
440                 return UIManager.getColor("controlShadow");
441             }
442         }
443         
444         public Insets getBorderInsets(Component c) {
445             if (pane.getParent() == AbstractOutputWindow.this) {
446                 return new Insets(0,0,0,0);
447             }
448             return new Insets(0, 0, 0, 2);
449         }
450         
451         public boolean isBorderOpaque() {
452             return true;
453         }
454         
455     }
456     
457 }
458
Popular Tags