All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.wings.STextComponent Maven / Gradle / Ivy
/*
* $Id$
* Copyright 2000,2005 wingS development team.
*
* This file is part of wingS (http://wingsframework.org).
*
* wingS is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
*
* Please see COPYING for the complete licence.
*/
package org.wings;
import org.wings.event.SDocumentEvent;
import org.wings.event.SDocumentListener;
import org.wings.event.SMouseEvent;
import org.wings.plaf.TextAreaCG;
import org.wings.plaf.TextFieldCG;
import org.wings.text.DefaultDocument;
import org.wings.text.SDocument;
import org.wings.sdnd.TextAndHTMLTransferable;
import org.wings.sdnd.SDropMode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.text.BadLocationException;
import javax.swing.*;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
/**
* Abstract base class of input text components like {@link STextArea} and {@link STextField}.
* Requires a surrounding {@link SForm} element!
*
* @author Armin Haaf
* @version $Revision$
*/
public abstract class STextComponent extends SComponent implements LowLevelEventListener, SDocumentListener {
private static final Logger LOG = LoggerFactory.getLogger(STextComponent.class);
private boolean editable = true;
private SDocument document;
/**
* @see LowLevelEventListener#isEpochCheckEnabled()
*/
private boolean epochCheckEnabled = true;
public STextComponent() {
this(new DefaultDocument(), true);
}
public STextComponent(String text) {
this(new DefaultDocument(text), true);
}
public STextComponent(SDocument document) {
this(document, true);
}
public STextComponent(SDocument document, boolean editable) {
setDocument(document);
setEditable(editable);
installTransferHandler();
createActionMap();
if(!(this instanceof STextField)) {
setDropMode(SDropMode.USE_SELECTION);
}
}
public SDocument getDocument() {
return document;
}
public void setDocument(SDocument document) {
if (document == null)
throw new IllegalArgumentException("null");
SDocument oldDocument = this.document;
this.document = document;
if (oldDocument != null)
oldDocument.removeDocumentListener(this);
document.addDocumentListener(this);
reloadIfChange(oldDocument, document);
propertyChangeSupport.firePropertyChange("document", oldDocument, this.document);
}
/**
* Defines if the textcomponent is editable or not.
* @see #isEditable()
* @param ed true if the text component is to be editable false if not.
*/
public void setEditable(boolean ed) {
boolean oldEditable = editable;
editable = ed;
if (editable != oldEditable)
reload();
propertyChangeSupport.firePropertyChange("editable", oldEditable, this.editable);
}
public boolean isEditable() {
return editable;
}
/**
* Sets the text of the component to the specified text.
* @see #getText()
* @param text the new text for the component.
*/
public void setText(String text) {
String oldVal = document.getText();
document.setText(text);
propertyChangeSupport.firePropertyChange("text", oldVal, document.getText());
}
public String getText() {
return document.getText();
}
/**
* Appends the given text to the end of the document. Does nothing
* if the string is null or empty.
*
* @param text the text to append.
*/
public void append(String text) {
try {
document.insert(document.getLength(), text);
} catch (BadLocationException e) {
}
}
@Override
public void processLowLevelEvent(String action, String... values) {
processKeyEvents(values);
if (action.endsWith("_keystroke"))
return;
if (isEditable() && isEnabled()) {
String newValue = values[0];
if (newValue != null && newValue.length() == 0) {
newValue = null;
}
String text = getText();
if (text != null && text.length() == 0) {
text = null;
}
if (isDifferent(newValue, text)) {
document.setDelayEvents(true);
setText(newValue);
document.setDelayEvents(false);
SForm.addArmedComponent(this);
}
}
}
public SDocumentListener[] getDocumentListeners() {
return document.getDocumentListeners();
}
public void addDocumentListener(SDocumentListener listener) {
document.addDocumentListener(listener);
}
public void removeDocumentListener(SDocumentListener listener) {
document.removeDocumentListener(listener);
}
@Override
public void fireIntermediateEvents() {
document.fireDelayedIntermediateEvents();
}
@Override
public void fireFinalEvents() {
super.fireFinalEvents();
document.fireDelayedFinalEvents();
}
/**
* @see LowLevelEventListener#isEpochCheckEnabled()
*/
@Override
public boolean isEpochCheckEnabled() {
return epochCheckEnabled;
}
/**
* @see LowLevelEventListener#isEpochCheckEnabled()
*/
public void setEpochCheckEnabled(boolean epochCheckEnabled) {
boolean oldVal = this.epochCheckEnabled;
this.epochCheckEnabled = epochCheckEnabled;
propertyChangeSupport.firePropertyChange("epochCheckEnabled", oldVal, this.epochCheckEnabled);
}
@Override
public void insertUpdate(SDocumentEvent e) {
//reload();
}
@Override
public void removeUpdate(SDocumentEvent e) {
//reload();
}
@Override
public void changedUpdate(SDocumentEvent e) {
if (isUpdatePossible()) {
if (STextField.class.isAssignableFrom(getClass()) && ! SPasswordField.class.isAssignableFrom(getClass()))
update(((TextFieldCG) getCG()).getTextUpdate((STextField) this, getText()));
else if (STextArea.class.isAssignableFrom(getClass()))
update(((TextAreaCG) getCG()).getTextUpdate((STextArea) this, getText()));
else
reload();
} else {
reload();
}
}
/**
* Drag and Drop stuff
*/
private int selectionStart;
private int selectionEnd;
private int caretPosition;
protected void createActionMap() {
ActionMap map = getActionMap();
map.put(STransferHandler.getCutAction().getValue(Action.NAME), STransferHandler.getCutAction());
map.put(STransferHandler.getCopyAction().getValue(Action.NAME), STransferHandler.getCopyAction());
map.put(STransferHandler.getPasteAction().getValue(Action.NAME), STransferHandler.getPasteAction());
}
public void setCaretPosition(int caretPosition) {
this.caretPosition = caretPosition;
}
/**
* Note: Used for Clipboard - only updated if done by setCaretPosition
* @return
*/
public int getCaretPosition() {
return caretPosition;
}
/**
* Internal Selection Mechanism for Drag and Drop - may be made public if a real selection support is introduced
* @return
*/
public int getSelectionStart() {
return selectionStart;
}
/**
* Internal Selection Mechanism for Drag and Drop - may be made public if a real selection support is introduced
* @param selectionStart
*/
public void setSelectionStart(int selectionStart) {
this.selectionStart = selectionStart;
}
/**
* Internal Selection Mechanism for Drag and Drop - may be made public if a real selection support is introduced
* @return
*/
public int getSelectionEnd() {
return selectionEnd;
}
/**
* Internal Selection Mechanism for Drag and Drop - may be made public if a real selection support is introduced
* @param selectionEnd
*/
public void setSelectionEnd(int selectionEnd) {
this.selectionEnd = selectionEnd;
}
/**
* Internal Selection Mechanism for Drag and Drop - may be made public if a real selection support is introduced
* @return
*/
protected String getSelectedText() {
String text = getText();
return text.substring(selectionStart, selectionEnd);
}
protected boolean dragEnabled = false;
protected SDropMode dropMode = null;
/**
* Sets the DropMode for this component - supports USE_SELECTION and INSERT
* @param dropMode
*/
public void setDropMode(SDropMode dropMode) {
if(dropMode == null || (dropMode != SDropMode.USE_SELECTION))
throw new IllegalArgumentException(dropMode + " - unsupported DropMode");
if(this instanceof STextField) {
LOG.warn("setDropMode: STextField as DropTarget will show different drop-behaviour in IE than in FF");
}
this.dropMode = dropMode;
getSession().getSDragAndDropManager().addDropTarget(this);
}
private void installTransferHandler() {
if(getTransferHandler() == null) {
setTransferHandler(new DefaultTransferHandler());
}
}
public SDropMode getDropMode() {
return this.dropMode;
}
public void setDragEnabled(boolean dragEnabled) {
if(dragEnabled != this.dragEnabled) {
if(dragEnabled)
this.getSession().getSDragAndDropManager().addDragSource(this);
else
this.getSession().getSDragAndDropManager().removeDragSource(this);
this.dragEnabled = dragEnabled;
}
}
public boolean getDragEnabled() {
return this.dragEnabled;
}
@Override
protected DropLocation dropLocationForPoint(SPoint point) {
if(point.getCoordinates() == null)
return null;
if(point.getCoordinates().contains("-") && point.getCoordinates().indexOf("-1") != 0) // dragstart => dragenter event
return null;
return new DropLocation(point);
}
public static final class DropLocation extends STransferHandler.DropLocation {
private int index;
public DropLocation(SPoint point) {
super(point);
try {
this.index = Integer.parseInt(point.getCoordinates());
if(this.index == -1)
this.index = 0;
} catch(NumberFormatException e) {
this.index = -1;
e.printStackTrace();
}
}
public int getIndex() {
return this.index;
}
}
private static class TextTransferable extends TextAndHTMLTransferable {
private int startPos, endPos;
private STextComponent component;
private STextComponent destComponent;
protected TextTransferable(STextComponent component, int startPos, int endPos) {
super(null, null);
this.startPos = startPos;
this.endPos = endPos;
this.component = component;
this.plainTextData = component.getSelectedText();
}
protected void setDestComponent(STextComponent component) {
this.destComponent = component;
}
protected void removeText() {
try {
component.getDocument().remove(this.startPos, this.endPos - this.startPos);
component.reload();
} catch (BadLocationException e) {
e.printStackTrace();
}
}
}
public static class DefaultTransferHandler extends STransferHandler {
public DefaultTransferHandler() {
super("text");
}
@Override
public void exportDone(SComponent source, Transferable transferable, int action) {
if(action == MOVE) {
if(transferable instanceof TextTransferable) {
((TextTransferable)transferable).removeText();
}
}
super.exportDone(source, transferable, action);
}
@Override
protected Transferable createTransferable(SComponent component) {
if(component instanceof STextComponent) {
STextComponent textComponent = (STextComponent)component;
return new TextTransferable(textComponent, textComponent.getSelectionStart(), textComponent.getSelectionEnd());
}
return null;
}
@Override
protected Transferable createTransferable(SComponent component, SMouseEvent event) {
if(component instanceof STextComponent) {
STextComponent textComponent = (STextComponent)component;
String[] stringArray = event.getPoint().getCoordinates().split("-");
int startIndex = Integer.parseInt(stringArray[0]);
int endIndex = Integer.parseInt(stringArray[1]);
textComponent.setSelectionStart(startIndex);
textComponent.setSelectionEnd(endIndex);
}
return super.createTransferable(component, event);
}
protected static DataFlavor getImportFlavor(STextComponent component, DataFlavor... flavors) {
for(DataFlavor flavor:flavors) {
if(flavor.getMimeType().startsWith("text/plain") || flavor.getMimeType().startsWith(DataFlavor.javaJVMLocalObjectMimeType) && flavor.getRepresentationClass() == String.class) {
return flavor;
}
}
return null;
}
@Override
public boolean canImport(SComponent component, DataFlavor... transferFlavors) {
STextComponent textComponent = (STextComponent)component;
if(!textComponent.isEditable() || !textComponent.isEnabled()) // if the component is not editable
return false; // or disabled, don't allow imports
return getImportFlavor(textComponent, transferFlavors) != null;
}
@Override
public boolean importData(SComponent component, Transferable transferable) {
try {
STextComponent textComponent = (STextComponent)component;
String data = (String)(transferable.getTransferData(getImportFlavor((STextComponent)component, transferable.getTransferDataFlavors())));
String text = textComponent.getText();
int insertIndex = textComponent.getCaretPosition();
if(insertIndex == -1) { // in case we couldn't determine a drop position, append
textComponent.setText(text + data);
return true;
}
if(insertIndex > text.length())
return false;
if(textComponent.getSelectionStart() == textComponent.getSelectionEnd()) {
String firstPart = text.substring(0, insertIndex);
String secondPart = text.substring(insertIndex);
if(transferable instanceof TextTransferable) {
((TextTransferable)transferable).setDestComponent((STextComponent)component);
}
textComponent.setText(firstPart + data + secondPart);
} else {
String firstPart = text.substring(0, textComponent.getSelectionStart());
String secondPart = text.substring(textComponent.getSelectionEnd());
textComponent.setText(firstPart + data + secondPart);
}
return true;
} catch (UnsupportedFlavorException | IOException e) {
}
return false;
}
@Override
public boolean importData(TransferSupport support) {
if(support.isDrop()) {
int index = ((STextComponent.DropLocation)support.getDropLocation()).getIndex();
((STextComponent)support.getComponent()).setCaretPosition(index);
((STextComponent)support.getComponent()).setSelectionStart(index);
((STextComponent)support.getComponent()).setSelectionEnd(index);
}
return super.importData(support);
}
@Override
public int getSourceActions(SComponent component) {
if(component instanceof SPasswordField) // don't allow drag/drop from password fields
return NONE;
if(!((STextComponent)component).isEditable()) // don't allow MOVE when the component isn't editable
return COPY;
return COPY_OR_MOVE;
}
}
}