PlainDocument com regex

Ola!

Estou fazendo uma GUI aqui na qual a vários JTextField onde cada um tem uma particularidade especifica por exemplo, um de data, outro para números decimais, outro para inteiros, outro para e-mail entre outros. Então pensei em fazer um PlainDocument para cada caso, mas tive a ideia de ter apenas um PlainDocument que trabalhasse com expressão regular, mas fazendo uma busca na internet não encontrei essa implementação.

então estou postando aqui no GUJ para tentar colher ideias de como fazer essa implementação, que creio eu que seria de grande utilidade para todos!

qualquer dica é bem vinda!

Consegui fazer um que funcione! mas ainda tem alguns problemas:
[list]não esta tendo o comportamento adequado ao inserir uma String com vários caracteres (ao colar, por exemplo)[/list][list]não esta funcionando em expressões regulares que exijam ser inseridos um carácter ("[0-9]:[0-9]", por exemplo), pois ele impede que se apague esse caractere[/list]
ainda não esta 100% depurado (fiz pouquíssimos testes), então possivelmente ira aparecer centenas de erros!

Seque como esta a implementação:

[code]public class RegexPlainDocument extends PlainDocument {
private String regex;

public RegexPlainDocument(String regex, String def) {

	if (!def.matches(regex))
		throw new IllegalArgumentException(
				"o segundo argumento não é valido para a regex");
	this.regex = regex;
	try {
		super.insertString(0, def, null);
	} catch (BadLocationException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
}

@Override
public void insertString(int offs, String str, AttributeSet a)
		throws BadLocationException {

	char[] crs = str.toCharArray();
	String envio = "";
	for (int i = 0; i < crs.length; i++) {
		String temp = getText(0, offs) + envio + crs[i]
				+ getText(offs, getLength() - offs);
		System.out.println(temp);
		if (temp.matches(regex)) {
			envio += crs[i];
		} else {
			Toolkit.getDefaultToolkit().beep();
		}

	}
	super.insertString(offs, envio, a);
}

@Override
public void remove(int offs, int len) throws BadLocationException {
	for (int i = 0; i < len; i++) {
		String temp = getText(0, offs)
				+ getText(offs + 1, getLength() - (offs + 1));
		System.out.println(temp);

		if (temp.matches(regex)) {
			super.remove(offs, 1);
		} else {
			offs++;
			Toolkit.getDefaultToolkit().beep();
		}
	}

}

}[/code]

Sinta-se avoante para modificar!
Até!

Ao criar uma classe derivada de PlainDocument, não se esqueça de redefinir também o método replace():

http://download.oracle.com/javase/6/docs/api/javax/swing/text/AbstractDocument.html#replace(int, int, java.lang.String, javax.swing.text.AttributeSet)

Bem lembrado roger_rf, nunca dei muita importância para esse método pois na maioria dos casos o remover e inserir já davam o resultado esperado, mas nesse caso foi de grande ajuda, com ele as expressões do tipo “[0-9]:[0-9]” passaram a funcionar (ainda é incomodo ter que selecionar a parte que se quer mudar, mas pelo menos agora funciona) e o resultado passou a ser bem melhor com o Ctrl+v

Abaixo vai como ficou a implementação do replace

[code] public void replace(int offset, int length, String text, AttributeSet attrs)
throws BadLocationException {
String temp = getText(0, offset) + text
+ getText(offset + length, getLength() - (offset + length));

	if (temp.matches(regex)) {
		super.remove(offset, length);
		super.insertString(offset, text, attrs);
	} else {
		Toolkit.getDefaultToolkit().beep();
	}
}[/code]

Estou pensando em fazer algo como um insert, mas não tenho ideia de como implementar!
vou dar uma pesquisada se achar volto a postar!

até!

Tenho uma dúvida :

No caso de inserir texto ta ocorrendo tudo certo, o problema é quando eu do um “Ctrl + X” la no JTextField e ele não entra no evento (creio que obviamente pelo nome ser “insertString” )

Minha dúvida é, como fazer detectar quando ele apaga todo o conteudo do JTextField

O problema de se usar uma expressão regular para um plain document é que ela deve lidar com o fato de uma expressão incompleta.

O único caso em que ela é realmente útil é quando a expressão regular é algo como “zero ou mais ocorrências de um conjunto de caracteres” - exemplo: [A-Za-z0-9]*

Quando você tem algo estruturado, um plain document com expressão regular começa a ter problemas.

Como exemplo, digamos que você tivesse uma expressão regular que batesse com um CPF com separadores:

\d{3}.\d{3}.\d{3}-\d{2}

Enquanto você vai digitando o CPF, a expressão regular que mostrei acima simplesmente não bate com um CPF “incompleto”. Só quando você concluiu a digitação do CPF é que ela fica OK.

Resolvido minha dúvida anterior para futuras pesquisas:

http://www.guj.com.br/java/275775-duvida-plaindocument#1450463

vou dar uma pesquisada se achar volto a postar!

Ola vou te mostrar como utilizo o plain documente

Tenho está classe que verifica a quantidade de dados digitados

Observe que estou herdando PlainDocument

[code]
public class FixedLengthDocument extends PlainDocument
{
private int maxLength;

public FixedLengthDocument(int maxlen) { // Determino a quantidade de informações poderão ser digitadas 
    super();  
      
    if (maxlen <= 0)  
        throw new IllegalArgumentException("You must specify a maximum length!");  
      
    maxLength = maxlen;  
}  

@Override  
public void insertString(int offset, String str, AttributeSet attr)   
throws BadLocationException {  
    if (str == null || getLength() == maxLength)  
        return;  

    int totalLen = (getLength() + str.length());  
    if (totalLen <= maxLength) {  
        super.insertString(offset, str, attr);  
        return;  
    }  
      
    String newStr = str.substring(0, (maxLength - getLength()));  
    super.insertString(offset, newStr, attr);  
}  

}

[/code]Aqui está a jogada somente com está classe não terá que se preocupar mais em testar os dados

observe que estou agora herdando a classe FixedLengthDocument que herda a classe Plain
você com isso tem a possibilidade de validar para aceitar somente numeros inteiro como tambem permitir somente uma quantidade de dados



public class IntegerDocument extends FixedLengthDocument{
	public IntegerDocument(int maxlen) {  
        super(maxlen);  
    }  
  
    @Override  
    public void insertString(int offset, String str, AttributeSet attr)  
            throws BadLocationException {  
        if (str == null)  
            return;  
          
        try {  
            Integer.parseInt(str);  
        } catch (Exception e) {  
            return;  
        }  
          
        super.insertString(offset, str, attr);  
    }  

}

para validar os dados é so
seuTXFIELD.setDocument(new IntegerDocument(10))