All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.cuf.model.ui.DocumentAdapter Maven / Gradle / Ivy

The newest version!
package net.sf.cuf.model.ui;

import net.sf.cuf.model.ValueModel;

import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
import javax.swing.text.BadLocationException;
import javax.swing.text.AbstractDocument;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.DocumentEvent;

/**
 * A DocumentAdapter connects the document of a Swing text widget
 * to the value of a ValueModel. Whenever one of the models
 * changes, the other is adjusted accordingly.
 * A DocumentAdapter is itself not a ValueModel, but connects a
 * ValueModel to a Document.
 * 

* A null value of the ValueModel is preserved until the document * changes. Note the following mapping: *

    *
  • Initially the ValueModel overrides the document. *
  • When copying the value from ValueModel to the document, * the value null is converted to an empty string, * but the ValueModel is not modified. *
  • When the document changes to "", * an empty string is set to the ValueModel instead of null. *
*/ public class DocumentAdapter implements ChangeListener, DocumentListener { /** the value model we are watching, never null */ private ValueModel mValueModel; /** the docment model we are watching, never null */ private Document mDocument; /** the widget we are watching, may be null */ private JTextComponent mTextComponent; /** marker if we are changing the value model */ private boolean mInSetValue; /** marker if we are changing the document */ private boolean mInInsertString; /** * Creates a new adapter between a ValueModel and the Document of a * JTextComponent. * Whenever one of the models changes, the other is adjusted accordingly. * The initial text is taken from the value model. * @param pValueModel the value model * @param pTextField text field we take the document model from * @throws IllegalArgumentException if pValueModel or pTextField are null */ public DocumentAdapter(final ValueModel pValueModel, final JTextComponent pTextField) { if (pTextField==null) throw new IllegalArgumentException("text field must not be null"); init(pValueModel, pTextField.getDocument(), pTextField); } /** * Creates a new adapter between a ValueModel and a Document. * Whenever one of the models changes, the other is adjusted accordingly. * The initial text is taken from the value model. * @param pValueModel the value model * @param pDocument the document model * @throws IllegalArgumentException if pValueModel or pDocument are null */ public DocumentAdapter(final ValueModel pValueModel, final Document pDocument) { init(pValueModel, pDocument, null); } /** * Common stuff of the constructors. * @param pValueModel the value model, must not be null * @param pDocument the document model, must not be null * @param pTextComponent the text component widget, may be null if we are only document bound * @throws IllegalArgumentException if pValueModel or pDocument are null */ private void init(final ValueModel pValueModel, final Document pDocument, final JTextComponent pTextComponent) { if (pValueModel==null) throw new IllegalArgumentException("value model must not be null"); if (pDocument==null) throw new IllegalArgumentException("text document must not be null"); mValueModel = pValueModel; mDocument = pDocument; mTextComponent = pTextComponent; mInSetValue = false; mInInsertString= false; propagateStateChange(getVMValue()); mValueModel.addChangeListener (this); mDocument .addDocumentListener(this); } /** * Return the text component we are adapting. * @return the text component, may be null if we are watching a document with multiple text components */ public JTextComponent getTextComponent() { return mTextComponent; } /** * Returns the VM content as a string. If no content is set, or the content is * null, an empty string is returned. * @return the VM content as a string, never null */ private String getVMValue() { String value = mValueModel.getValue(); return (value != null ? value : ""); } public void stateChanged(final ChangeEvent pEvent) { if (mInSetValue) { // this return is particularly important here, since the Document model is // allergic to modification while it is notifying others of changes return; } propagateStateChange(getVMValue()); } public void insertUpdate(final DocumentEvent pEvent) { propagateDocumentChange(); } public void removeUpdate(final DocumentEvent pEvent) { propagateDocumentChange(); } public void changedUpdate(final DocumentEvent pEvent) { propagateDocumentChange(); } /** * Handle changes of our ValueModel * @param pContent the new content, must not be null * @noinspection EmptyCatchBlock */ private void propagateStateChange(final String pContent) { // optimize if nothing changes, pContent is never null due to getVMValue if ((mDocument.getLength()==0) && (pContent.length()==0)) { return; } try { mInInsertString= true; if (mDocument instanceof AbstractDocument) { ((AbstractDocument)mDocument).replace(0, mDocument.getLength(), pContent, null); } else { mDocument.remove(0, mDocument.getLength()); mDocument.insertString(0, pContent, null); } } catch (BadLocationException ignored) { } finally { mInInsertString= false; } } /** * Handle changes of our Document. * @noinspection EmptyCatchBlock */ private void propagateDocumentChange() { if (mInInsertString) { return; } String documentContent= null; try { documentContent= mDocument.getText(0, mDocument.getLength()); } catch (BadLocationException ignored) {} try { mInSetValue= true; mValueModel.setValue(documentContent); } finally { mInSetValue= false; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy