001    package sale.multiwindow;
002    
003    import java.awt.Component;
004    import java.awt.Graphics;
005    import java.awt.Image;
006    import java.awt.Rectangle;
007    import java.awt.event.MouseAdapter;
008    import java.awt.event.MouseEvent;
009    
010    import javax.swing.ImageIcon;
011    import javax.swing.JTabbedPane;
012    
013    import resource.util.ResourceManager;
014    
015    /**
016     * A JTabbedPane which has a close ('X') icon on each tab.
017     *
018     * It is also possible to render the tabs unclosable, i.e. without an icon.
019     */
020    public class IconTabbedPane extends JTabbedPane {
021    
022        /**
023             * ID for Serialization.
024             */
025            private static final long serialVersionUID = 5782825255690036127L;
026    
027            /**
028         * Indicates whether the tabs can be closed or not.
029         */
030        private boolean m_fAllowClose = true;
031    
032        /**
033         * The tab whose close button has been clicked most recently.
034         */
035        private int tabNumber;
036    
037        /**
038         * The imageIcon to be used as close icon.
039         */
040        protected static ImageIcon CLOSE_ICON = new ImageIcon(ResourceManager.getInstance().getResource(
041                ResourceManager.RESOURCE_GIF, "icon.icon_closetab_16x16"));
042    
043    
044        /**
045         * Creates an IconTabbedPane. A MouseListener is added tat listens to clicks on the close button if set.
046         * @param fAllowClose Indicates if close buttons should be set or not.
047         */
048        public IconTabbedPane(boolean fAllowClose) {
049            super();
050            m_fAllowClose = fAllowClose;
051            addMouseListener(new MouseAdapter() {
052                public void mouseClicked(MouseEvent e) {
053                    if (getAllowClose()) {
054                        tabNumber = getUI().tabForCoordinate(IconTabbedPane.this, e.getX(), e.getY());
055                        if (tabNumber < 0) {
056                            return;
057                        }
058                        Rectangle rect = ((CloseTabIcon)getIconAt(tabNumber)).getBounds();
059                        if (rect.contains(e.getX(), e.getY())) {
060                            getIconClicked();
061                        }
062                    }
063                }
064            });
065        }
066    
067        /**
068         * Specifies a new close icon. Icons which are set on currently open tabs will not be changed
069         * automatically.
070         * @param iNewIcon the new ImageIcon to be used as close icon.
071         */
072        public void setCloseIcon(ImageIcon iNewIcon) {
073            CLOSE_ICON = iNewIcon;
074        }
075    
076        /**
077         * Creates an IconTabbedPane with close buttons set. Calls <code>IconTabbedPane(true)</code>
078         */
079        public IconTabbedPane() {
080            this(true);
081        }
082    
083        /**
084         * Adds a tab to the IconTabbedPane. Depending on whether closing is allowed or not a close icon
085         * will be set or not, respectively.
086         * @param title the component's title
087         * @param component the compoment to be added as tab
088         */
089        public void addTab(String title, Component component) {
090            CloseTabIcon cti = getAllowClose() ? new CloseTabIcon(CLOSE_ICON) : null;
091            super.addTab(title, cti, component);
092        }
093    
094        /*public void removeTabAt(final int i) {
095    
096            try {
097                javax.swing.SwingUtilities.invokeAndWait(new Thread() {
098                    public void run() {
099                        IconTabbedPane.super.removeTabAt(i);
100                    }
101                });
102            }
103            catch (InvocationTargetException ex) {
104            }
105            catch (InterruptedException ex) {
106            }
107            //System.out.println(javax.swing.SwingUtilities.isEventDispatchThread());
108            //super.removeTabAt(i);
109        }*/
110    
111        /**
112         * @return the index of the tab whose close icon has been clicked most recently
113         */
114        public int getIconClicked() {
115            return tabNumber;
116        }
117    
118        /**
119         * Specifies if closing of tabs should be permitted or not.
120         * @param fAllowClose
121         */
122        public void setAllowClose(boolean fAllowClose) {
123            m_fAllowClose = fAllowClose;
124        }
125    
126        /**
127         * @return if closing of tabs is allowed or not.
128         */
129        public boolean getAllowClose() {
130            return m_fAllowClose;
131        }
132    
133        /**
134         * Extends ImageIcon by method <code>getBounds</code> to make it possible to determine the coordinates of
135         * the icon on the screen.
136         */
137        protected class CloseTabIcon extends ImageIcon {
138                    private static final long serialVersionUID = -3548845199557231620L;
139                    private int x_pos;
140            private int y_pos;
141            private int width;
142            private int height;
143            private ImageIcon imageIcon;
144    
145            /**
146             * Creates a CloseTabIcon from an ImageIcon.
147             */
148            public CloseTabIcon(ImageIcon icon) {
149                this.imageIcon = icon;
150                width = imageIcon.getIconWidth();
151                height = imageIcon.getIconHeight();
152            }
153    
154            /**
155             * Returns the image of the ImageIcon.
156             */
157            public Image getImage() {
158                return imageIcon.getImage();
159            }
160    
161            /**
162             * Paints the Icon. This method is usually not called directly.
163             */
164            public void paintIcon(Component c, Graphics g, int x, int y) {
165                imageIcon.paintIcon(c, g, x, y);
166                this.x_pos = x;
167                this.y_pos = y;
168            }
169    
170            /**
171             * Returns the icon's width.
172             */
173            public int getIconWidth() {
174                return width;
175            }
176    
177            /**
178             * Returns the icon's height.
179             */
180            public int getIconHeight() {
181                return height;
182            }
183    
184            /**
185             * Returns the position of the icon on the screen. Used to check for mouse clicks on the icon.
186             */
187            public Rectangle getBounds() {
188                return new Rectangle(x_pos, y_pos, width, height);
189            }
190        }
191    
192    }
193    
194