![JAR search and dependency download from the Maven repository](/logo.png)
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