package de.cmk.gui;
import javax.swing.text.*;
import java.awt.*;
import java.util.*;
public class LimitedInputDocument extends PlainDocument implements LimitedTextInputModes
{
private int charLimitMax = 0; // maximale Anzahl erlaubter Zeichen
private int limitMode = _ANYTHING; //
private String specials = new String();
private String forbiddenSpecials = new String();
private ArrayList editableAreas = new ArrayList();
public LimitedInputDocument()
{
}
public void setMode(int mode)
{
limitMode = mode;
if (limitMode < _ANYTHING || mode > _LETTERS_DIGITS_SPECIALS_ONLY)
{
throw new IllegalArgumentException("unbekannter Modus!");
}
}
public void setMaxChar(int maxChar)
{
charLimitMax = maxChar;
}
public void setSpecials(String allowedSpecials)
{
specials = allowedSpecials;
}
public void setForbiddenSpecials(String forbiddenSpecials)
{
this.forbiddenSpecials = forbiddenSpecials;
}
/**
* fügt eine editierbare Region in dem Textdokument ein
* wird gar keine jemals angegeben, ist das gesammt Dokument prinzipiell editierbar
* @param start int
* @param end int
* @throws BadLocationException
* @see boolean isInEditableArea(int offset)
*/
public void addEditableArea(int start, int end) throws BadLocationException
{
editableAreas.add(new Area(createPosition(start),createPosition(end)));
}
public void removeAllEditableAreas()
{// was mit den Positionen im Document passiert ist ungewiss
// müssten eigetnlich ungenutzt stehen bleiben
editableAreas.clear();
}
public void removeEditableArea(int start, int end)
{
for (int i=editableAreas.size()-1; i>=0; i--)
{
Area a = (Area)editableAreas.get(i);
if (a.start == start && a.end == end)
{
editableAreas.remove(i);
}
}
}
public void insertString(int offs,
String str,
AttributeSet a) throws BadLocationException
{
if (str == null)
{
str = "";
}
char[] source = str.toCharArray();
char[] result = new char[source.length];
int j = 0;
for (int i = 0; i < result.length; i++)
{
boolean charToBeIgnored = false;
switch (limitMode)
{
case _ANYTHING:
break;
case _SPECIALS_ONLY:
charToBeIgnored=!isSpecialChar(source[i]);
break;
case _LETTERS_ONLY:
charToBeIgnored=!Character.isLetter(source[i]);
break;
case _DIGITS_ONLY:
charToBeIgnored=!Character.isDigit(source[i]);
break;
case _LETTERS_SPECIALS_ONLY:
charToBeIgnored=!Character.isLetter(source[i])
&& !isSpecialChar(source[i]);
break;
case _DIGITS_SPECIALS_ONLY:
charToBeIgnored=!Character.isDigit(source[i])
&& !isSpecialChar(source[i]);
break;
case _LETTERS_DIGITS_SPECIALS_ONLY:
charToBeIgnored=!Character.isLetterOrDigit(source[i])
&& !isSpecialChar(source[i]);
break;
default: System.out.println("falscher Modus im Textfeld "+this.toString()+" durchgeflutscht");
}// end of switch(limitMode)
if (!charToBeIgnored &&
!isForbiddenChar(source[i]) &&
fitsInLength(j) &&
isInEditableArea(offs))
{
result[j++] = source[i];
}
else
{
Toolkit.getDefaultToolkit().beep();
}
}
super.insertString(offs, new String(result, 0, j), a);
}// end of insertString(int, String, AttributeSet)
public void remove(int offset, int len) throws BadLocationException
{
if (isFullEditable(offset, len))
{
super.remove(offset,len);
}
else
{
Toolkit.getDefaultToolkit().beep();
}
}
protected boolean isSpecialChar(char keyChar)
{
boolean charOk = false;
char [] sC = specials.toCharArray();
for(int i=0; !charOk && i<specials.length();i++)
{
if (keyChar==sC[i])
{
charOk=true;
}
}// end of for i
return charOk||specials.length()==0 ? true:false;
}// end of isSpecialChar(char)
protected boolean isInEditableArea(int offset)
{
boolean isInEditableArea = false;
if (editableAreas.size()>0)
{
for (int i = 0; i<editableAreas.size() && !isInEditableArea; i++)
{
Area a = (Area)editableAreas.get(i);
isInEditableArea = a.laysInArea(offset);
}
}
else
{
isInEditableArea = true;
}
return isInEditableArea;
}
/**
* Analysiert ob der Bereich editierbar ist, d.h. wenn
* editierbare Areale angegeben wurden wird geschaut, ob
* der durch die Parameter gegebene Bereich vollständig
* in diesen Arealen liegt. Sind keine editierbaren Areale angegeben
* wird davon ausgegangen, dass alles editierbar ist.
* @param offset Offset im Document als Start des Bereiches
* @param len Länge des Bereiches
* @return true : wenn der angegebene Bereich vollständig in ein oder mehere
* angegebene editierbare Bereich liegt, oder wenn kein
* Bereich angegeben wurde.
* false : wenn nicht der gesammte angegebene Bereich in editierbaren
* Bereichen liegt, falls editierbare Bereich angegeben sind
* @see addEditableArea (int, int)
* @see Area
*/
protected boolean isFullEditable(int offset, int len)
{
boolean isFullEditable = true;
if (editableAreas.size()>0)
{
boolean[] editables = new boolean[len];
for (int i = 0; i<editables.length; i++)
{
editables[i] = false;
}
boolean isFullIncluded = false;
for (int i = 0; i<editableAreas.size() && !isFullIncluded; i++)
{
Area a = (Area)editableAreas.get(i);
isFullIncluded = a.analyseInterception(offset, editables);
}
for (int i = 0; i<editables.length && isFullEditable; i++)
{
isFullEditable = editables[i];
}
}
return isFullEditable;
}
protected boolean fitsInLength(int addedCharCount)
{
return (charLimitMax<=0 || charLimitMax > addedCharCount+getLength());
}
protected boolean isForbiddenChar(char keyChar)
{
boolean charOk = false;
char [] sC = forbiddenSpecials.toCharArray();
for(int i=0; !charOk && i<forbiddenSpecials.length();i++)
{
if (keyChar==sC[i])
{
charOk=true;
}
}// end of for i
return charOk;
}// end of isSpecialChar(char)
private class Area
{
private Position startPos;
private Position endPos;
private int start;
private int end;
public Area(Position start, Position end)
{
this.startPos = start;
this.endPos = end;
this.start = start.getOffset();
this.end = end.getOffset();
}
public int getStart()
{
return startPos.getOffset();
}
public int getEnd()
{
return endPos.getOffset();
}
/**
*
* @param offset
* @param editables (boolean []) Elemente werden auf true gesetzt, wenn
* diese Stelle in der Area in Bezug auf offset
* eingeschlossen ist.
* @return true wenn gegebene Parameter vollständig in der Area liegen
* sonst false
*/
public boolean analyseInterception(int offset, boolean [] editables)
{
int end = getEnd();
int start = getStart();
int len =0;
if (start<offset)
{
for (int i=offset, x=0; i<end && x<editables.length; i++,x++)
{
editables[x]=true;
len++;
}
}
else if (start>offset)
{
for (int i=start, x = start-offset; i<end && x<editables.length; i++,x++)
{
editables[x]=true;
len++;
}
}
else // offsets sind identisch
{
for (int i = 0; i<end && i<editables.length; i++)
{
editables[i]=true;
len++;
}
}
return editables.length == len;
}// end of intercept(int, boolean[])
public boolean laysInArea(int p)
{
return startPos.getOffset()<p && p<=endPos.getOffset();
}
public boolean equals(Object o)
{
boolean rc = false;
if (o!=null)
{
if (o==this)
{
rc = true;
}
else if (o instanceof Area)
{
if (((Area)o).end==this.end && ((Area)o).start==this.start)
{
rc = true;
}
}
}
return rc;
}
}// end of class Area
}// end of class LimitedInputDocument