Source Code Cross Referenced for SheetTable.java in  » IDE-Netbeans » openide » org » openide » explorer » propertysheet » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE Netbeans » openide » org.openide.explorer.propertysheet 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003:         *
0004:         * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005:         *
0006:         * The contents of this file are subject to the terms of either the GNU
0007:         * General Public License Version 2 only ("GPL") or the Common
0008:         * Development and Distribution License("CDDL") (collectively, the
0009:         * "License"). You may not use this file except in compliance with the
0010:         * License. You can obtain a copy of the License at
0011:         * http://www.netbeans.org/cddl-gplv2.html
0012:         * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013:         * specific language governing permissions and limitations under the
0014:         * License.  When distributing the software, include this License Header
0015:         * Notice in each file and include the License file at
0016:         * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
0017:         * particular file as subject to the "Classpath" exception as provided
0018:         * by Sun in the GPL Version 2 section of the License file that
0019:         * accompanied this code. If applicable, add the following below the
0020:         * License Header, with the fields enclosed by brackets [] replaced by
0021:         * your own identifying information:
0022:         * "Portions Copyrighted [year] [name of copyright owner]"
0023:         *
0024:         * Contributor(s):
0025:         *
0026:         * The Original Software is NetBeans. The Initial Developer of the Original
0027:         * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
0028:         * Microsystems, Inc. All Rights Reserved.
0029:         *
0030:         * If you wish your version of this file to be governed by only the CDDL
0031:         * or only the GPL Version 2, indicate your decision by adding
0032:         * "[Contributor] elects to include this software in this distribution
0033:         * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034:         * single choice of license, a recipient has the option to distribute
0035:         * your version of this file under either the CDDL, the GPL Version 2 or
0036:         * to extend the choice of license to its licensees as provided above.
0037:         * However, if you add GPL Version 2 code and therefore, elected the GPL
0038:         * Version 2 license, then the option applies only if the new code is
0039:         * made subject to such option by the copyright holder.
0040:         */
0041:
0042:        package org.openide.explorer.propertysheet;
0043:
0044:        import java.awt.Color;
0045:        import java.awt.Component;
0046:        import java.awt.Container;
0047:        import java.awt.ContainerOrderFocusTraversalPolicy;
0048:        import java.awt.Dimension;
0049:        import java.awt.Graphics;
0050:        import java.awt.Insets;
0051:        import java.awt.KeyboardFocusManager;
0052:        import java.awt.Point;
0053:        import java.awt.Rectangle;
0054:        import java.awt.Toolkit;
0055:        import java.awt.datatransfer.DataFlavor;
0056:        import java.awt.datatransfer.Transferable;
0057:        import java.awt.datatransfer.UnsupportedFlavorException;
0058:        import java.awt.event.ActionEvent;
0059:        import java.awt.event.FocusEvent;
0060:        import java.awt.event.KeyEvent;
0061:        import java.awt.event.MouseEvent;
0062:        import java.beans.FeatureDescriptor;
0063:        import java.beans.PropertyEditor;
0064:        import java.io.IOException;
0065:        import java.io.InputStream;
0066:        import java.io.Reader;
0067:        import java.io.StringBufferInputStream;
0068:        import java.io.StringReader;
0069:        import java.util.EventObject;
0070:        import java.util.logging.Level;
0071:        import java.util.logging.Logger;
0072:        import javax.swing.AbstractAction;
0073:        import javax.swing.Action;
0074:        import javax.swing.ActionMap;
0075:        import javax.swing.BorderFactory;
0076:        import javax.swing.DefaultListSelectionModel;
0077:        import javax.swing.InputMap;
0078:        import javax.swing.JComponent;
0079:        import javax.swing.JDialog;
0080:        import javax.swing.JFrame;
0081:        import javax.swing.JTable;
0082:        import javax.swing.KeyStroke;
0083:        import javax.swing.ListSelectionModel;
0084:        import javax.swing.SwingUtilities;
0085:        import javax.swing.TransferHandler;
0086:        import javax.swing.UIManager;
0087:        import javax.swing.event.ChangeEvent;
0088:        import javax.swing.event.TableModelEvent;
0089:        import javax.swing.plaf.TableUI;
0090:        import javax.swing.table.JTableHeader;
0091:        import javax.swing.table.TableCellEditor;
0092:        import javax.swing.table.TableCellRenderer;
0093:        import javax.swing.table.TableColumnModel;
0094:        import javax.swing.table.TableModel;
0095:        import org.openide.awt.HtmlRenderer;
0096:        import org.openide.nodes.Node;
0097:        import org.openide.nodes.Node.Property;
0098:        import org.openide.nodes.Node.PropertySet;
0099:        import org.openide.util.Exceptions;
0100:        import org.openide.util.NbBundle;
0101:
0102:        /**
0103:         * A JTable subclass that displays node properties.  To set the properties,
0104:         * call <code>getPropertySetModel().setPropertySets()</code>.  This class
0105:         * uses instance counts to track shared resources.  Do NOT un-final this class.
0106:         * <p>
0107:         * This class implements only property-specific functionality; the row-selection
0108:         * painting logic, etc, are in the superclass BaseTable.
0109:         *
0110:         * @author Tim Boudreau
0111:         */
0112:        final class SheetTable extends BaseTable implements 
0113:                PropertySetModelListener, CustomEditorAction.Invoker {
0114:            /** Action key for right-arrow expansion of property sets */
0115:            private static final String ACTION_EXPAND = "expandSet"; //NOI18N
0116:
0117:            /** Action key for left-arrow closing of property sets */
0118:            private static final String ACTION_COLLAPSE = "collapseSet"; //NOI18N
0119:
0120:            /** Action key for invoking the custom editor */
0121:            private static final String ACTION_CUSTOM_EDITOR = "invokeCustomEditor"; //NOI18N
0122:
0123:            /** Action key for action to log the curent property editor class*/
0124:            private static final String ACTION_EDCLASS = "edclass"; //NOI18N
0125:
0126:            /** A reference count so the finalizer can release the shared editor and
0127:             * renderer instances (which hold onto some fairly heavy GUI components
0128:             * when no more instances are active */
0129:            private static int instanceCount = 0;
0130:
0131:            /** Flag to block calls to setModel, etc., after initialization */
0132:            private transient boolean initialized = false;
0133:
0134:            /** Field to hold last edited feature descriptor if state was stored */
0135:            private FeatureDescriptor storedFd = null;
0136:
0137:            /** Field to hold last editing state if state was stored */
0138:            private boolean wasEditing = false;
0139:
0140:            /** Field to hold partial user input if state was stored while editing */
0141:            private Object partialValue = null;
0142:
0143:            /** Fallback field storing the last selected row, in the case that the
0144:             *  table changes and selection should be restored */
0145:            private int lastSelectedRow = -1;
0146:
0147:            /** Static sheetCellRenderer which will be shared by all instances of
0148:             * SheetTable */
0149:            private SheetCellRenderer renderer = null;
0150:
0151:            /** Static sheetCellEditor which will be shared by all instances of
0152:             * SheetTable */
0153:            private SheetCellEditor cellEditor = null;
0154:
0155:            /** Custom editor action used to invoke the custom editor from keyboard
0156:             * or button */
0157:            private Action customEditorAction = null;
0158:
0159:            /** Display name of the current node, for passing to the custom editor
0160:             * dialog for setting the title */
0161:            /** Action to collapse or expand a set when the user presses the left or right arrow */
0162:            private Action expandAction;
0163:
0164:            /** Action to collapse or expand a set when the user presses the left or right arrow */
0165:            private Action collapseAction;
0166:
0167:            /** For debugging, an action that prints the current selection's property editor class
0168:             * to the standard out  */
0169:            private Action edClassAction;
0170:
0171:            /** Name used for the custom editor dialog, set by PropertySheet */
0172:            private String beanName;
0173:
0174:            /** Flag set when a custom editor is opening until it closes.  This is
0175:             * used to shut off tooltips to avoid a Windows bug that when a tooltip
0176:             * appears, the window containing it will be fronted, moving the modal
0177:             * custom editor behind it. */
0178:            private boolean customEditorIsOpen = false;
0179:            private ReusablePropertyEnv reusableEnv = new ReusablePropertyEnv();
0180:            private ReusablePropertyModel reusableModel = new ReusablePropertyModel(
0181:                    reusableEnv);
0182:            boolean lastIncludeMargin = false;
0183:            private HtmlRenderer.Renderer htmlrenderer = null;
0184:
0185:            //***************Implementation of issue 9691 - restore editing state after failed edit (dlg shown) *********
0186:
0187:            /** field to keep a count of focus events - there will be two following a
0188:             * failed edit.  EditingStopped will set this value to 2.  FocusGained will
0189:             * decrement it.  Doing almost anything else that touches the property sheet
0190:             * will reset it to -1.  If it is 0 when a focusGained event occurs, editing
0191:             * will be restarted.  This is less than ideal, but the code that shows the
0192:             * dialog will not start blocking the AWT queue until after focus has
0193:             * returned and the editor has been removed.  We get one focusGained event as a
0194:             * result of the inplace editor being removed;  the second is the user closing
0195:             * the dialog.  */
0196:            int countDown = -1;
0197:            boolean lastFailed = false;
0198:
0199:            /** Creates a new instance of SheetTable */
0200:            public SheetTable() {
0201:                super (new SheetTableModel(), new SheetColumnModel(),
0202:                        new DefaultListSelectionModel());
0203:                setPropertySetModel(new PropertySetModelImpl());
0204:
0205:                //Set a default row height
0206:                setRowHeight(16);
0207:
0208:                //Show grid lines if no alternating color defined
0209:                setShowGrid(PropUtils.noAltBg());
0210:                setShowVerticalLines(PropUtils.noAltBg());
0211:                setShowHorizontalLines(PropUtils.noAltBg());
0212:                setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN);
0213:
0214:                if (!PropUtils.noAltBg()) {
0215:                    setIntercellSpacing(new Dimension(0, 0));
0216:                }
0217:
0218:                setGridColor(PropUtils.getSetRendererColor());
0219:
0220:                Color c = UIManager.getColor("PropSheet.selectionBackground"); //NOI18N
0221:
0222:                if (c != null) {
0223:                    setSelectionBackground(c);
0224:                }
0225:
0226:                c = UIManager.getColor("PropSheet.selectionForeground"); //NOI18N
0227:
0228:                if (c != null) {
0229:                    setSelectionForeground(c);
0230:                }
0231:
0232:                getAccessibleContext().setAccessibleName(
0233:                        NbBundle.getMessage(SheetTable.class,
0234:                                "ACSN_SHEET_TABLE")); //NOI18N
0235:
0236:                getAccessibleContext().setAccessibleDescription(
0237:                        NbBundle.getMessage(SheetTable.class,
0238:                                "ACSD_SHEET_TABLE")); //NOI18N
0239:
0240:                setTransferHandler(new SheetTableTransferHandler());
0241:
0242:                Color col = UIManager.getColor("netbeans.ps.background"); //NOI18N
0243:
0244:                if (col != null) {
0245:                    setBackground(col);
0246:                }
0247:
0248:                setFocusTraversalPolicy(new STPolicy());
0249:                instanceCount++;
0250:            }
0251:
0252:            //************Shared infrastructure*****************************    
0253:            protected void finalize() {
0254:                instanceCount--;
0255:
0256:                if (instanceCount == 0) {
0257:                    renderer = null;
0258:                    cellEditor = null;
0259:                    cleanup();
0260:                }
0261:            }
0262:
0263:            /** Fetch the static render instance shared among tables */
0264:            SheetCellRenderer getRenderer() {
0265:                if (renderer == null) {
0266:                    renderer = new SheetCellRenderer(true, reusableEnv,
0267:                            reusableModel);
0268:                }
0269:
0270:                return renderer;
0271:            }
0272:
0273:            /** Fetch the static editor instance shared among tables */
0274:            SheetCellEditor getEditor() {
0275:                if (cellEditor == null) {
0276:                    cellEditor = new SheetCellEditor(getReusablePropertyEnv());
0277:                }
0278:
0279:                return cellEditor;
0280:            }
0281:
0282:            /****************Bean getters/setters*****************************************
0283:
0284:                /** Implement's Rochelle's suggestion of including the display name
0285:             * of the edited bean in the custom editor dlg title.  SheetTable doesn't
0286:             * know what node it's displaying, so property sheet code sets this
0287:             * when it changes */
0288:            void setBeanName(String name) {
0289:                this .beanName = name;
0290:            }
0291:
0292:            /** Fetch the name of the currently displayed JavaBean */
0293:            public String getBeanName() {
0294:                return beanName;
0295:            }
0296:
0297:            /** Returns a reference to the static editor shared among all instances
0298:             * of SheetTable */
0299:            public TableCellEditor getCellEditor(int row, int column) {
0300:                return getEditor();
0301:            }
0302:
0303:            /** Returns a reference to the static renderer shared among all instances
0304:             * of SheetTable */
0305:            public TableCellRenderer getCellRenderer(int row, int column) {
0306:                return getRenderer();
0307:            }
0308:
0309:            //**********Overrides of model setters to disable changes that would break the impl******    
0310:
0311:            /** Throws an UnsupportedOperationException when called by user code.  Replacing
0312:             *  the data model of property sheets is unsupported.  You can change the model
0313:             *  that determines what properties are shown - see <code>setPropertySetModel()</code>. */
0314:            public void setModel(TableModel model) {
0315:                if (initialized) {
0316:                    throw new UnsupportedOperationException(
0317:                            "Changing the model of a property sheet table is not supported.  If you want to change the set of properties, ordering or other characteristings, see setPropertySetModel()."); //NOI18N
0318:                }
0319:
0320:                super .setModel(model);
0321:            }
0322:
0323:            /** Throws an UnsupportedOperationException when called by user code.  Replacing
0324:             *  the column model of property sheets is unsupported.*/
0325:            public void setColumnModel(TableColumnModel model) {
0326:                if (initialized) {
0327:                    throw new UnsupportedOperationException(
0328:                            "Changing the column model of a property sheet table is not supported.  If you want to change the set of properties, ordering or other characteristings, see setPropertySetModel()."); //NOI18N
0329:                }
0330:
0331:                super .setColumnModel(model);
0332:            }
0333:
0334:            /** Throws an UnsupportedOperationException when called by user code.  Replacing
0335:             *  the selection model of property sheets not supported.*/
0336:            public void setSelectionModel(ListSelectionModel model) {
0337:                if (initialized) {
0338:                    throw new UnsupportedOperationException(
0339:                            "Changing the selection model of a property sheet table is not supported.  If you want to change the set of properties, ordering or other characteristings, see setPropertySetModel()."); //NOI18N
0340:                }
0341:
0342:                super .setSelectionModel(model);
0343:            }
0344:
0345:            /** Set the model which determines the ordering of properties and expansion
0346:             *  state of embedded property sets. */
0347:            public void setPropertySetModel(PropertySetModel psm) {
0348:                PropertySetModel old = getSheetModel().getPropertySetModel();
0349:
0350:                if (old == psm) {
0351:                    return;
0352:                }
0353:
0354:                if (old != null) {
0355:                    old.removePropertySetModelListener(this );
0356:                }
0357:
0358:                getSheetModel().setPropertySetModel(psm);
0359:                psm.addPropertySetModelListener(this );
0360:            }
0361:
0362:            /** Convenience getter for the property set model. Delegates to the SheetModel. */
0363:            PropertySetModel getPropertySetModel() {
0364:                return getSheetModel().getPropertySetModel();
0365:            }
0366:
0367:            /** Convenience getter for the model as an instance of SheetTableModel. */
0368:            SheetTableModel getSheetModel() {
0369:                return (SheetTableModel) this .getModel();
0370:            }
0371:
0372:            /** Overridden to return null - some look and feels will want to create
0373:             * an empty header, and we don't want them to do that */
0374:            public JTableHeader getTableHeader() {
0375:                return null;
0376:            }
0377:
0378:            //******************Keyboard/mouse mgmt***********************************
0379:            protected void initKeysAndActions() {
0380:                super .initKeysAndActions();
0381:                unregisterKeyboardAction(KeyStroke.getKeyStroke(
0382:                        KeyEvent.VK_RIGHT, 0));
0383:                unregisterKeyboardAction(KeyStroke.getKeyStroke(
0384:                        KeyEvent.VK_LEFT, 0));
0385:
0386:                expandAction = new ExpandAction();
0387:                collapseAction = new CollapseAction();
0388:                edClassAction = new EditorClassAction();
0389:
0390:                InputMap imp = getInputMap();
0391:                InputMap impAncestor = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
0392:                ActionMap am = getActionMap();
0393:                KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_C,
0394:                        KeyEvent.CTRL_MASK);
0395:                imp.put(ks, null);
0396:
0397:                imp.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0),
0398:                        ACTION_EXPAND);
0399:
0400:                imp.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0),
0401:                        ACTION_COLLAPSE);
0402:
0403:                imp.put(KeyStroke.getKeyStroke(KeyEvent.VK_HOME,
0404:                        KeyEvent.SHIFT_DOWN_MASK
0405:                                | Toolkit.getDefaultToolkit()
0406:                                        .getMenuShortcutKeyMask()),
0407:                        ACTION_EDCLASS);
0408:
0409:                imp
0410:                        .put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0),
0411:                                ACTION_NEXT);
0412:
0413:                imp.put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB,
0414:                        KeyEvent.SHIFT_DOWN_MASK), ACTION_PREV);
0415:
0416:                impAncestor.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE,
0417:                        KeyEvent.CTRL_DOWN_MASK), ACTION_CUSTOM_EDITOR);
0418:
0419:                impAncestor
0420:                        .remove(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0));
0421:                impAncestor.remove(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0));
0422:
0423:                am.put(ACTION_EXPAND, expandAction);
0424:                am.put(ACTION_COLLAPSE, collapseAction);
0425:
0426:                am.put(ACTION_CUSTOM_EDITOR, getCustomEditorAction());
0427:                am.put(ACTION_EDCLASS, edClassAction);
0428:            }
0429:
0430:            Action getCustomEditorAction() {
0431:                if (customEditorAction == null) {
0432:                    customEditorAction = new CustomEditorAction(this );
0433:                }
0434:
0435:                return customEditorAction;
0436:            }
0437:
0438:            /** Overridden to cast value to FeatureDescriptor and return true if the
0439:             * text matches its display name.  The popup search field uses this method
0440:             * to check matches. */
0441:            protected boolean matchText(Object value, String text) {
0442:                if (value instanceof  FeatureDescriptor) {
0443:                    return ((FeatureDescriptor) value).getDisplayName()
0444:                            .toUpperCase().startsWith(text.toUpperCase());
0445:                } else {
0446:                    return false;
0447:                }
0448:            }
0449:
0450:            //******************Painting logic **********************************    
0451:
0452:            /** Paint the table.  After the super.paint() call, calls paintMargin() to fill
0453:             *  in the left edge with the appropriate color, and then calls paintExpandableSets()
0454:             *  to paint the property sets, which are not painted by the default painting
0455:             *  methods because they need to be painted across two rows.    */
0456:            public void paintComponent(Graphics g) {
0457:                boolean includeMargin = PropUtils
0458:                        .shouldDrawMargin(getPropertySetModel());
0459:
0460:                getRenderer().setIncludeMargin(includeMargin);
0461:                super .paintComponent(g);
0462:
0463:                if (!PropUtils.noAltBg()) {
0464:                    paintCenterLine(g);
0465:                }
0466:
0467:                if (includeMargin) {
0468:                    paintMargin(g);
0469:                }
0470:
0471:                paintExpandableSets(g);
0472:
0473:                lastIncludeMargin = includeMargin;
0474:            }
0475:
0476:            /** Workaround for excessive paints by SwingUtilities.paintComponent() */
0477:            private void paintComponent(Graphics g, Component c, int x, int y,
0478:                    int w, int h) {
0479:                c.setBounds(x, y, w, h);
0480:                g.translate(x, y);
0481:                c.paint(g);
0482:                g.translate(-x, -y);
0483:                c.setBounds(-w, -h, 0, 0);
0484:            }
0485:
0486:            /** Paints the center line in the property sheet if an alternate
0487:             * color has been specified, so the divider is visible */
0488:            private void paintCenterLine(Graphics g) {
0489:                Color c = PropUtils.getAltBg();
0490:                g.setColor(c);
0491:
0492:                int xpos = getColumn(SheetColumnModel.NAMES_IDENTIFIER)
0493:                        .getWidth() - 1;
0494:                g.drawLine(xpos, 0, xpos, getHeight());
0495:            }
0496:
0497:            /** We only use a single listener on the selected node, PropertySheet.SheetPCListener,
0498:             * to centralize things.  It will call this method if a property change is detected
0499:             * so that it can be repainted. */
0500:            void repaintProperty(String name) {
0501:                if (!isShowing()) {
0502:                    return;
0503:                }
0504:
0505:                if (PropUtils.isLoggable(SheetTable.class)) {
0506:                    PropUtils.log(SheetTable.class, "RepaintProperty: " + name);
0507:                }
0508:
0509:                PropertySetModel psm = getPropertySetModel();
0510:                int min = getFirstVisibleRow();
0511:
0512:                if (min == -1) {
0513:                    return;
0514:                }
0515:
0516:                int max = min + getVisibleRowCount();
0517:
0518:                for (int i = min; i < max; i++) {
0519:                    FeatureDescriptor fd = psm.getFeatureDescriptor(i);
0520:
0521:                    if (null != fd && fd.getName().equals(name)) {
0522:                        Rectangle r = getCellRect(i, 1, true);
0523:
0524:                        if (PropUtils.isLoggable(SheetTable.class)) {
0525:                            PropUtils.log(SheetTable.class, "Repainting " + r
0526:                                    + " for property " + name);
0527:                        }
0528:
0529:                        repaint(r.x, r.y, r.width, r.height);
0530:
0531:                        return;
0532:                    }
0533:                }
0534:
0535:                if (PropUtils.isLoggable(SheetTable.class)) {
0536:                    PropUtils.log(SheetTable.class,
0537:                            "Property is either scrolled offscreen or property name is bogus: "
0538:                                    + name);
0539:                }
0540:            }
0541:
0542:            /** Paint the outside margin where the spinners for expandable
0543:             *  sets are.  This should be derived from the standard control
0544:             *  color.  This method will overpaint the grid lines in this
0545:             *  area.    */
0546:            private void paintMargin(Graphics g) {
0547:                //Don't paint the margin for sorted modes
0548:                //fill the outer column with the set renderer color, per UI spec
0549:                g.setColor(PropUtils.getSetRendererColor());
0550:
0551:                int w = PropUtils.getMarginWidth();
0552:                int h = getHeight();
0553:
0554:                if (g.hitClip(0, 0, w, h)) {
0555:                    g.fillRect(0, 0, w, h);
0556:                }
0557:            }
0558:
0559:            public Component prepareRenderer(TableCellRenderer renderer,
0560:                    int row, int col) {
0561:                Component result = super .prepareRenderer(renderer, row, col);
0562:
0563:                if ((row < 0) || (row >= getRowCount())) {
0564:                    return result;
0565:                }
0566:
0567:                Object value = getValueAt(row, col);
0568:
0569:                if ((result != null) && value instanceof  Property && (col == 1)) {
0570:                    result.setEnabled(((Property) value).canWrite());
0571:                }
0572:
0573:                return result;
0574:            }
0575:
0576:            /** Paint the expandable sets.  These are painted double width,
0577:             *  across the entire width of the table. */
0578:            private void paintExpandableSets(Graphics g) {
0579:                int start = 0;
0580:                int end = getRowCount();
0581:
0582:                Insets ins = getInsets();
0583:
0584:                boolean canBeSelected = isKnownComponent(KeyboardFocusManager
0585:                        .getCurrentKeyboardFocusManager()
0586:                        .getPermanentFocusOwner());
0587:
0588:                for (int i = 0; i < end; i++) {
0589:                    int idx = start + i;
0590:                    Object value = getValueAt(idx, 0);
0591:
0592:                    if (value instanceof  PropertySet) {
0593:                        Rectangle r = getCellRect(idx, 0, false);
0594:                        r.x = ins.left;
0595:                        r.width = getWidth() - (ins.left + ins.right);
0596:
0597:                        if (g.hitClip(r.x, r.y, r.width, r.height)) {
0598:                            PropertySet ps = (PropertySet) value;
0599:
0600:                            String txt = ps.getHtmlDisplayName();
0601:                            boolean isHtml = txt != null;
0602:
0603:                            if (!isHtml) {
0604:                                txt = ps.getDisplayName();
0605:                            }
0606:
0607:                            if (htmlrenderer == null) {
0608:                                htmlrenderer = HtmlRenderer.createRenderer();
0609:                            }
0610:
0611:                            JComponent painter = (JComponent) htmlrenderer
0612:                                    .getTableCellRendererComponent(this , txt,
0613:                                            false, false, idx, 0);
0614:
0615:                            htmlrenderer.setHtml(isHtml);
0616:                            htmlrenderer.setParentFocused(true);
0617:
0618:                            htmlrenderer.setIconTextGap(2);
0619:
0620:                            htmlrenderer.setIcon(getPropertySetModel()
0621:                                    .isExpanded(ps) ? PropUtils
0622:                                    .getExpandedIcon() : PropUtils
0623:                                    .getCollapsedIcon());
0624:
0625:                            boolean selected = canBeSelected
0626:                                    && (getSelectedRow() == idx);
0627:
0628:                            if (!selected) {
0629:                                painter.setBackground(PropUtils
0630:                                        .getSetRendererColor());
0631:                                painter.setForeground(PropUtils
0632:                                        .getSetForegroundColor());
0633:                            } else {
0634:                                painter.setBackground(PropUtils
0635:                                        .getSelectedSetRendererColor());
0636:                                painter.setForeground(PropUtils
0637:                                        .getSelectedSetForegroundColor());
0638:                            }
0639:
0640:                            painter.setOpaque(true);
0641:
0642:                            paintComponent(g, painter, r.x, r.y, r.width,
0643:                                    r.height);
0644:                        }
0645:                    }
0646:                }
0647:            }
0648:
0649:            /** Overridden to check if the edit failed, and if so, set a focus event
0650:             * countdown for re-initiating editing */
0651:            public void editingStopped(ChangeEvent e) {
0652:                super .editingStopped(e);
0653:
0654:                //Po Ting's request for Rave - if commit on focus loss is on, all
0655:                //edits look like failures and trigger a new call to editCellAt()
0656:                if (!PropUtils.psCommitOnFocusLoss
0657:                        && !getEditor().isLastUpdateSuccessful()) {
0658:                    //The last update failed, we're two focus events away from really
0659:                    //having focus again - we'll get one, then the error dialog will
0660:                    //steal focus.  On the second one we've got focus back.
0661:                    countDown = 2;
0662:                }
0663:            }
0664:
0665:            /** Initiate editing automatically - triggered by the focus event countdown */
0666:            private void autoEdit() {
0667:                editCellAt(getSelectedRow(), getSelectedColumn(), null);
0668:
0669:                if (editorComp != null) {
0670:                    editorComp.requestFocus();
0671:                }
0672:
0673:                countDown = -1;
0674:            }
0675:
0676:            /** Overridden to clear the focus event countdown */
0677:            public void changeSelection(int row, int col, boolean a, boolean b) {
0678:                countDown = -1;
0679:                super .changeSelection(row, col, a, b);
0680:            }
0681:
0682:            /** Overridden to check the focus event countdown and initiate editing on
0683:             * the second focus event following a failed edit (dialog was shown) */
0684:            public void processFocusEvent(FocusEvent fe) {
0685:                super .processFocusEvent(fe);
0686:
0687:                if (fe.getID() == fe.FOCUS_GAINED) {
0688:                    countDown--;
0689:
0690:                    if (countDown == 0) {
0691:                        autoEdit();
0692:                    }
0693:                }
0694:
0695:                if ((fe.getID() == fe.FOCUS_GAINED)
0696:                        || ((fe.getOppositeComponent() != null)
0697:                                && (fe.getID() == fe.FOCUS_LOST) && !isAncestorOf(fe
0698:                                .getOppositeComponent()))) {
0699:                    //Ensure the description goes back to the node description if
0700:                    //we lose focus
0701:                    fireChange();
0702:                }
0703:            }
0704:
0705:            protected void focusLostCancel() {
0706:                if (PropUtils.psCommitOnFocusLoss && isEditing()) {
0707:                    getEditor().stopCellEditing();
0708:                } else {
0709:                    super .focusLostCancel();
0710:                }
0711:            }
0712:
0713:            //**********************Miscellaneous**************************    
0714:
0715:            /** Overridden to catch a mouse pressed event over the custom editor
0716:             * button and invoke the custom editor even if we do not have focus;
0717:             * otherwise, for example, in the options dialog, clicking from the
0718:             * tree to the table over the custom editor button will just set focus
0719:             * to the table, but will not initiate the custom editor dialog */
0720:            public void processMouseEvent(MouseEvent me) {
0721:                if (me.getID() == me.MOUSE_PRESSED
0722:                        && SwingUtilities.isLeftMouseButton(me)
0723:                        && onCustomEditorButton(me) && !hasFocus()) {
0724:                    if (PropUtils.psCommitOnFocusLoss && isEditing()) {
0725:                        getEditor().stopCellEditing();
0726:
0727:                        // #54211: it can happen that PropertySheet window is closed
0728:                        // when previous property editing is finished (e.g. Form
0729:                        // event properties) If this is the case don't try to edit
0730:                        // newly selected property.
0731:                        if (isGoingToBeClosed()) {
0732:                            return;
0733:                        }
0734:                    }
0735:
0736:                    int row = rowAtPoint(me.getPoint());
0737:                    int col = columnAtPoint(me.getPoint());
0738:
0739:                    if ((row != -1) && (col != -1)) {
0740:                        changeSelection(row, col, false, false);
0741:                        getCustomEditorAction().actionPerformed(
0742:                                new ActionEvent(this ,
0743:                                        ActionEvent.ACTION_PERFORMED,
0744:                                        ACTION_CUSTOM_EDITOR));
0745:                        me.consume();
0746:
0747:                        return;
0748:                    }
0749:                }
0750:
0751:                super .processMouseEvent(me);
0752:            }
0753:
0754:            /** Overridden to do nothing, the editor will take care of updating
0755:             * the value */
0756:            public void setValueAt(Object o, int row, int column) {
0757:                //do nothing
0758:            }
0759:
0760:            /** See if a component is one we know about or one the current editor
0761:             * knows about.  This affects whether we paint as if focused or not, and
0762:             * is used to determine what kind of focus changes mean we should stop
0763:             * editing, and what kind are ok */
0764:            protected boolean isKnownComponent(Component c) {
0765:                boolean result = super .isKnownComponent(c);
0766:
0767:                if (result) {
0768:                    return result;
0769:                }
0770:
0771:                if (c == null) {
0772:                    return false;
0773:                }
0774:
0775:                if (c instanceof  ButtonPanel) {
0776:                    return true;
0777:                }
0778:
0779:                InplaceEditor ie = getEditor().getInplaceEditor();
0780:
0781:                if (ie != null) {
0782:                    JComponent comp = ie.getComponent();
0783:
0784:                    if (comp == c) {
0785:                        return true;
0786:                    }
0787:
0788:                    if (comp.isAncestorOf(c)) {
0789:                        return true;
0790:                    }
0791:                }
0792:
0793:                if (c.getParent() instanceof  ButtonPanel) {
0794:                    return true;
0795:                }
0796:
0797:                if ((getParent() != null) && (getParent().isAncestorOf(c))) {
0798:                    return true;
0799:                }
0800:
0801:                Container par = getParent();
0802:
0803:                if ((par != null) && par.isAncestorOf(c)) {
0804:                    return true;
0805:                }
0806:
0807:                if (c instanceof  InplaceEditor) {
0808:                    return true;
0809:                }
0810:
0811:                InplaceEditor ine = getEditor().getInplaceEditor();
0812:
0813:                if (ine != null) {
0814:                    return ine.isKnownComponent(c);
0815:                }
0816:
0817:                return false;
0818:            }
0819:
0820:            /**  Returns true if a mouse event occured over the custom editor button.
0821:             *   This is used to supply button specific tooltips and launch the custom
0822:             *   editor without needing to instantiate a real button */
0823:            private boolean onCustomEditorButton(MouseEvent e) {
0824:                //see if we're in the approximate bounds of the custom editor button
0825:                Point pt = e.getPoint();
0826:                int row = rowAtPoint(pt);
0827:                int col = columnAtPoint(pt);
0828:                FeatureDescriptor fd = getSheetModel().getPropertySetModel()
0829:                        .getFeatureDescriptor(row);
0830:                if (null == fd) {
0831:                    //prevent NPE when the activated Node has been destroyed and a new one hasn't been set yet
0832:                    return false;
0833:                }
0834:
0835:                //see if the event happened over the custom editor button
0836:                boolean success;
0837:
0838:                if (PropUtils.noCustomButtons) {
0839:                    //#41412 - impossible to invoke custom editor on props w/ no inline
0840:                    //edit mode if the no custom buttons switch is set
0841:                    success = false;
0842:                } else {
0843:                    success = e.getX() > (getWidth() - PropUtils
0844:                            .getCustomButtonWidth());
0845:                }
0846:
0847:                //if it's a mouse button event, then we're not showing a tooltip, we're
0848:                //deciding if we should display a custom editor.  For read-only props that
0849:                //support one, we should return true, since clicking the non-editable cell
0850:                //is not terribly useful.
0851:                if ((e.getID() == MouseEvent.MOUSE_PRESSED)
0852:                        || (e.getID() == MouseEvent.MOUSE_RELEASED)
0853:                        || (e.getID() == MouseEvent.MOUSE_CLICKED)) {
0854:                    //We will show the custom editor for any click on the text value
0855:                    //of a property that looks editable but sets canEditAsText to false -
0856:                    //the click means the user is trying to edit something, so to just
0857:                    //swallow the gesture is confusing
0858:                    success |= Boolean.FALSE.equals(fd
0859:                            .getValue("canEditAsText"));
0860:
0861:                    if (!success && fd instanceof  Property) {
0862:                        PropertyEditor pe = PropUtils
0863:                                .getPropertyEditor((Property) fd);
0864:
0865:                        if ((pe != null) && pe.supportsCustomEditor()) {
0866:                            //Undocumented but used in Studio - in NB 3.5 and earlier, returning null from getAsText()
0867:                            //was a way to make a property non-editable
0868:                            success |= (pe.isPaintable()
0869:                                    && (pe.getAsText() == null) && (pe
0870:                                    .getTags() == null));
0871:                        }
0872:                    }
0873:                }
0874:
0875:                try {
0876:                    if (success) { //NOI18N
0877:
0878:                        if (fd instanceof  Property && (col == 1)) {
0879:                            boolean supp = PropUtils.getPropertyEditor(
0880:                                    (Property) fd).supportsCustomEditor();
0881:
0882:                            return (supp);
0883:                        }
0884:                    }
0885:                } catch (IllegalStateException ise) {
0886:                    //See bugtraq 4941073 - if a property accessed via Reflection throws
0887:                    //an unexpected exception (try customize bean on a vanilla GenericServlet
0888:                    //to produce this) when the getter is accessed, then we are already
0889:                    //displaying "Error fetching property value" in the value area of
0890:                    //the propertysheet.  No point in distracting the user with a 
0891:                    //stack trace - it's not our bug.
0892:                    Logger.getLogger(SheetTable.class.getName()).log(
0893:                            Level.WARNING, null, ise);
0894:                }
0895:
0896:                return false;
0897:            }
0898:
0899:            /** Overridden to supply different tooltips depending on mouse position (name,
0900:             *  value, custom editor button).  Will HTML-ize long tooltips*/
0901:            public String getToolTipText(MouseEvent e) {
0902:                if (customEditorIsOpen) {
0903:                    return null;
0904:                }
0905:
0906:                String result;
0907:                Point pt = e.getPoint();
0908:                int row = rowAtPoint(pt);
0909:                int col = columnAtPoint(pt);
0910:
0911:                if ((col == 1) && onCustomEditorButton(e)) {
0912:                    result = NbBundle.getMessage(SheetTable.class,
0913:                            "CTL_EDBUTTON_TIP"); // NOI18N
0914:                } else {
0915:                    result = getSheetModel().getDescriptionFor(row, col);
0916:
0917:                    if ((col == 1) && (result != null)
0918:                            && (result.length() > 100)) {
0919:                        //e.g. Jesse's new file list property gives massive
0920:                        //tooltips; break them up
0921:                        result = PropUtils.createHtmlTooltip(
0922:                                getPropertySetModel().getFeatureDescriptor(row)
0923:                                        .getDisplayName(), result);
0924:                    }
0925:                }
0926:
0927:                if ((result != null) && "".equals(result.trim())) {
0928:                    result = null; // prevents 2x2 dot as a tooltip
0929:                }
0930:
0931:                return result;
0932:            }
0933:
0934:            /** Convenience method to get the currently selected property.  Equivalent to calling
0935:             *  <code>getSheetModel().getPropertySetModel().getFeatureDescriptor(getSelectedRow())
0936:             *  </code>.  This method will return null if the table does not have focus or editing
0937:             *  is not in progress.  */
0938:            public final FeatureDescriptor getSelection() {
0939:                return _getSelection();
0940:            }
0941:
0942:            /** Internal implementation of getSelection() which returns the selected feature
0943:             *  descriptor whether or not the component has focus. */
0944:            public final FeatureDescriptor _getSelection() {
0945:                int i = getSelectedRow();
0946:                FeatureDescriptor result;
0947:
0948:                //Check bounds - a change can be fired after the model has been changed, but
0949:                //before the table has received the event and updated itself, in which case
0950:                //you get an AIOOBE
0951:                if (i < getPropertySetModel().getCount()) {
0952:                    result = getSheetModel().getPropertySetModel()
0953:                            .getFeatureDescriptor(getSelectedRow());
0954:                } else {
0955:                    result = null;
0956:                }
0957:
0958:                return result;
0959:            }
0960:
0961:            //*********Implementation of editing*************************************    
0962:
0963:            /**
0964:             * Overridden to do a bunch of property related things:  cancel editing
0965:             * if the name cell was clicked; ignore duplicate requests; ignore edit
0966:             * requests if the user is currently dragging the center line; launch
0967:             * the custom editor dialog without entering edit mode if a click is
0968:             * over the custom editor button;  expand/close property sets; directly
0969:             * toggle boolean values rather than rapidly instantiate and hide a
0970:             * checkbox editor
0971:             */
0972:            public boolean editCellAt(int row, int column, EventObject e) {
0973:                assert SwingUtilities.isEventDispatchThread();
0974:                enterEditRequest();
0975:
0976:                if ((editingRow == row) && isEditing()) {
0977:                    if (0 == column) {
0978:                        //click on name cell should stop editing
0979:                        getEditor().stopCellEditing();
0980:                        removeEditor();
0981:                    }
0982:                    //discard edit requests if we're already editing that cell
0983:                    exitEditRequest();
0984:
0985:                    return false;
0986:                }
0987:
0988:                //issue 37584, there are some requests for commit on focus loss,
0989:                //so we'll try experimental support for this.  Not sure it's a great
0990:                //idea, but might as well keep an open mind
0991:                if (PropUtils.psCommitOnFocusLoss && isEditing()) {
0992:                    getEditor().stopCellEditing();
0993:
0994:                    // #53870: it can happen that PropertySheet window is closed when
0995:                    // previous property editing is finished (e.g. Form event properties)
0996:                    // If this is the case don't try to edit newly selected property.
0997:                    if (isGoingToBeClosed()) {
0998:                        return false;
0999:                    }
1000:                }
1001:
1002:                if ((e instanceof  MouseEvent) && (onCenterLine((MouseEvent) e))) {
1003:                    //If it's a drag request, other code will handle it
1004:                    exitEditRequest();
1005:
1006:                    return false;
1007:                }
1008:
1009:                if ((e instanceof  MouseEvent)
1010:                        && (onCustomEditorButton((MouseEvent) e))) {
1011:                    if (PropUtils.isLoggable(SheetTable.class)) {
1012:                        PropUtils.log(SheetTable.class,
1013:                                "Got a mouse click on the "
1014:                                        + "custom editor button"); //NOI18N
1015:                    }
1016:
1017:                    if (isEditing() && (editingRow != row)) {
1018:                        removeEditor();
1019:                    }
1020:
1021:                    //If it's a click on the custom editor button, just display the
1022:                    //dialog, don't open an inplace editor
1023:                    int prevSel = getSelectedRow();
1024:                    changeSelection(row, column, false, false);
1025:
1026:                    if (prevSel != -1) {
1027:                        paintRow(prevSel);
1028:                    }
1029:
1030:                    paintSelectionRow();
1031:                    getCustomEditorAction().actionPerformed(
1032:                            new ActionEvent(this , 0, null));
1033:                    exitEditRequest();
1034:
1035:                    return false;
1036:                }
1037:
1038:                //Get the selected item
1039:                FeatureDescriptor fd = getPropertySetModel()
1040:                        .getFeatureDescriptor(row);
1041:
1042:                //See if we got an edit trigger for a property set - if so,
1043:                //toggle its expanded state
1044:                if (fd instanceof  PropertySet) {
1045:                    //It was a legitimate click, so do stop editing and set the
1046:                    //selection (otherwise selection will change but editor will remain)
1047:                    if (isEditing()) {
1048:                        removeEditor();
1049:                        changeSelection(row, column, false, false);
1050:                    }
1051:
1052:                    maybeToggleExpanded(row, e);
1053:                    exitEditRequest();
1054:
1055:                    return false;
1056:                }
1057:
1058:                //Set the flag indicating we're starting to edit - affects paint
1059:                //and focus requests
1060:
1061:                /*        boolean useRadioButtons = PropUtils.forceRadioButtons ||
1062:                            (fd.getValue ("stringValues") != null);
1063:                 */
1064:                boolean useRadioButtons = (e instanceof  MouseEvent && PropUtils.forceRadioButtons)
1065:                        || ((fd != null) && (fd.getValue("stringValues") != null));
1066:
1067:                //Special handling for boolean if checkbox - no need to create an 
1068:                //editor that will be removed immediately, just toggles the value
1069:                //programmatically
1070:                if (!useRadioButtons
1071:                        && (((column == 1) || e instanceof  KeyEvent) && checkEditBoolean(row))) {
1072:                    //if checkEditBoolean returned true, then the value was toggled -
1073:                    //set the flag off and return
1074:                    exitEditRequest();
1075:
1076:                    return false;
1077:                }
1078:
1079:                boolean result = false;
1080:
1081:                try {
1082:                    //Try to start an actual edit
1083:                    result = super .editCellAt(row, column, e);
1084:                } finally {
1085:                    exitEditRequest();
1086:                }
1087:
1088:                return result;
1089:            }
1090:
1091:            public void removeEditor() {
1092:                enterEditorRemoveRequest();
1093:
1094:                try {
1095:                    //        synchronized(getTreeLock()) {
1096:                    super .removeEditor();
1097:
1098:                    //Make the editor detach its listeners and clear values in the
1099:                    //inplace editor since we're done with it
1100:                    getEditor().setInplaceEditor(null);
1101:
1102:                    //        }
1103:                    //Order of removal can cause the custom editor button to get focus even
1104:                    //though it's no longer onscreen, when the custom editor is removed
1105:                    //        Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
1106:                } finally {
1107:                    exitEditorRemoveRequest();
1108:                }
1109:            }
1110:
1111:            /**Overridden to do the assorted black magic by which one determines if
1112:             * a property is editable */
1113:            public boolean isCellEditable(int row, int column) {
1114:                if (column == 0) {
1115:                    return false;
1116:                }
1117:
1118:                FeatureDescriptor fd = getPropertySetModel()
1119:                        .getFeatureDescriptor(row);
1120:                boolean result;
1121:
1122:                if (fd instanceof  PropertySet) {
1123:                    result = false;
1124:                } else {
1125:                    Property p = (Property) fd;
1126:                    result = p.canWrite();
1127:
1128:                    if (result) {
1129:                        Object val = p.getValue("canEditAsText"); //NOI18N
1130:
1131:                        if (val != null) {
1132:                            result &= Boolean.TRUE.equals(val);
1133:                        }
1134:                    }
1135:                }
1136:
1137:                return result;
1138:            }
1139:
1140:            /** Toggle the expanded state of a property set if either the event
1141:             *  was a double click in the title area, a single click in the spinner
1142:             *  area, or a keyboard event. */
1143:            private void maybeToggleExpanded(int row, EventObject e) {
1144:                boolean doExpand = true;
1145:
1146:                //If it's a mouse event, we need to check if it's a double click.
1147:                if (e instanceof  MouseEvent) {
1148:                    MouseEvent me = (MouseEvent) e;
1149:                    doExpand = me.getClickCount() > 1;
1150:
1151:                    //If not a double click, allow single click in the spinner margin
1152:                    if (!doExpand) {
1153:                        //marginWidth will definitely be initialized, you can't
1154:                        //click something that isn't on the screen
1155:                        doExpand = me.getPoint().x <= PropUtils
1156:                                .getMarginWidth();
1157:                    }
1158:                }
1159:
1160:                if (doExpand) {
1161:                    toggleExpanded(row);
1162:                }
1163:            }
1164:
1165:            /** Toggle the expanded state of a property set.  If editing, the edit is
1166:             *  cancelled.  */
1167:            private void toggleExpanded(int index) {
1168:                if (isEditing()) {
1169:                    getEditor().cancelCellEditing();
1170:                }
1171:
1172:                PropertySetModel psm = getSheetModel().getPropertySetModel();
1173:                psm.toggleExpanded(index);
1174:            }
1175:
1176:            /** In the case that an edit request is made on a boolean checkbox property, an
1177:             *  edit request should simply toggle its state without instantiating a custom
1178:             *  editor component.  Returns true if the state was toggled, in which case the
1179:             *  editor instantiation portion of editCellAt() should be aborted  */
1180:            boolean checkEditBoolean(int row) {
1181:                FeatureDescriptor fd = getSheetModel().getPropertySetModel()
1182:                        .getFeatureDescriptor(row);
1183:
1184:                if (fd.getValue("stringValues") != null) {
1185:                    return false; //NOI18N
1186:                }
1187:
1188:                Property p = (fd instanceof  Property) ? (Property) fd : null;
1189:
1190:                if (p != null) {
1191:                    Class c = p.getValueType();
1192:
1193:                    //only do this if the property is supplying no special values for
1194:                    //the tags - if it is, we are using the radio button renderer
1195:                    if ((c == Boolean.class) || (c == boolean.class)) {
1196:                        if (!isCellEditable(row, 1)) {
1197:                            return true;
1198:                        }
1199:
1200:                        //Okay, try to toggle it
1201:                        try {
1202:                            Boolean b = null;
1203:
1204:                            //get the current value
1205:                            try {
1206:                                b = (Boolean) p.getValue();
1207:                            } catch (ProxyNode.DifferentValuesException dve) {
1208:                                //If we're represeting conflicting multi-selected 
1209:                                //properties, we'll make them both true when we toggle
1210:                                b = Boolean.FALSE;
1211:                            }
1212:
1213:                            if (isEditing()) {
1214:                                removeEditor();
1215:                            }
1216:
1217:                            changeSelection(row, 1, false, false);
1218:
1219:                            //Toggle the value
1220:                            Boolean newValue = ((b == null) || Boolean.FALSE
1221:                                    .equals(b)) ? Boolean.TRUE : Boolean.FALSE;
1222:                            p.setValue(newValue);
1223:
1224:                            //Force an event so we'll repaint
1225:                            /*
1226:                            tableChanged(new TableModelEvent (getSheetModel(), row,
1227:                                row, 1, TableModelEvent.UPDATE));
1228:                             */
1229:                            paintRow(row);
1230:
1231:                            return true;
1232:                        } catch (Exception ex) {
1233:                            //Something wrong, log it
1234:                            Exceptions.printStackTrace(ex);
1235:                        }
1236:                    }
1237:                }
1238:
1239:                return false;
1240:            }
1241:
1242:            /** Overridden to set the colors apropriately - we always want the editor
1243:             * to appear selected */
1244:            public Component prepareEditor(TableCellEditor editor, int row,
1245:                    int col) {
1246:                if (editor == null) {
1247:                    return null;
1248:                }
1249:
1250:                Component result = super .prepareEditor(editor, row, col);
1251:
1252:                if (result == null) {
1253:                    return null;
1254:                }
1255:
1256:                //Usually result == ine, but custom impls may not be
1257:                InplaceEditor ine = getEditor().getInplaceEditor();
1258:
1259:                if (ine.supportsTextEntry()) {
1260:                    result.setBackground(PropUtils.getTextFieldBackground());
1261:                    result.setForeground(PropUtils.getTextFieldForeground());
1262:                }
1263:
1264:                if (result instanceof  JComponent) {
1265:                    //unlikely that it won't be
1266:                    ((JComponent) result).setBorder(BorderFactory
1267:                            .createEmptyBorder(0, PropUtils.getTextMargin(), 0,
1268:                                    0));
1269:                }
1270:
1271:                return result;
1272:            }
1273:
1274:            //***********Methods for storing state if a recoverable change is happening****    
1275:
1276:            /** Overridden to store some data in the event of a recoverable change,
1277:             * such as the row currently being edited */
1278:            public void tableChanged(TableModelEvent e) {
1279:                boolean ed = isEditing();
1280:                lastSelectedRow = ed ? getEditingRow() : getSelectionModel()
1281:                        .getAnchorSelectionIndex();
1282:
1283:                if (ed) {
1284:                    getEditor().stopCellEditing();
1285:                }
1286:
1287:                super .tableChanged(e);
1288:                restoreEditingState();
1289:            }
1290:
1291:            /** Temporarily store the currently edited feature descriptor and partial
1292:             * value from the editor.  This info is used to restore the editing state
1293:             * after temporary losses of focus and recoverable changes like reordering
1294:             * the model, or changes that derive from the underlying node */
1295:            void saveEditingState() {
1296:                storedFd = _getSelection();
1297:
1298:                if (isEditing()) {
1299:                    InplaceEditor ine = getEditor().getInplaceEditor();
1300:
1301:                    if (ine != null) {
1302:                        partialValue = ine.getValue();
1303:                    }
1304:                }
1305:            }
1306:
1307:            /** Restore the previous editing state, if the previously edited
1308:             * FeatureDescriptor is still available for editing */
1309:            void restoreEditingState() {
1310:                int idx = indexOfLastSelected();
1311:                boolean canResumeEditing = idx != -1;
1312:
1313:                if (!canResumeEditing) {
1314:                    idx = lastSelectedRow;
1315:                }
1316:
1317:                if (idx == -1) {
1318:                    clearSavedEditingState();
1319:
1320:                    return;
1321:                }
1322:
1323:                if (idx < getRowCount()) {
1324:                    changeSelection(idx, 1, false, false);
1325:
1326:                    if ((canResumeEditing) && wasEditing) {
1327:                        editCellAt(idx, 1);
1328:
1329:                        InplaceEditor ine = getEditor().getInplaceEditor();
1330:
1331:                        if ((ine != null) && (partialValue != null)) {
1332:                            ine.setValue(partialValue);
1333:                        }
1334:                    }
1335:                }
1336:
1337:                clearSavedEditingState();
1338:            }
1339:
1340:            /** Clear saved editing data, so no memory leaks can occur */
1341:            private void clearSavedEditingState() {
1342:                storedFd = null;
1343:                wasEditing = false;
1344:                partialValue = null;
1345:            }
1346:
1347:            /** Find the current index of the last edited FeatureDescriptor, to
1348:             * figure out in which cell to restore the editing state */
1349:            private int indexOfLastSelected() {
1350:                if (storedFd == null) {
1351:                    return -1;
1352:                }
1353:
1354:                PropertySetModel mdl = getPropertySetModel();
1355:                int idx = mdl.indexOf(storedFd);
1356:                storedFd = null;
1357:
1358:                return idx;
1359:            }
1360:
1361:            //*************PropertySetModelListener implementation ******************
1362:
1363:            /** If we know a change is going to happen, try to store the current
1364:             * state to restore after the change is completed.  Reordering of
1365:             * properties and addition of properties by the underlying node can
1366:             * trigger this.  Since the PropertySetModel has a cache of current
1367:             * properties, it can call this while its internal state is still
1368:             * intact */
1369:            public void pendingChange(PropertySetModelEvent e) {
1370:                if (e.isReordering()) {
1371:                    wasEditing = isEditing();
1372:                    saveEditingState();
1373:                } else {
1374:                    storedFd = null;
1375:                    wasEditing = false;
1376:                    partialValue = null;
1377:                }
1378:            }
1379:
1380:            public void boundedChange(PropertySetModelEvent e) {
1381:                //Do nothing, we'll get notification from the TableModel
1382:            }
1383:
1384:            public void wholesaleChange(PropertySetModelEvent e) {
1385:                //Do nothing, we'll get notification from the TableModel
1386:            }
1387:
1388:            //*************CustomEditorAction.Invoker implementation ******************
1389:            //Generally, EditablePropertyDisplayer does a lot more with this 
1390:            //interface than SheetTable needs to
1391:
1392:            /** Returns the content pane of our owner, so as to display the wait
1393:             * cursor while the dialog is being invoked */
1394:            public Component getCursorChangeComponent() {
1395:                Container cont = SheetTable.this .getTopLevelAncestor();
1396:
1397:                return (cont instanceof  JFrame) ? ((JFrame) cont)
1398:                        .getContentPane()
1399:                        : ((cont instanceof  JDialog) ? ((JDialog) cont)
1400:                                .getContentPane() : cont);
1401:            }
1402:
1403:            /** If we have been editing and the user has typed something, fetch this
1404:             * value to use in the custom editor */
1405:            public Object getPartialValue() {
1406:                Object partialValue = null;
1407:
1408:                if (isEditing() && (editingRow == getSelectedRow())) {
1409:                    InplaceEditor ine = getEditor().getInplaceEditor();
1410:
1411:                    if (ine != null) {
1412:                        partialValue = ine.getValue();
1413:
1414:                        //reset the inplace editor so the value is not taken when the editor
1415:                        //is closed
1416:                        ine.reset();
1417:                        getEditor().cancelCellEditing();
1418:                    }
1419:                } else {
1420:                    partialValue = null;
1421:
1422:                    if (isEditing()) {
1423:                        removeEditor();
1424:                    }
1425:                }
1426:
1427:                return partialValue;
1428:            }
1429:
1430:            /** Restarts inline edit mode if the the preceding custom edit failed */
1431:            public void editorClosed() {
1432:                if (lastFailed) {
1433:                    editCellAt(getSelectedRow(), 1, null);
1434:                }
1435:
1436:                repaint();
1437:                customEditorIsOpen = false;
1438:            }
1439:
1440:            public void editorOpened() {
1441:                //Make sure it's painted as non-focused
1442:                paintSelectionRow();
1443:                customEditorIsOpen = true;
1444:            }
1445:
1446:            public void editorOpening() {
1447:                lastFailed = false;
1448:                customEditorIsOpen = true;
1449:            }
1450:
1451:            public void valueChanged(java.beans.PropertyEditor editor) {
1452:                lastFailed = false;
1453:            }
1454:
1455:            public boolean allowInvoke() {
1456:                return true;
1457:            }
1458:
1459:            public void failed() {
1460:                lastFailed = true;
1461:            }
1462:
1463:            public boolean wantAllChanges() {
1464:                return false;
1465:            }
1466:
1467:            public ReusablePropertyEnv getReusablePropertyEnv() {
1468:                return reusableEnv;
1469:            }
1470:
1471:            public ReusablePropertyModel getReusablePropertyModel() {
1472:                return reusableModel;
1473:            }
1474:
1475:            private boolean isGoingToBeClosed() {
1476:                // TODO mkrauskopf: try to find better way for the case that
1477:                // PropertySheet is going to be removed (note that isShowing, isVisible,
1478:                // ... methods return still true when this method is called)
1479:                return getRowCount() <= 0;
1480:            }
1481:
1482:            @Override
1483:            public void setUI(TableUI ui) {
1484:                super .setUI(ui);
1485:                renderer = null;
1486:                cellEditor = null;
1487:            }
1488:
1489:            //*************Actions bound to the keyboard ******************
1490:            private class ExpandAction extends AbstractAction {
1491:                public ExpandAction() {
1492:                    super (ACTION_EXPAND);
1493:                }
1494:
1495:                public void actionPerformed(ActionEvent ae) {
1496:                    FeatureDescriptor fd = _getSelection();
1497:
1498:                    if (fd instanceof  PropertySet) {
1499:                        int row = SheetTable.this .getSelectedRow();
1500:                        boolean b = getPropertySetModel().isExpanded(fd);
1501:
1502:                        if (b) {
1503:                            toggleExpanded(row);
1504:                        }
1505:                    }
1506:                }
1507:
1508:                public boolean isEnabled() {
1509:                    return _getSelection() instanceof  PropertySet;
1510:                }
1511:            }
1512:
1513:            private class CollapseAction extends AbstractAction {
1514:                public CollapseAction() {
1515:                    super (ACTION_COLLAPSE);
1516:                }
1517:
1518:                public void actionPerformed(ActionEvent ae) {
1519:                    FeatureDescriptor fd = _getSelection();
1520:
1521:                    if (fd instanceof  PropertySet) {
1522:                        int row = SheetTable.this .getSelectedRow();
1523:                        boolean b = getPropertySetModel().isExpanded(fd);
1524:
1525:                        if (!b) {
1526:                            toggleExpanded(row);
1527:                        }
1528:                    }
1529:                }
1530:
1531:                public boolean isEnabled() {
1532:                    boolean result = _getSelection() instanceof  PropertySet;
1533:
1534:                    return result;
1535:                }
1536:            }
1537:
1538:            private class EditorClassAction extends AbstractAction {
1539:                public EditorClassAction() {
1540:                    super (ACTION_EDCLASS);
1541:                }
1542:
1543:                public void actionPerformed(ActionEvent ae) {
1544:                    int i = getSelectedRow();
1545:
1546:                    if (i != -1) {
1547:                        FeatureDescriptor fd = getPropertySetModel()
1548:                                .getFeatureDescriptor(i);
1549:
1550:                        if (fd instanceof  Property) {
1551:                            java.beans.PropertyEditor ped = PropUtils
1552:                                    .getPropertyEditor((Property) fd);
1553:                            System.err.println(ped.getClass().getName());
1554:                        } else {
1555:                            System.err.println("PropertySets - no editor"); //NOI18N
1556:                        }
1557:                    } else {
1558:                        System.err.println("No selection"); //NOI18N
1559:                    }
1560:                }
1561:
1562:                public boolean isEnabled() {
1563:                    return getSelectedRow() != -1;
1564:                }
1565:            }
1566:
1567:            private class STPolicy extends ContainerOrderFocusTraversalPolicy {
1568:                public Component getComponentAfter(Container focusCycleRoot,
1569:                        Component aComponent) {
1570:                    if (inEditorRemoveRequest()) {
1571:                        return SheetTable.this ;
1572:                    } else {
1573:                        Component result = super .getComponentAfter(
1574:                                focusCycleRoot, aComponent);
1575:
1576:                        return result;
1577:                    }
1578:                }
1579:
1580:                public Component getComponentBefore(Container focusCycleRoot,
1581:                        Component aComponent) {
1582:                    if (inEditorRemoveRequest()) {
1583:                        return SheetTable.this ;
1584:                    } else {
1585:                        return super .getComponentBefore(focusCycleRoot,
1586:                                aComponent);
1587:                    }
1588:                }
1589:
1590:                public Component getFirstComponent(Container focusCycleRoot) {
1591:                    if (!inEditorRemoveRequest() && isEditing()) {
1592:                        return editorComp;
1593:                    } else {
1594:                        return SheetTable.this ;
1595:                    }
1596:                }
1597:
1598:                public Component getDefaultComponent(Container focusCycleRoot) {
1599:                    if (!inEditorRemoveRequest() && isEditing()
1600:                            && editorComp.isShowing()) {
1601:                        return editorComp;
1602:                    } else {
1603:                        return SheetTable.this ;
1604:                    }
1605:                }
1606:
1607:                protected boolean accept(Component aComponent) {
1608:                    //Do not allow focus to go to a child of the editor we're using if
1609:                    //we are in the process of removing the editor
1610:                    if (isEditing() && inEditorRemoveRequest()) {
1611:                        InplaceEditor ine = getEditor().getInplaceEditor();
1612:
1613:                        if (ine != null) {
1614:                            if ((aComponent == ine.getComponent())
1615:                                    || ine.isKnownComponent(aComponent)) {
1616:                                return false;
1617:                            }
1618:                        }
1619:                    }
1620:
1621:                    return super .accept(aComponent) && aComponent.isShowing();
1622:                }
1623:            }
1624:
1625:            private static class SheetTableTransferHandler extends
1626:                    TransferHandler {
1627:                protected Transferable createTransferable(JComponent c) {
1628:                    if (c instanceof  SheetTable) {
1629:                        SheetTable table = (SheetTable) c;
1630:                        FeatureDescriptor fd = table.getSelection();
1631:
1632:                        if (fd == null) {
1633:                            return null;
1634:                        }
1635:
1636:                        String res = fd.getDisplayName();
1637:
1638:                        if (fd instanceof  Node.Property) {
1639:                            Node.Property prop = (Node.Property) fd;
1640:                            res += ("\t" + PropUtils.getPropertyEditor(prop)
1641:                                    .getAsText());
1642:                        }
1643:
1644:                        return new SheetTableTransferable(res);
1645:                    }
1646:
1647:                    return null;
1648:                }
1649:
1650:                public int getSourceActions(JComponent c) {
1651:                    return COPY;
1652:                }
1653:            }
1654:
1655:            /**
1656:             * Transferable implementation for SheetTable.
1657:             */
1658:            private static class SheetTableTransferable implements  Transferable {
1659:                private static DataFlavor[] stringFlavors;
1660:                private static DataFlavor[] plainFlavors;
1661:
1662:                static {
1663:                    try {
1664:                        plainFlavors = new DataFlavor[3];
1665:                        plainFlavors[0] = new DataFlavor(
1666:                                "text/plain;class=java.lang.String"); // NOI18N
1667:                        plainFlavors[1] = new DataFlavor(
1668:                                "text/plain;class=java.io.Reader"); // NOI18N
1669:                        // XXX isn't this just DataFlavor.plainTextFlavor?
1670:                        plainFlavors[2] = new DataFlavor(
1671:                                "text/plain;charset=unicode;class=java.io.InputStream"); // NOI18N
1672:
1673:                        stringFlavors = new DataFlavor[2];
1674:                        stringFlavors[0] = new DataFlavor(
1675:                                DataFlavor.javaJVMLocalObjectMimeType
1676:                                        + ";class=java.lang.String"); // NOI18N
1677:                        stringFlavors[1] = DataFlavor.stringFlavor;
1678:                    } catch (ClassNotFoundException cle) {
1679:                        assert false : cle;
1680:                    }
1681:                }
1682:
1683:                protected String plainData;
1684:
1685:                public SheetTableTransferable(String plainData) {
1686:                    this .plainData = plainData;
1687:                }
1688:
1689:                public DataFlavor[] getTransferDataFlavors() {
1690:                    int nPlain = (isPlainSupported()) ? plainFlavors.length : 0;
1691:                    int nString = (isPlainSupported()) ? stringFlavors.length
1692:                            : 0;
1693:                    int nFlavors = nPlain + nString;
1694:                    DataFlavor[] flavors = new DataFlavor[nFlavors];
1695:
1696:                    // fill in the array
1697:                    int nDone = 0;
1698:
1699:                    if (nPlain > 0) {
1700:                        System.arraycopy(plainFlavors, 0, flavors, nDone,
1701:                                nPlain);
1702:                        nDone += nPlain;
1703:                    }
1704:
1705:                    if (nString > 0) {
1706:                        System.arraycopy(stringFlavors, 0, flavors, nDone,
1707:                                nString);
1708:                        nDone += nString;
1709:                    }
1710:
1711:                    return flavors;
1712:                }
1713:
1714:                public boolean isDataFlavorSupported(DataFlavor flavor) {
1715:                    DataFlavor[] flavors = getTransferDataFlavors();
1716:
1717:                    for (int i = 0; i < flavors.length; i++) {
1718:                        if (flavors[i].equals(flavor)) {
1719:                            return true;
1720:                        }
1721:                    }
1722:
1723:                    return false;
1724:                }
1725:
1726:                public Object getTransferData(DataFlavor flavor)
1727:                        throws UnsupportedFlavorException, IOException {
1728:                    if (isPlainFlavor(flavor)) {
1729:                        String data = getPlainData();
1730:                        data = (data == null) ? "" : data;
1731:
1732:                        if (String.class
1733:                                .equals(flavor.getRepresentationClass())) {
1734:                            return data;
1735:                        } else if (Reader.class.equals(flavor
1736:                                .getRepresentationClass())) {
1737:                            return new StringReader(data);
1738:                        } else if (InputStream.class.equals(flavor
1739:                                .getRepresentationClass())) {
1740:                            // XXX should this enforce UTF-8 encoding?
1741:                            return new StringBufferInputStream(data);
1742:                        }
1743:
1744:                        // fall through to unsupported
1745:                    } else if (isStringFlavor(flavor)) {
1746:                        String data = getPlainData();
1747:                        data = (data == null) ? "" : data;
1748:
1749:                        return data;
1750:                    }
1751:
1752:                    throw new UnsupportedFlavorException(flavor);
1753:                }
1754:
1755:                // --- plain text flavors ----------------------------------------------
1756:
1757:                /**
1758:                 * Returns whether or not the specified data flavor is an plain flavor
1759:                 * that is supported.
1760:                 *
1761:                 * @param flavor the requested flavor for the data
1762:                 * @return boolean indicating whether or not the data flavor is supported
1763:                 */
1764:                protected boolean isPlainFlavor(DataFlavor flavor) {
1765:                    DataFlavor[] flavors = plainFlavors;
1766:
1767:                    for (int i = 0; i < flavors.length; i++) {
1768:                        if (flavors[i].equals(flavor)) {
1769:                            return true;
1770:                        }
1771:                    }
1772:
1773:                    return false;
1774:                }
1775:
1776:                /**
1777:                 * Should the plain text flavors be offered?  If so, the method
1778:                 * getPlainData should be implemented to provide something reasonable.
1779:                 */
1780:                protected boolean isPlainSupported() {
1781:                    return plainData != null;
1782:                }
1783:
1784:                /**
1785:                 * Fetch the data in a text/plain format.
1786:                 */
1787:                protected String getPlainData() {
1788:                    return plainData;
1789:                }
1790:
1791:                // --- string flavors --------------------------------------------------
1792:
1793:                /**
1794:                 * Returns whether or not the specified data flavor is a String flavor
1795:                 * that is supported.
1796:                 *
1797:                 * @param flavor the requested flavor for the data
1798:                 * @return boolean indicating whether or not the data flavor is supported
1799:                 */
1800:                protected boolean isStringFlavor(DataFlavor flavor) {
1801:                    DataFlavor[] flavors = stringFlavors;
1802:
1803:                    for (int i = 0; i < flavors.length; i++) {
1804:                        if (flavors[i].equals(flavor)) {
1805:                            return true;
1806:                        }
1807:                    }
1808:
1809:                    return false;
1810:                }
1811:            }
1812:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.