001    /*
002     * $Id: DefaultXTreeCellEditor.java 3310 2009-03-26 10:25:24Z kleopatra $
003     *
004     * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
005     * Santa Clara, California 95054, U.S.A. All rights reserved.
006     *
007     * This library is free software; you can redistribute it and/or
008     * modify it under the terms of the GNU Lesser General Public
009     * License as published by the Free Software Foundation; either
010     * version 2.1 of the License, or (at your option) any later version.
011     * 
012     * This library is distributed in the hope that it will be useful,
013     * but WITHOUT ANY WARRANTY; without even the implied warranty of
014     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015     * Lesser General Public License for more details.
016     * 
017     * You should have received a copy of the GNU Lesser General Public
018     * License along with this library; if not, write to the Free Software
019     * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
020     */
021    package org.jdesktop.swingx.tree;
022    
023    import java.awt.Container;
024    import java.awt.Dimension;
025    import java.awt.Graphics;
026    
027    import javax.swing.Icon;
028    import javax.swing.JComponent;
029    import javax.swing.JTree;
030    import javax.swing.SwingUtilities;
031    import javax.swing.tree.DefaultTreeCellEditor;
032    import javax.swing.tree.DefaultTreeCellRenderer;
033    import javax.swing.tree.TreeCellEditor;
034    
035    import org.jdesktop.swingx.decorator.UIDependent;
036    
037    /**
038     * Subclassed to hack around core bug with RtoL editing (#4980473).
039     * 
040     * The price to pay is currently is to guarantee a minimum size of the
041     * editing field (is only one char wide if the node value is null).
042     * 
043     * PENDING: any possibility to position the editorContainer? 
044     * BasicTreeUI adds it to the tree and positions at the node location. 
045     * That's not a problem in LToR, only
046     * in RToL 
047     *
048     * 
049     * @author Jeanette Winzenburg
050     */
051    public class DefaultXTreeCellEditor extends DefaultTreeCellEditor implements UIDependent {
052    
053        public DefaultXTreeCellEditor(JTree tree, DefaultTreeCellRenderer renderer) {
054            super(tree, renderer);
055        }
056    
057        public DefaultXTreeCellEditor(JTree tree, DefaultTreeCellRenderer renderer,
058                TreeCellEditor editor) {
059            super(tree, renderer, editor);
060        }
061    
062        public void setRenderer(DefaultTreeCellRenderer renderer) {
063            this.renderer = renderer;
064        }
065        
066        public DefaultTreeCellRenderer getRenderer() {
067            return renderer;
068        }
069        
070        public class XEditorContainer extends EditorContainer {
071    
072            @Override
073            public Dimension getPreferredSize() {
074                if (isRightToLeft()) {
075                    if(editingComponent != null) {
076                        Dimension         pSize = editingComponent.getPreferredSize();
077        
078                        pSize.width += offset + 5;
079        
080                        Dimension         rSize = (renderer != null) ?
081                                                  renderer.getPreferredSize() : null;
082        
083                        if(rSize != null)
084                            pSize.height = Math.max(pSize.height, rSize.height);
085                        if(editingIcon != null)
086                            pSize.height = Math.max(pSize.height,
087                                                    editingIcon.getIconHeight());
088        
089                        // trying to enforce a minimum size leads to field being painted over the icon
090                        // Make sure width is at least 100.
091        //                pSize.width = Math.max(pSize.width, 100);
092                        return pSize;
093                    }
094                    return new Dimension(0, 0);
095                }
096                return super.getPreferredSize();
097                
098            }
099    
100            @Override
101            public void doLayout() {
102                if (isRightToLeft()) {
103                    Dimension             cSize = getSize();
104    
105                    editingComponent.getPreferredSize();
106                    editingComponent.setLocation(0, 0);
107                    editingComponent.setBounds(0, 0,
108                                               cSize.width - offset,
109                                               cSize.height);
110                } else {
111    
112                    super.doLayout();
113                }
114            }
115    
116    
117            @Override
118            public void paint(Graphics g) {
119                if (isRightToLeft()) {
120                    Dimension size = getSize();
121    
122                    // Then the icon.
123                    if (editingIcon != null) {
124                        int yLoc = Math.max(0, (size.height - editingIcon
125                                .getIconHeight()) / 2);
126                        int xLoc = Math.max(0, size.width - offset);
127                        editingIcon.paintIcon(this, g, xLoc, yLoc);
128                    }
129                    // need to prevent super from painting the icon
130                    Icon rememberIcon = editingIcon;
131                    editingIcon = null;
132                    super.paint(g);
133                    editingIcon = rememberIcon;
134                    
135                } else {
136                    super.paint(g);
137                }
138            }
139            
140        }
141    
142    
143        @Override
144        protected Container createContainer() {
145            return new XEditorContainer();
146        }
147    
148        @Override
149        protected void prepareForEditing() {
150            super.prepareForEditing();
151            applyComponentOrientation();
152        }
153    
154        protected void applyComponentOrientation() {
155            if (tree != null) {
156                editingContainer.applyComponentOrientation(tree.getComponentOrientation());
157            }
158            
159        }
160    
161        /**
162         * @return
163         */
164        private boolean isRightToLeft() {
165            return (tree != null) && (!tree.getComponentOrientation().isLeftToRight());
166        }
167    
168        /**
169         * Implement UIDependent. Quick hack for #1060-swingx: icons lost on laf toggle.
170         */
171        public void updateUI() {
172            if (getRenderer() != null) {
173                SwingUtilities.updateComponentTreeUI(getRenderer());
174            }
175            if (realEditor instanceof JComponent) {
176                SwingUtilities.updateComponentTreeUI((JComponent) realEditor);
177            } else if (realEditor instanceof UIDependent) {
178                ((UIDependent) realEditor).updateUI();
179            }
180            
181        }
182    
183    }