Source Code Cross Referenced for CellComponentFactory.java in  » Database-Client » squirrel-sql-2.6.5a » net » sourceforge » squirrel_sql » fw » datasetviewer » cellcomponent » 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 » Database Client » squirrel sql 2.6.5a » net.sourceforge.squirrel_sql.fw.datasetviewer.cellcomponent 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        package net.sourceforge.squirrel_sql.fw.datasetviewer.cellcomponent;
0002:
0003:        import java.awt.Color;
0004:        import java.awt.Component;
0005:        import java.io.FileInputStream;
0006:        import java.io.FileOutputStream;
0007:        import java.io.IOException;
0008:        import java.lang.reflect.Method;
0009:        import java.sql.PreparedStatement;
0010:        import java.sql.ResultSet;
0011:        import java.sql.Types;
0012:        import java.util.ArrayList;
0013:        import java.util.Arrays;
0014:        import java.util.HashMap;
0015:
0016:        import javax.swing.DefaultCellEditor;
0017:        import javax.swing.JLabel;
0018:        import javax.swing.JTable;
0019:        import javax.swing.JTextArea;
0020:        import javax.swing.JTextField;
0021:        import javax.swing.table.DefaultTableCellRenderer;
0022:        import javax.swing.table.TableCellRenderer;
0023:
0024:        import net.sourceforge.squirrel_sql.fw.datasetviewer.ColumnDisplayDefinition;
0025:        import net.sourceforge.squirrel_sql.fw.gui.OkJPanel;
0026:        import net.sourceforge.squirrel_sql.fw.sql.ISQLDatabaseMetaData;
0027:        import net.sourceforge.squirrel_sql.fw.util.log.ILogger;
0028:        import net.sourceforge.squirrel_sql.fw.util.log.LoggerController;
0029:
0030:        /**
0031:         * @author gwg
0032:         *
0033:         * This class is used by other parts of SQuirreL to handle all
0034:         * DataType-specific behavior for the ContentsTab.
0035:         * This includes reading/updating the DB, formatting data for display,
0036:         * validating user input, converting user input into an internal object
0037:         * of the appropriate type, and saving the data to or reading from a file.
0038:         * The actual work is handled by separate DataType-specific classes,
0039:         * so this class is a facade that selects the class to use and calls
0040:         * the desired method on that class.  All of the DataType-specifc classes
0041:         * implement the IDataTypeComponent interface.
0042:         * <P>
0043:         * At this time we use only the type of the data to determine which DataType
0044:         * class to use for the requested component.  In the future it may become
0045:         * useful to include other factors, such as the specific table and column
0046:         * being displayed.  This info could be used to select a specialized class
0047:         * (or a general class using an external resource file) to display table
0048:         * and column specific translations of data, such as mapping an integer
0049:         * code in the DB into a mnemonic representation (eg. 1='dial-up', 2='cable', 3='DSL').
0050:         * <P>
0051:         * The JTable is needed to allow the components to identify which cell
0052:         * is being referred to by a double-click mouse event, which causes
0053:         * a popup editing window to be generated.
0054:         * <P>
0055:         * <B>Creating new DataType handlers</B>
0056:         * Plugins and other code may need to create and install handlers for
0057:         * data types that are not included in the standard SQuirreL product.
0058:         * This might be needed to handle DBMS-specific data types,
0059:         * or to override the standard behavior for a specific data type.
0060:         * For example:
0061:         * <DL>
0062:         * <LI>
0063:         * PostgreSQL defines several non-standard data types, such as "bytea",
0064:         * "tid", "xid", int2vector", etc.  All of these have the same SQL type-code
0065:         * of "1111", which means "OTHER".
0066:         * The default ContesTab operation on type 1111 is to not display it
0067:         * and not allow editing.  However, if a plugin is able to define the
0068:         * operations on those fields, it can register a handler that will
0069:         * display the data appropriately and allow editing on those fields.
0070:         * <LI>
0071:         * If a DBMS defines a standard SQL data type in a non-standard way,
0072:         * a plugin for that DBMS may need to override the normal DataType class
0073:         * for that data type with another.
0074:         * An example would be if a DBMS implemented SQL type SMALLINT,
0075:         * which is handled internally as a Short, as an INTEGER, which is
0076:         * handled as an Integer.
0077:         * In order to correctly read and display values of that type in the ContentsTab,
0078:         * the handler for SQL type SMALLINT (=5) should be changed from
0079:         * DataTypeShort to DataTypeInteger.
0080:         * </DL>
0081:         * <P>
0082:         * Here is how to create and register a DataType handler:
0083:         * <DL>
0084:         * <LI>
0085:         * Using SQuirrel, connect to the DBMS.
0086:         * Click on the "Data Types" tab.
0087:         * Get the "TYPE_NAME" and "DATA_TYPE" values for the data type
0088:         * for which you want to create a handler.
0089:         * <LI>
0090:         * Create a handler for that type of data.
0091:         * The handler must implement the IDataTypeComponet interface.
0092:         * The files whose names start with "DataType..."
0093:         * in the package net.sourceforge.squirrel_sql.fw.datasetviewer.cellcomponent
0094:         * (i.e. the same place as this file)
0095:         * are examples of how to handle different data types.
0096:         * The data must be held in the JTable as a Java object.
0097:         * You must first identify what class of that object is.
0098:         * It may be your own local class or one of the standard Java classes
0099:         * since all of the code outside of the DataType class just treats it as an Object.
0100:         * The DataType class that you create must handle all transformations
0101:         * between that internal Java class and the Database,
0102:         * rendering in a cell, rendering in the Popup editing window
0103:         * (which may be the same as in a cell), and export/import with files.
0104:         * The DataType class also determines whether or not these verious translations
0105:         * are allowed.
0106:         * <LI>
0107:         * As part of the initialization of the application or plugin,
0108:         * register the DataType class as the handler for the data type.
0109:         * This is done using the static method registerDataType() in this class.
0110:         * The first argument is the fully-qualified name of the method,
0111:         * and the other two arguments identify the data type.
0112:         * For example:
0113:         * <PRE>
0114:         * 	CellComponentFactory.registerDataType(
0115:         * 		"net.sourceforge.squirrel_sql.plugins.postgreSQLPlugin.DataTypeBytea",
0116:         * 		1111, "bytea");
0117:         * </PRE>
0118:         * Another example, in the case where a SMALLINT is actually handled
0119:         * by the DBMS as an integer:
0120:         * <PRE>
0121:         * 	CellComponentFactory.registerDataType(
0122:         * 		"net.sourceforge.squirrel_sql.fw.datasetviewer.cellcomponent.DataTypeInteger",
0123:         * 		5, "SHORT");
0124:         * </PRE>
0125:         * Once the DataType class is registered,
0126:         * that class is called to process that data type in all of the
0127:         * associated data type.
0128:         * </DL>
0129:         * <P>
0130:         * The DataType registration process does not associate DataType handlers
0131:         * with particular DBMSs.  Therefore, if two plugins for two different DBMSs
0132:         * register exactly the same SQL Type code and data type name,
0133:         * one of the databases will not be handled correctly.
0134:         */
0135:        public class CellComponentFactory {
0136:
0137:            /* map of existing DataType objects for each column.
0138:             * The key is the ColumnDisplayDefinition object, and the value
0139:             * is the DataTypeObject for that column's data type.
0140:             */
0141:            static HashMap<ColumnDisplayDefinition, IDataTypeComponent> _colDataTypeObjects = new HashMap<ColumnDisplayDefinition, IDataTypeComponent>();
0142:
0143:            /* map of DBMS-specific registered data handlers.
0144:             * The key is a string of the form:
0145:             *   <SQL type as a string>:<SQL type name>
0146:             * and the value is a factory that can create instances of DBMS-specific
0147:             * DataTypeComponets.
0148:             */
0149:            static HashMap<String, IDataTypeComponentFactory> _pluginDataTypeFactories = new HashMap<String, IDataTypeComponentFactory>();
0150:
0151:            /* The current JTable that we are working with.
0152:             * This is used only to see when the user moves
0153:             * to a different JTable so we know when to clear
0154:             * the HashMap of DataTypeObjects.
0155:             */
0156:            static JTable _table = null;
0157:
0158:            /* logging mechanism for errors */
0159:            static private ILogger s_log = LoggerController
0160:                    .createLogger(CellComponentFactory.class);
0161:
0162:            /**
0163:             * Return the name of the Java class that is used to represent
0164:             * this data type within the application.
0165:             */
0166:            public static String getClassName(ColumnDisplayDefinition colDef) {
0167:                IDataTypeComponent dataTypeObject = getDataTypeObject(null,
0168:                        colDef);
0169:                if (dataTypeObject != null)
0170:                    return dataTypeObject.getClassName();
0171:                else
0172:                    return "java.lang.Object";
0173:            }
0174:
0175:            /**
0176:             * Determine if the values of two objects are the same.
0177:             */
0178:            public static boolean areEqual(ColumnDisplayDefinition colDef,
0179:                    Object newValue, Object oldValue) {
0180:
0181:                IDataTypeComponent dataTypeObject = getDataTypeObject(null,
0182:                        colDef);
0183:                if (dataTypeObject != null)
0184:                    return dataTypeObject.areEqual(newValue, oldValue);
0185:
0186:                // we should never get here because the areEqual function is only
0187:                // called when we are trying to update the database, so we know
0188:                // that we have a DataType object for this column (or we would
0189:                // have been stopped from editing by the isEditableXXX methods),
0190:                // but we need a return here to keep the compiler happy.
0191:                return false;
0192:            }
0193:
0194:            /*
0195:             * Operations for Text and in-cell work
0196:             */
0197:
0198:            /**
0199:             * Render value of object as a string for text output.
0200:             * Used by Text version of table.
0201:             */
0202:            public static String renderObject(Object value,
0203:                    ColumnDisplayDefinition colDef) {
0204:                IDataTypeComponent dataTypeObject = getDataTypeObject(null,
0205:                        colDef);
0206:
0207:                if (dataTypeObject != null)
0208:                    return dataTypeObject.renderObject(value);
0209:
0210:                // default behavior: toString
0211:                if (null == value) {
0212:                    return "<null>";
0213:                } else {
0214:                    return value.toString();
0215:                }
0216:            }
0217:
0218:            /**
0219:             * Get a TableCellRenderer for the given column.
0220:             */
0221:            public static TableCellRenderer getTableCellRenderer(
0222:                    ColumnDisplayDefinition colDef) {
0223:                return new CellRenderer(getDataTypeObject(null, colDef));
0224:            }
0225:
0226:            /**
0227:             * The base component of a DefaultTableCellRenderer is a JLabel.
0228:             * @author gwg
0229:             */
0230:            static private final class CellRenderer extends
0231:                    DefaultTableCellRenderer implements 
0232:                    SquirrelTableCellRenderer {
0233:                private static final long serialVersionUID = 1L;
0234:                transient private final IDataTypeComponent _dataTypeObject;
0235:
0236:                CellRenderer(IDataTypeComponent dataTypeObject) {
0237:                    super ();
0238:
0239:                    _dataTypeObject = dataTypeObject;
0240:                }
0241:
0242:                /**
0243:                 *
0244:                 * Returns the default table cell renderer - overridden from DefaultTableCellRenderer.
0245:                 *
0246:                 * @param table  the <code>JTable</code>
0247:                 * @param value  the value to assign to the cell at
0248:                 *			<code>[row, column]</code>
0249:                 * @param isSelected true if cell is selected
0250:                 * @param hasFocus true if cell has focus
0251:                 * @param row  the row of the cell to render
0252:                 * @param column the column of the cell to render
0253:                 * @return the default table cell renderer
0254:                 */
0255:                public Component getTableCellRendererComponent(JTable table,
0256:                        Object value, boolean isSelected, boolean hasFocus,
0257:                        int row, int column) {
0258:
0259:                    JLabel label = (JLabel) super 
0260:                            .getTableCellRendererComponent(table, value,
0261:                                    isSelected, hasFocus, row, column);
0262:
0263:                    // if text cannot be edited in the cell but can be edited in
0264:                    //				the popup, show that by changing the text colors.
0265:                    if (_dataTypeObject != null
0266:                            && _dataTypeObject.isEditableInCell(value) == false
0267:                            && _dataTypeObject.isEditableInPopup(value) == true) {
0268:                        // Use a CYAN background to indicate that the cell is
0269:                        // editable in the popup
0270:                        setBackground(Color.cyan);
0271:                    } else {
0272:                        // since the previous entry might have changed the color,
0273:                        // we need to reset the color back to default value for table cells,
0274:                        // taking into account whether the cell is selected or not.
0275:                        if (isSelected)
0276:                            setBackground(table.getSelectionBackground());
0277:                        else
0278:                            setBackground(table.getBackground());
0279:                    }
0280:
0281:                    return label;
0282:                }
0283:
0284:                public void setValue(Object value) {
0285:                    // default behavior if no DataType object is to use the
0286:                    // DefaultColumnRenderer with no modification.
0287:                    if (_dataTypeObject != null)
0288:                        super .setValue(_dataTypeObject.renderObject(value));
0289:                    else
0290:                        super .setValue(DefaultColumnRenderer.getInstance()
0291:                                .renderObject(value));
0292:                }
0293:
0294:                public Object renderValue(Object value) {
0295:                    if (_dataTypeObject != null) {
0296:                        return _dataTypeObject.renderObject(value);
0297:                    } else {
0298:                        return DefaultColumnRenderer.getInstance()
0299:                                .renderObject(value);
0300:                    }
0301:                }
0302:            }
0303:
0304:            /**
0305:             * Return true if the data type for the column may be edited
0306:             * within the table cell, false if not.
0307:             */
0308:            public static boolean isEditableInCell(
0309:                    ColumnDisplayDefinition colDef, Object originalValue) {
0310:                if (colDef.isAutoIncrement()) {
0311:                    return false;
0312:                }
0313:                IDataTypeComponent dataTypeObject = getDataTypeObject(null,
0314:                        colDef);
0315:
0316:                if (dataTypeObject != null)
0317:                    return dataTypeObject.isEditableInCell(originalValue);
0318:
0319:                // there was no data type object, so this data type is unknown
0320:                // to squirrel and thus cannot be edited.	
0321:                return false;
0322:            }
0323:
0324:            /**
0325:             * See if a value in a column has been limited in some way and
0326:             * needs to be re-read before being used for editing.
0327:             * For read-only tables this may actually return true since we want
0328:             * to be able to view the entire contents of the cell even if it was not
0329:             * completely loaded during the initial table setup.
0330:             */
0331:            public static boolean needToReRead(ColumnDisplayDefinition colDef,
0332:                    Object originalValue) {
0333:                IDataTypeComponent dataTypeObject = getDataTypeObject(null,
0334:                        colDef);
0335:
0336:                if (dataTypeObject != null)
0337:                    return dataTypeObject.needToReRead(originalValue);
0338:
0339:                // default - if we do not know the data type, then we cannot re-read it
0340:                return false;
0341:            };
0342:
0343:            /**
0344:             * Return a DefaultCellEditor using a JTextField with appropriate
0345:             * handlers to manage the type of input for the cell.
0346:             */
0347:            public static DefaultCellEditor getInCellEditor(JTable table,
0348:                    ColumnDisplayDefinition colDef) {
0349:
0350:                DefaultCellEditor ed;
0351:
0352:                IDataTypeComponent dataTypeObject = getDataTypeObject(table,
0353:                        colDef);
0354:
0355:                JTextField textField;
0356:
0357:                // Default behavior if no data type found is to use a restorable text field
0358:                // with no other special behavior and hope the object has a toString().
0359:                if (dataTypeObject != null)
0360:                    textField = dataTypeObject.getJTextField();
0361:                else
0362:                    textField = new RestorableJTextField();
0363:
0364:                textField.setBackground(Color.yellow);
0365:
0366:                ed = new CellEditorUsingRenderer(textField, dataTypeObject);
0367:                ed.setClickCountToStart(1);
0368:                return ed;
0369:            }
0370:
0371:            /**
0372:             * Call the validate and convert method in the appropriate
0373:             * DataType object.
0374:             */
0375:            public static Object validateAndConvert(
0376:                    ColumnDisplayDefinition colDef, Object originalValue,
0377:                    String inputValue, StringBuffer messageBuffer) {
0378:
0379:                IDataTypeComponent dataTypeObject = getDataTypeObject(null,
0380:                        colDef);
0381:
0382:                if (dataTypeObject != null) {
0383:                    // we have an appropriate data type object
0384:                    return dataTypeObject.validateAndConvert(inputValue,
0385:                            originalValue, messageBuffer);
0386:                }
0387:
0388:                // No appropriate DataType for this column, so do the best
0389:                // we can with what we know.
0390:                //
0391:                // THIS MAY NOT BE THE BEST BEHAVIOR HERE!!!!!!!
0392:
0393:                // Default Operation
0394:                if (inputValue.equals("<null>"))
0395:                    return null;
0396:                else
0397:                    return inputValue;
0398:            }
0399:
0400:            /**
0401:             * Return the flag from the component saying
0402:             * whether to do editing in the special binary editing panel
0403:             * or the component will handle all text input.
0404:             */
0405:            public static boolean useBinaryEditingPanel(
0406:                    ColumnDisplayDefinition colDef) {
0407:                IDataTypeComponent dataTypeObject = getDataTypeObject(null,
0408:                        colDef);
0409:
0410:                if (dataTypeObject != null) {
0411:                    // we have an appropriate data type object
0412:                    return dataTypeObject.useBinaryEditingPanel();
0413:                }
0414:                return false; // no object, so do not assume binary editing will work
0415:            }
0416:
0417:            /*
0418:             * Operations for Popup work.
0419:             */
0420:
0421:            /**
0422:             * Return true if the data type for the column may be edited
0423:             * in the popup, false if not.
0424:             */
0425:            public static boolean isEditableInPopup(
0426:                    ColumnDisplayDefinition colDef, Object originalValue) {
0427:                if (colDef != null && colDef.isAutoIncrement()) {
0428:                    return false;
0429:                }
0430:
0431:                IDataTypeComponent dataTypeObject = getDataTypeObject(null,
0432:                        colDef);
0433:
0434:                if (dataTypeObject != null) {
0435:                    return dataTypeObject.isEditableInPopup(originalValue);
0436:                }
0437:
0438:                // there was no data type object, so this data type is unknown
0439:                // to squirrel and thus cannot be edited.	
0440:                return false;
0441:            }
0442:
0443:            /**
0444:             * Return a JTextArea with appropriate handlers for editing
0445:             * the type of data in the cell.
0446:             */
0447:            public static JTextArea getJTextArea(
0448:                    ColumnDisplayDefinition colDef, Object value) {
0449:
0450:                // The first argument is a JTable, which is only used by instances
0451:                // of JTextField to convert coordinates on a double-click.  Since that
0452:                // cannot happen with the JTextArea, do not bother passing the table.
0453:
0454:                IDataTypeComponent dataTypeObject = getDataTypeObject(null,
0455:                        colDef);
0456:
0457:                if (dataTypeObject != null)
0458:                    return dataTypeObject.getJTextArea(value);
0459:
0460:                // default behavior if no appropriate data type found is to create
0461:                // a simple JTextArea with no special handling.
0462:                //
0463:                // In Theory, this cannot happen because if there is no data type object
0464:                // for this column's data type, then isEditableInPopup returns false, so
0465:                // we should not get here.  If there IS a data type object, and isEditableInPopup
0466:                // returns true, then we would have executed the return statement above.
0467:                // Assume that the value can be represented as a string.
0468:                RestorableJTextArea textArea = new RestorableJTextArea();
0469:                if (value != null) {
0470:                    textArea.setText(value.toString());
0471:                } else {
0472:                    textArea.setText("");
0473:                }
0474:                return textArea;
0475:            }
0476:
0477:            /**
0478:             * Call the validate and convert method in the appropriate
0479:             * DataType object.
0480:             */
0481:            public static Object validateAndConvertInPopup(
0482:                    ColumnDisplayDefinition colDef, Object originalValue,
0483:                    String inputValue, StringBuffer messageBuffer) {
0484:
0485:                IDataTypeComponent dataTypeObject = getDataTypeObject(null,
0486:                        colDef);
0487:
0488:                if (dataTypeObject != null) {
0489:                    // we have an appropriate data type object
0490:                    return dataTypeObject.validateAndConvertInPopup(inputValue,
0491:                            originalValue, messageBuffer);
0492:                }
0493:
0494:                // No appropriate DataType for this column, so do the best
0495:                // we can with what we know.
0496:                //
0497:                // THIS MAY NOT BE THE BEST BEHAVIOR HERE!!!!!!!
0498:
0499:                // Default Operation
0500:                if (inputValue.equals("<null>"))
0501:                    return null;
0502:                else
0503:                    return inputValue;
0504:            }
0505:
0506:            /*
0507:             * DataBase-related functions
0508:             */
0509:
0510:            /**
0511:             * Returns the result for the column at the specified index as determined 
0512:             * by a previously registered plugin DataTypeComponent.  Will return null 
0513:             * if the type cannot be handled by any plugin-registered DataTypeComponent.
0514:             * 
0515:             * @param rs
0516:             *        the ResultSet to read
0517:             * @param sqlType
0518:             *        the Java SQL type of the column
0519:             * @param sqlTypeName
0520:             *        the SQL type name of the column
0521:             * @param index
0522:             *        the index of the column that should be read
0523:             * 
0524:             * @return the value as interpreted by the plugin-registered
0525:             *         DataTypeComponent, or null if no plugin DataTypeComponent has
0526:             *         been registered for the specified sqlType and sqlTypename.
0527:             * 
0528:             * @throws Exception
0529:             */
0530:            public static Object readResultWithPluginRegisteredDataType(
0531:                    ResultSet rs, int sqlType, String sqlTypeName, int index)
0532:                    throws Exception {
0533:
0534:                Object result = null;
0535:                String typeNameKey = getRegDataTypeKey(sqlType, sqlTypeName);
0536:                if (_pluginDataTypeFactories.containsKey(typeNameKey)) {
0537:                    IDataTypeComponentFactory factory = _pluginDataTypeFactories
0538:                            .get(typeNameKey);
0539:                    IDataTypeComponent dtComp = factory
0540:                            .constructDataTypeComponent();
0541:                    ColumnDisplayDefinition colDef = new ColumnDisplayDefinition(
0542:                            rs, index);
0543:                    dtComp.setColumnDisplayDefinition(colDef);
0544:                    dtComp.setTable(_table);
0545:                    result = dtComp.readResultSet(rs, index, false);
0546:                }
0547:                return result;
0548:            }
0549:
0550:            /**
0551:             * On input from the DB, read the data from the ResultSet into the appropriate
0552:             * type of object to be stored in the table cell.
0553:             */
0554:            public static Object readResultSet(ColumnDisplayDefinition colDef,
0555:                    ResultSet rs, int index, boolean limitDataRead)
0556:                    throws java.sql.SQLException {
0557:
0558:                IDataTypeComponent dataTypeObject = getDataTypeObject(null,
0559:                        colDef);
0560:
0561:                if (dataTypeObject != null) {
0562:                    // we have an appropriate data type object
0563:                    return dataTypeObject.readResultSet(rs, index,
0564:                            limitDataRead);
0565:                }
0566:
0567:                //?? Best guess: read object?
0568:                //?? This is probably the wrong thing to do here, but
0569:                //?? I don't know what else to try.
0570:                return rs.getObject(index);
0571:            }
0572:
0573:            /**
0574:             * When updating the database, generate a string form of this object value
0575:             * that can be used in the WHERE clause to match the value in the database.
0576:             * A return value of null means that this column cannot be used in the WHERE
0577:             * clause, while a return of "null" (or "is null", etc) means that the column
0578:             * can be used in the WHERE clause and the value is actually a null value.
0579:             * This function must also include the column label so that its output
0580:             * is of the form:
0581:             * 	"columnName = value"
0582:             * or
0583:             * 	"columnName is null"
0584:             * or whatever is appropriate for this column in the database.
0585:             */
0586:            public static String getWhereClauseValue(
0587:                    ColumnDisplayDefinition colDef, Object value,
0588:                    ISQLDatabaseMetaData md) {
0589:                IDataTypeComponent dataTypeObject = getDataTypeObject(null,
0590:                        colDef);
0591:
0592:                if (dataTypeObject != null) {
0593:                    // we have an appropriate data type object
0594:                    return dataTypeObject.getWhereClauseValue(value, md);
0595:                }
0596:
0597:                // if no object for this data type, then cannot use value in where clause
0598:                return null;
0599:            }
0600:
0601:            /**
0602:             * When updating the database, insert the appropriate datatype into the
0603:             * prepared statment at the given variable position.
0604:             */
0605:            public static void setPreparedStatementValue(
0606:                    ColumnDisplayDefinition colDef, PreparedStatement pstmt,
0607:                    Object value, int position) throws java.sql.SQLException {
0608:
0609:                IDataTypeComponent dataTypeObject = getDataTypeObject(null,
0610:                        colDef);
0611:
0612:                // We should never NOT have an object here because we only get here
0613:                // when a DataType object has claimed that the column is editable.
0614:                // If there is no DataType for the column, then the default in the
0615:                // isEditableXXX() methods in this class is to say that the column
0616:                // is not editable, and therefore we should never have this method
0617:                // called in that case.
0618:                if (dataTypeObject != null) {
0619:                    // we have an appropriate data type object
0620:                    dataTypeObject.setPreparedStatementValue(pstmt, value,
0621:                            position);
0622:                }
0623:            }
0624:
0625:            /**
0626:             * Get a default value for the table used to input data for a new row
0627:             * to be inserted into the DB.
0628:             */
0629:            static public Object getDefaultValue(
0630:                    ColumnDisplayDefinition colDef, String dbDefaultValue) {
0631:                IDataTypeComponent dataTypeObject = getDataTypeObject(null,
0632:                        colDef);
0633:
0634:                if (dataTypeObject != null)
0635:                    return dataTypeObject.getDefaultValue(dbDefaultValue);
0636:
0637:                // there was no data type object, so this data type is unknown
0638:                // to squirrel and thus cannot be edited.	
0639:                return null;
0640:            }
0641:
0642:            /*
0643:             * File IO related functions
0644:             */
0645:
0646:            /**
0647:             * Say whether or not object can be exported to and imported from
0648:             * a file.  We put both export and import together in one test
0649:             * on the assumption that all conversions can be done both ways.
0650:             */
0651:            public static boolean canDoFileIO(ColumnDisplayDefinition colDef) {
0652:
0653:                IDataTypeComponent dataTypeObject = getDataTypeObject(null,
0654:                        colDef);
0655:
0656:                // if no DataType object, then there is nothing to handle File IO,
0657:                // so cannot do it
0658:                if (dataTypeObject == null)
0659:                    return false;
0660:
0661:                // let DataType object speak for itself
0662:                return dataTypeObject.canDoFileIO();
0663:            }
0664:
0665:            /**
0666:             * Read a file and construct a valid object from its contents.
0667:             * Errors are returned by throwing an IOException containing the
0668:             * cause of the problem as its message.
0669:             */
0670:            public static String importObject(ColumnDisplayDefinition colDef,
0671:                    FileInputStream inStream) throws IOException {
0672:
0673:                IDataTypeComponent dataTypeObject = getDataTypeObject(null,
0674:                        colDef);
0675:
0676:                // if no DataType object, then there is nothing to handle File IO,
0677:                // so cannot do it
0678:                if (dataTypeObject == null)
0679:                    throw new IOException(
0680:                            "No internal Data Type class for this column's SQL type");
0681:
0682:                // let DataType object speak for itself
0683:                return dataTypeObject.importObject(inStream);
0684:            }
0685:
0686:            /**
0687:             * Given a text string from the Popup, validate that it makes sense
0688:             * for the given DataType, then write it out to a file in the
0689:             * appropriate format.
0690:             * Errors are returned by throwing an IOException containing the
0691:             * cause of the problem as its message.
0692:             */
0693:            public static void exportObject(ColumnDisplayDefinition colDef,
0694:                    FileOutputStream outStream, String text) throws IOException {
0695:
0696:                IDataTypeComponent dataTypeObject = getDataTypeObject(null,
0697:                        colDef);
0698:
0699:                // if no DataType object, then there is nothing to handle File IO,
0700:                // so cannot do it
0701:                if (dataTypeObject == null)
0702:                    throw new IOException(
0703:                            "No internal Data Type class for this column's SQL type");
0704:
0705:                // let DataType object speak for itself
0706:                dataTypeObject.exportObject(outStream, text);
0707:            }
0708:
0709:            /**
0710:             * Constructs a key that is used to lookup previously registered custom
0711:             * types.
0712:             * 
0713:             * @param sqlType
0714:             *        the JDBC type code supplied by the driver
0715:             * @param sqlTypeName
0716:             *        the JDBC type name supplied by the driver
0717:             * 
0718:             * @return a key that can be used to store/retreive a custom type.
0719:             */
0720:            private static String getRegDataTypeKey(int sqlType,
0721:                    String sqlTypeName) {
0722:                StringBuilder result = new StringBuilder();
0723:                result.append(sqlType);
0724:                result.append(":");
0725:                result.append(sqlTypeName);
0726:                return result.toString();
0727:            }
0728:
0729:            /**
0730:             * Method for registering a DataTypeComponent factory for a non-standard
0731:             * SQL type (or for overriding a standard handler).
0732:             */
0733:            public static void registerDataTypeFactory(
0734:                    IDataTypeComponentFactory factory, int sqlType,
0735:                    String sqlTypeName) {
0736:                String typeName = getRegDataTypeKey(sqlType, sqlTypeName);
0737:
0738:                _pluginDataTypeFactories.put(typeName, factory);
0739:            }
0740:
0741:            /*
0742:             * Get control panels to let user adjust properties
0743:             * on DataType classes.
0744:             */
0745:
0746:            /**
0747:             * Get the Control Panels (JPanels containing controls) that let the
0748:             * user adjust the properties of static properties in specific DataTypes.
0749:             * The only DataType objects checked for here are:
0750:             * 	- those that are registered through the registerDataType method, and
0751:             * 	- those that are specifically listed in the variable initialClassNameList
0752:             */
0753:            public static OkJPanel[] getControlPanels() {
0754:                ArrayList<OkJPanel> panelList = new ArrayList<OkJPanel>();
0755:
0756:                /*
0757:                 * This is the list of names of classes that:
0758:                 * 	- support standard SQL type codes and thus do not need to be registered
0759:                 * 	- provide the getControlPanel method to allow manipulation of properties
0760:                 * These classes should all be named
0761:                 * 	net.sourceforge.squirrel_sql.fw.datasetviewer.cellcomponent.DataTypeXXXX
0762:                 * because they are part of the standard delivery of the product, and thus should
0763:                 * be local to this directory.
0764:                 */
0765:                String[] initialClassNameList = {
0766:                        net.sourceforge.squirrel_sql.fw.datasetviewer.cellcomponent.DataTypeBlob.class
0767:                                .getName(),
0768:                        net.sourceforge.squirrel_sql.fw.datasetviewer.cellcomponent.DataTypeClob.class
0769:                                .getName(),
0770:                        net.sourceforge.squirrel_sql.fw.datasetviewer.cellcomponent.DataTypeString.class
0771:                                .getName(),
0772:                        net.sourceforge.squirrel_sql.fw.datasetviewer.cellcomponent.DataTypeOther.class
0773:                                .getName(),
0774:                        net.sourceforge.squirrel_sql.fw.datasetviewer.cellcomponent.DataTypeUnknown.class
0775:                                .getName(),
0776:                        net.sourceforge.squirrel_sql.fw.datasetviewer.cellcomponent.DataTypeDate.class
0777:                                .getName(),
0778:                        net.sourceforge.squirrel_sql.fw.datasetviewer.cellcomponent.DataTypeTime.class
0779:                                .getName(),
0780:                        net.sourceforge.squirrel_sql.fw.datasetviewer.cellcomponent.DataTypeTimestamp.class
0781:                                .getName(),
0782:                        net.sourceforge.squirrel_sql.fw.datasetviewer.cellcomponent.FloatingPointBase.class
0783:                                .getName(), };
0784:
0785:                // make a single list of all class names that we need to check.
0786:                // Start with the names of known, standard classes that provide Control Panels
0787:                ArrayList<String> classNameList = new ArrayList<String>(Arrays
0788:                        .asList(initialClassNameList));
0789:
0790:                // add to that the list of all names that have been registered by plugins
0791:                //		Iterator<IDataTypeComponentFactory> pluginDataTypeFactories = 
0792:                //		    _registeredDataTypes.values().iterator();
0793:                //		while (pluginDataTypeFactories.hasNext()) {
0794:                //		    TODO: add support for plugin-registered data-type preferences panels
0795:                //		          when it is needed.
0796:                //		}
0797:
0798:                // Now go through the list in the given order to get the panels
0799:                for (int i = 0; i < classNameList.size(); i++) {
0800:                    String className = classNameList.get(i);
0801:                    Class<?>[] parameterTypes = new Class<?>[0];
0802:                    try {
0803:                        Method panelMethod = Class.forName(className)
0804:                                .getMethod("getControlPanel", parameterTypes);
0805:
0806:                        OkJPanel panel = (OkJPanel) panelMethod.invoke(null,
0807:                                (Object[]) null);
0808:                        panelList.add(panel);
0809:                    } catch (Exception e) {
0810:                        s_log.error("Unexpected exception: " + e.getMessage(),
0811:                                e);
0812:                    }
0813:                }
0814:
0815:                return panelList.toArray(new OkJPanel[0]);
0816:            }
0817:
0818:            /*
0819:             * Internal method used for both cell and popup work.
0820:             */
0821:
0822:            /* Identify the type of data in the cell and get an instance
0823:             * of the appropriate DataType object to work with it.
0824:             * 
0825:             * The JTable argument is used only by the DataType objects, not here.
0826:             * Also, since it is used only for converting coordinates when the user
0827:             * double-clicks in a cell, the JTextArea component does not use it, so
0828:             * it may be null in that case.
0829:             * 
0830:             * NOTE: This currently gets a new copy of the DataType object for every
0831:             * column even when multiple columns have the same SQL data type.  JTable's
0832:             * Render and Edit operations typically re-use the same CellRenderer and
0833:             * CellEditor objects for every cell by moving the viewpoint of the component
0834:             * to the location of the cell to be rendered/edited, setting the value in
0835:             * the component to the value at that cell, telling the component to paint,
0836:             * then moving that same component to the next cell.  For us, the cells have
0837:             * specific syntax or size constraints based on the SQL data type and the
0838:             * metadata from the DB, so we use different CellRenderer/Editor components
0839:             * for each column.  However, JTable's rendering/editing algorithm allows
0840:             * us to re-use the same component for all cells in the same column, which
0841:             * is what we do.  By saving the component, we avoid the need to create
0842:             * new instances each time the userstarts editing, creates the popup dialog,
0843:             * or does an operation requireing a static method call (e.g. validateAndConvert).
0844:             */
0845:            private static IDataTypeComponent getDataTypeObject(JTable table,
0846:                    ColumnDisplayDefinition colDef) {
0847:
0848:                // keep a hash table of the column objects
0849:                // so we can reuse them.
0850:                if (table != _table) {
0851:                    // new table - clear hash map
0852:                    _colDataTypeObjects.clear();
0853:                    _table = table;
0854:                }
0855:                if (_colDataTypeObjects.containsKey(colDef))
0856:                    return _colDataTypeObjects.get(colDef);
0857:
0858:                // we have not already created a DataType object for this column
0859:                // so do that now and save it
0860:                IDataTypeComponent dataTypeComponent = null;
0861:
0862:                /* See if we have a custom data-type registered. */
0863:                if (!_pluginDataTypeFactories.isEmpty()) {
0864:                    String typeName = getRegDataTypeKey(colDef.getSqlType(),
0865:                            colDef.getSqlTypeName());
0866:                    IDataTypeComponentFactory factory = _pluginDataTypeFactories
0867:                            .get(typeName);
0868:                    if (factory != null) {
0869:                        dataTypeComponent = factory
0870:                                .constructDataTypeComponent();
0871:                        if (colDef != null) {
0872:                            dataTypeComponent
0873:                                    .setColumnDisplayDefinition(colDef);
0874:                        }
0875:                        if (table != null) {
0876:                            dataTypeComponent.setTable(table);
0877:                        } else if (_table != null) {
0878:                            dataTypeComponent.setTable(_table);
0879:                        }
0880:                    }
0881:                }
0882:
0883:                // Use the standard SQL type code to get the right handler
0884:                // for this data type.
0885:                if (dataTypeComponent == null) {
0886:                    switch (colDef.getSqlType()) {
0887:                    case Types.NULL: // should never happen
0888:                        //??
0889:                        break;
0890:
0891:                    case Types.BIT:
0892:                    case Types.BOOLEAN:
0893:                        dataTypeComponent = new DataTypeBoolean(table, colDef);
0894:                        break;
0895:
0896:                    case Types.TIME:
0897:                        dataTypeComponent = new DataTypeTime(table, colDef);
0898:                        break;
0899:
0900:                    case Types.DATE:
0901:                        // Some databases store a time component in DATE columns (Oracle) 
0902:                        // The user can set a preference for DATEs that allows them
0903:                        // to be read as TIMESTAMP columns instead. This doesn't 
0904:                        // appear to have ill effects for databases that are standards
0905:                        // compliant (such as MySQL or PostgreSQL).  If the user 
0906:                        // prefers it, use the TIMESTAMP data type instead of DATE.
0907:                        if (DataTypeDate.getReadDateAsTimestamp()) {
0908:                            colDef.setSqlType(Types.TIMESTAMP);
0909:                            colDef.setSqlTypeName("TIMESTAMP");
0910:                            dataTypeComponent = new DataTypeTimestamp(table,
0911:                                    colDef);
0912:                        } else {
0913:                            dataTypeComponent = new DataTypeDate(table, colDef);
0914:                        }
0915:                        break;
0916:
0917:                    case Types.TIMESTAMP:
0918:                    case -101: // Oracle's 'TIMESTAMP WITH TIME ZONE' == -101  
0919:                    case -102: // Oracle's 'TIMESTAMP WITH LOCAL TIME ZONE' == -102
0920:                        dataTypeComponent = new DataTypeTimestamp(table, colDef);
0921:                        break;
0922:
0923:                    case Types.BIGINT:
0924:                        dataTypeComponent = new DataTypeLong(table, colDef);
0925:                        break;
0926:
0927:                    case Types.DOUBLE:
0928:                    case Types.FLOAT:
0929:                        dataTypeComponent = new DataTypeDouble(table, colDef);
0930:                        break;
0931:
0932:                    case Types.REAL:
0933:                        dataTypeComponent = new DataTypeFloat(table, colDef);
0934:                        break;
0935:
0936:                    case Types.DECIMAL:
0937:                    case Types.NUMERIC:
0938:                        dataTypeComponent = new DataTypeBigDecimal(table,
0939:                                colDef);
0940:                        break;
0941:
0942:                    case Types.INTEGER:
0943:                        // set up for integers
0944:                        dataTypeComponent = new DataTypeInteger(table, colDef);
0945:                        break;
0946:
0947:                    case Types.SMALLINT:
0948:                        dataTypeComponent = new DataTypeShort(table, colDef);
0949:                        break;
0950:
0951:                    case Types.TINYINT:
0952:                        dataTypeComponent = new DataTypeByte(table, colDef);
0953:                        break;
0954:
0955:                    // TODO: Hard coded -. JDBC/ODBC bridge JDK1.4
0956:                    // brings back -9 for nvarchar columns in
0957:                    // MS SQL Server tables.
0958:                    case Types.CHAR:
0959:                    case Types.VARCHAR:
0960:                    case Types.LONGVARCHAR:
0961:                    case -9:
0962:                        // set up for string types
0963:                        dataTypeComponent = new DataTypeString(table, colDef);
0964:                        break;
0965:
0966:                    // -8 is ROWID in Oracle.  It's a string, but it's auto-assigned
0967:                    case -8:
0968:                        dataTypeComponent = new DataTypeString(table, colDef);
0969:                        // Oracle jdbc driver doesn't properly identify this column
0970:                        // in ResultSetMetaData as read-only.  For now, just use 
0971:                        // isAutoIncrement flag to simulate this setting.
0972:                        colDef.setIsAutoIncrement(true);
0973:                        break;
0974:
0975:                    case Types.BINARY:
0976:                    case Types.VARBINARY:
0977:                    case Types.LONGVARBINARY:
0978:                        // set up for Binary types
0979:                        dataTypeComponent = new DataTypeBinary(table, colDef);
0980:                        break;
0981:
0982:                    case Types.BLOB:
0983:                        dataTypeComponent = new DataTypeBlob(table, colDef);
0984:                        break;
0985:
0986:                    case Types.CLOB:
0987:                        dataTypeComponent = new DataTypeClob(table, colDef);
0988:                        break;
0989:
0990:                    case Types.OTHER:
0991:                        dataTypeComponent = new DataTypeOther(table, colDef);
0992:                        break;
0993:
0994:                    //Add begin
0995:                    case Types.JAVA_OBJECT:
0996:                        dataTypeComponent = new DataTypeJavaObject(table,
0997:                                colDef);
0998:                        break;
0999:                    //Add end
1000:
1001:                    default:
1002:                        // data type is unknown to us.
1003:                        // It may be an unusual type like "JAVA OBJECT" or "ARRAY",
1004:                        // or it may be a DBMS-specific type
1005:                        dataTypeComponent = new DataTypeUnknown(table, colDef);
1006:
1007:                    }
1008:                }
1009:
1010:                // remember this DataType object so we can reuse it
1011:                _colDataTypeObjects.put(colDef, dataTypeComponent);
1012:
1013:                // If we get here, then no data type object was found for this column.
1014:                // (should not get here because switch default returns null.)
1015:                return dataTypeComponent;
1016:            }
1017:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.