Source Code Cross Referenced for TextComponentConnector.java in  » Swing-Library » jgoodies-data-binding » com » jgoodies » binding » adapter » 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 » Swing Library » jgoodies data binding » com.jgoodies.binding.adapter 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Copyright (c) 2002-2007 JGoodies Karsten Lentzsch. All Rights Reserved.
003:         *
004:         * Redistribution and use in source and binary forms, with or without
005:         * modification, are permitted provided that the following conditions are met:
006:         *
007:         *  o Redistributions of source code must retain the above copyright notice,
008:         *    this list of conditions and the following disclaimer.
009:         *
010:         *  o Redistributions in binary form must reproduce the above copyright notice,
011:         *    this list of conditions and the following disclaimer in the documentation
012:         *    and/or other materials provided with the distribution.
013:         *
014:         *  o Neither the name of JGoodies Karsten Lentzsch nor the names of
015:         *    its contributors may be used to endorse or promote products derived
016:         *    from this software without specific prior written permission.
017:         *
018:         * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019:         * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
020:         * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
021:         * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
022:         * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023:         * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024:         * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
025:         * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
026:         * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
027:         * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
028:         * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029:         */
030:
031:        package com.jgoodies.binding.adapter;
032:
033:        import java.beans.PropertyChangeEvent;
034:        import java.beans.PropertyChangeListener;
035:
036:        import javax.swing.JTextArea;
037:        import javax.swing.JTextField;
038:        import javax.swing.SwingUtilities;
039:        import javax.swing.event.DocumentEvent;
040:        import javax.swing.event.DocumentListener;
041:        import javax.swing.text.Document;
042:        import javax.swing.text.JTextComponent;
043:        import javax.swing.text.PlainDocument;
044:
045:        import com.jgoodies.binding.BindingUtils;
046:        import com.jgoodies.binding.PresentationModel;
047:        import com.jgoodies.binding.beans.BeanAdapter;
048:        import com.jgoodies.binding.value.ValueModel;
049:
050:        /**
051:         * Connects a String typed ValueModel and a JTextField or JTextArea.
052:         * At construction time the text component content is updated
053:         * with the subject's contents.<p>
054:         *
055:         * This connector has been designed for text components that display a plain
056:         * String. In case of a JEditorPane, the binding may require more information
057:         * then the plain String, for example styles. Since this is outside the scope
058:         * of this connector, the public constructors prevent a construction for
059:         * general JTextComponents. If you want to establish a one-way binding for
060:         * a display JEditorPane, use a custom listener instead.<p>
061:         *
062:         * This class provides limited support for handling
063:         * subject value modifications while updating the subject.
064:         * If a Document change initiates a subject value update, the subject
065:         * will be observed and a property change fired by the subject will be
066:         * handled - if any. In most cases, the subject will notify about a
067:         * change to the text that was just set by this connector.
068:         * However, in some cases the subject may decide to modify this text,
069:         * for example to ensure upper case characters.
070:         * Since at this moment, this adapter's Document is still write-locked,
071:         * the Document update is performed later using
072:         * <code>SwingUtilities#invokeLater</code>.<p>
073:         *
074:         * <strong>Note:</strong>
075:         * Such an update will typically change the Caret position in JTextField's
076:         * and other JTextComponent's that are synchronized using this class.
077:         * Hence, the subject value modifications can be used with
078:         * commit-on-focus-lost text components, but typically not with a
079:         * commit-on-key-typed component. For the latter case, you may consider
080:         * using a custom <code>DocumentFilter</code>.<p>
081:         *
082:         * <strong>Constraints:</strong>
083:         * The ValueModel must be of type <code>String</code>.<p>
084:         *
085:         * <strong>Examples:</strong><pre>
086:         * ValueModel lastNameModel = new PropertyAdapter(customer, "lastName", true);
087:         * JTextField lastNameField = new JTextField();
088:         * TextComponentConnector.connect(lastNameModel, lastNameField);
089:         *
090:         * ValueModel codeModel = new PropertyAdapter(shipment, "code", true);
091:         * JTextField codeField = new JTextField();
092:         * TextComponentConnector connector =
093:         *     new TextComponentConnector(codeModel, codeField);
094:         * connector.updateTextComponent();
095:         * </pre>
096:         *
097:         * @author  Karsten Lentzsch
098:         * @version $Revision: 1.9 $
099:         *
100:         * @see     ValueModel
101:         * @see     Document
102:         * @see     PlainDocument
103:         *
104:         * @since 1.2
105:         */
106:        public final class TextComponentConnector {
107:
108:            /**
109:             * Holds the underlying ValueModel that is used to read values,
110:             * to update the document and to write values if the document changes.
111:             */
112:            private final ValueModel subject;
113:
114:            /**
115:             * Refers to the text component that shall be synchronized
116:             * with the subject.
117:             */
118:            private final JTextComponent textComponent;
119:
120:            /**
121:             * Holds the text component's current document.
122:             * Used for the rare case where the text component fires
123:             * a PropertyChangeEvent for the "document" property
124:             * with oldValue or newValue == <code>null</code>.
125:             */
126:            private Document document;
127:
128:            private final SubjectValueChangeHandler subjectValueChangeHandler;
129:
130:            private final DocumentListener textChangeHandler;
131:
132:            private final PropertyChangeListener documentChangeHandler;
133:
134:            // Instance Creation ******************************************************
135:
136:            /**
137:             * Constructs a TextComponentConnector that connects the specified
138:             * String-typed subject ValueModel with the given text area.<p>
139:             *
140:             * In case you don't need the TextComponentConnector instance, you better
141:             * use one of the static <code>#connect</code> methods.
142:             * This constructor may confuse developers, if you just use
143:             * the side effects performed in the constructor; this is because it is
144:             * quite unconventional to instantiate an object that you never use.
145:             *
146:             * @param subject    the underlying String typed ValueModel
147:             * @param textArea   the JTextArea to be synchronized with the ValueModel
148:             *
149:             * @throws NullPointerException  if the subject or text area is <code>null</code>
150:             */
151:            public TextComponentConnector(ValueModel subject, JTextArea textArea) {
152:                this (subject, (JTextComponent) textArea);
153:            }
154:
155:            /**
156:             * Constructs a TextComponentConnector that connects the specified
157:             * String-typed subject ValueModel with the given text field.<p>
158:             *
159:             * In case you don't need the TextComponentConnector instance, you better
160:             * use one of the static <code>#connect</code> methods.
161:             * This constructor may confuse developers, if you just use
162:             * the side effects performed in the constructor; this is because it is
163:             * quite unconventional to instantiate an object that you never use.
164:             *
165:             * @param subject     the underlying String typed ValueModel
166:             * @param textField   the JTextField to be synchronized with the ValueModel
167:             *
168:             * @throws NullPointerException  if the subject or text field is <code>null</code>
169:             */
170:            public TextComponentConnector(ValueModel subject,
171:                    JTextField textField) {
172:                this (subject, (JTextComponent) textField);
173:            }
174:
175:            /**
176:             * Constructs a TextComponentConnector that connects the specified
177:             * String-typed subject ValueModel with the given JTextComponent.<p>
178:             *
179:             * In case you don't need the TextComponentConnector instance, you better
180:             * use one of the static <code>#connect</code> methods.
181:             * This constructor may confuse developers, if you just use
182:             * the side effects performed in the constructor; this is because it is
183:             * quite unconventional to instantiate an object that you never use.
184:             *
185:             * @param subject       the underlying String typed ValueModel
186:             * @param textComponent the JTextComponent to be synchronized with the ValueModel
187:             *
188:             * @throws NullPointerException  if the subject or text component is <code>null</code>
189:             */
190:            private TextComponentConnector(ValueModel subject,
191:                    JTextComponent textComponent) {
192:                if (subject == null)
193:                    throw new NullPointerException(
194:                            "The subject must not be null.");
195:                if (textComponent == null)
196:                    throw new NullPointerException(
197:                            "The text component must not be null.");
198:                this .subject = subject;
199:                this .textComponent = textComponent;
200:                this .subjectValueChangeHandler = new SubjectValueChangeHandler();
201:                this .textChangeHandler = new TextChangeHandler();
202:                document = textComponent.getDocument();
203:                reregisterTextChangeHandler(null, document);
204:                subject.addValueChangeListener(subjectValueChangeHandler);
205:                documentChangeHandler = new DocumentChangeHandler();
206:                textComponent.addPropertyChangeListener("document",
207:                        documentChangeHandler);
208:            }
209:
210:            /**
211:             * Establishes a synchronization between the specified String-typed
212:             * subject ValueModel and the given text area. Does not synchronize now.
213:             *
214:             * @param subject    the underlying String typed ValueModel
215:             * @param textArea   the JTextArea to be synchronized with the ValueModel
216:             *
217:             * @throws NullPointerException  if the subject or text area is <code>null</code>
218:             */
219:            public static void connect(ValueModel subject, JTextArea textArea) {
220:                new TextComponentConnector(subject, textArea);
221:            }
222:
223:            /**
224:             * Establishes a synchronization between the specified String-typed
225:             * subject ValueModel and the given text field. Does not synchronize now.
226:             *
227:             * @param subject    the underlying String typed ValueModel
228:             * @param textField   the JTextField to be synchronized with the ValueModel
229:             *
230:             * @throws NullPointerException  if the subject or text area is <code>null</code>
231:             */
232:            public static void connect(ValueModel subject, JTextField textField) {
233:                new TextComponentConnector(subject, textField);
234:            }
235:
236:            // Synchronization ********************************************************
237:
238:            /**
239:             * Reads the current text from the document
240:             * and sets it as new value of the subject.
241:             */
242:            public void updateSubject() {
243:                setSubjectText(getDocumentText());
244:            }
245:
246:            public void updateTextComponent() {
247:                setDocumentTextSilently(getSubjectText());
248:            }
249:
250:            /**
251:             * Returns the text contained in the document.
252:             *
253:             * @return the text contained in the document
254:             */
255:            private String getDocumentText() {
256:                return textComponent.getText();
257:            }
258:
259:            /**
260:             * Sets the document contents without notifying the subject of changes.
261:             * Invoked by the subject change listener. Removes the existing text first,
262:             * then inserts the new text; therefore a BadLocationException should not
263:             * happen. In case the delegate is an <code>AbstractDocument</code>
264:             * the text is replaced instead of a combined remove plus insert.<p>
265:             *
266:             * @param newText  the text to be set in the document
267:             */
268:            private void setDocumentTextSilently(String newText) {
269:                textComponent.getDocument().removeDocumentListener(
270:                        textChangeHandler);
271:                textComponent.setText(newText);
272:                textComponent.setCaretPosition(0);
273:                textComponent.getDocument().addDocumentListener(
274:                        textChangeHandler);
275:            }
276:
277:            /**
278:             * Returns the subject's text value.
279:             *
280:             * @return the subject's text value
281:             * @throws ClassCastException   if the subject value is not a String
282:             */
283:            private String getSubjectText() {
284:                String str = (String) subject.getValue();
285:                return str == null ? "" : str;
286:            }
287:
288:            /**
289:             * Sets the given text as new subject value. Since the subject may modify
290:             * this text, we cannot update silently, i.e. we cannot remove and add
291:             * the subjectValueChangeHandler before/after the update. Since this
292:             * change is invoked during a Document write operation, the document
293:             * is write-locked and so, we cannot modify the document before all
294:             * document listeners have been notified about the change.<p>
295:             *
296:             * Therefore we listen to subject changes and defer any document changes
297:             * using <code>SwingUtilities.invokeLater</code>. This mode is activated
298:             * by setting the subject change handler's <code>updateLater</code> to true.
299:             *
300:             * @param newText   the text to be set in the subject
301:             */
302:            private void setSubjectText(String newText) {
303:                subjectValueChangeHandler.setUpdateLater(true);
304:                try {
305:                    subject.setValue(newText);
306:                } finally {
307:                    subjectValueChangeHandler.setUpdateLater(false);
308:                }
309:            }
310:
311:            private void reregisterTextChangeHandler(Document oldDocument,
312:                    Document newDocument) {
313:                if (oldDocument != null) {
314:                    oldDocument.removeDocumentListener(textChangeHandler);
315:                }
316:                if (newDocument != null) {
317:                    newDocument.addDocumentListener(textChangeHandler);
318:                }
319:            }
320:
321:            // Misc *******************************************************************
322:
323:            /**
324:             * Removes the internal listeners from the subject, text component,
325:             * and text component's document.
326:             * This connector must not be used after calling <code>#release</code>.<p>
327:             *
328:             * To avoid memory leaks it is recommended to invoke this method,
329:             * if the ValueModel lives much longer than the text component.
330:             * Instead of releasing a text connector, you typically make the ValueModel
331:             * obsolete by releasing the PresentationModel or BeanAdapter that has
332:             * created the ValueModel.<p>
333:             *
334:             * As an alternative you may use ValueModels that in turn use
335:             * event listener lists implemented using <code>WeakReference</code>.
336:             *
337:             * @see PresentationModel#release()
338:             * @see BeanAdapter#release()
339:             * @see java.lang.ref.WeakReference
340:             */
341:            public void release() {
342:                reregisterTextChangeHandler(document, null);
343:                subject.removeValueChangeListener(subjectValueChangeHandler);
344:                textComponent.removePropertyChangeListener("document",
345:                        documentChangeHandler);
346:            }
347:
348:            // DocumentListener *******************************************************
349:
350:            /**
351:             * Updates the subject if the text has changed.
352:             */
353:            private final class TextChangeHandler implements  DocumentListener {
354:
355:                /**
356:                 * There was an insert into the document; update the subject.
357:                 *
358:                 * @param e the document event
359:                 */
360:                public void insertUpdate(DocumentEvent e) {
361:                    updateSubject();
362:                }
363:
364:                /**
365:                 * A portion of the document has been removed; update the subject.
366:                 *
367:                 * @param e the document event
368:                 */
369:                public void removeUpdate(DocumentEvent e) {
370:                    updateSubject();
371:                }
372:
373:                /**
374:                 * An attribute or set of attributes has changed; do nothing.
375:                 *
376:                 * @param e the document event
377:                 */
378:                public void changedUpdate(DocumentEvent e) {
379:                    // Do nothing on attribute changes.
380:                }
381:            }
382:
383:            /**
384:             * Handles changes in the subject value and updates this document
385:             * - if necessary.<p>
386:             *
387:             * Document changes update the subject text and result in a subject
388:             * property change. Most of these changes will just reflect the
389:             * former subject change. However, in some cases the subject may
390:             * modify the text set, for example to ensure upper case characters.
391:             * This method reduces the number of document updates by checking
392:             * the old and new text. If the old and new text are equal or
393:             * both null, this method does nothing.<p>
394:             *
395:             * Since subject changes as a result of a document change may not
396:             * modify the write-locked document immediately, we defer the update
397:             * if necessary using <code>SwingUtilities.invokeLater</code>.<p>
398:             *
399:             * See the TextComponentConnector's JavaDoc class comment
400:             * for the limitations of the deferred document change.
401:             */
402:            private final class SubjectValueChangeHandler implements 
403:                    PropertyChangeListener {
404:
405:                private boolean updateLater;
406:
407:                void setUpdateLater(boolean updateLater) {
408:                    this .updateLater = updateLater;
409:                }
410:
411:                /**
412:                 * The subject value has changed; updates the document immediately
413:                 * or later - depending on the <code>updateLater</code> state.
414:                 *
415:                 * @param evt   the event to handle
416:                 */
417:                public void propertyChange(PropertyChangeEvent evt) {
418:                    final String oldText = getDocumentText();
419:                    final Object newValue = evt.getNewValue();
420:                    final String newText = newValue == null ? getSubjectText()
421:                            : (String) newValue;
422:                    if (BindingUtils.equals(oldText, newText))
423:                        return;
424:
425:                    if (updateLater) {
426:                        SwingUtilities.invokeLater(new Runnable() {
427:                            public void run() {
428:                                setDocumentTextSilently(newText);
429:                            }
430:                        });
431:                    } else {
432:                        setDocumentTextSilently(newText);
433:                    }
434:                }
435:
436:            }
437:
438:            /**
439:             * Re-registers the text change handler after document changes.
440:             */
441:            private final class DocumentChangeHandler implements 
442:                    PropertyChangeListener {
443:                public void propertyChange(PropertyChangeEvent evt) {
444:                    Document oldDocument = document;
445:                    Document newDocument = textComponent.getDocument();
446:                    reregisterTextChangeHandler(oldDocument, newDocument);
447:                    document = newDocument;
448:                }
449:            }
450:
451:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.