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

com.viaoa.jfc.control.TextFieldController Maven / Gradle / Ivy

/*  Copyright 1999-2015 Vince Via [email protected]
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/
package com.viaoa.jfc.control;

import java.awt.Component;
import java.awt.event.*;

import javax.swing.*;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;
import javax.swing.text.DocumentFilter.FilterBypass;

import java.lang.reflect.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;

import com.viaoa.object.*;
import com.viaoa.hub.*;
import com.viaoa.jfc.undo.*;
import com.viaoa.util.*;
import com.viaoa.ds.*;
import com.viaoa.jfc.*;

/**
 * Controller for binding OA to JTextField.
 * @author vvia
 *
 */
public class TextFieldController extends JFCController implements FocusListener, ActionListener, KeyListener, MouseListener {
    private static Logger LOG = Logger.getLogger(TextFieldController.class.getName());
    protected JTextField textField;
    protected volatile String prevText;
    private final AtomicInteger aiSettingText = new AtomicInteger();
    private Object activeObject;
    private Object focusActiveObject;
    //private int dataSourceMax=-2;
    //20151002 moved to jfccontroller private int propertyInfoMax=-2;
    private int max=-1;
    private OAPlainDocument document;
    
    /**
     * 'U'ppercase, 
     * 'L'owercase, 
     * 'T'itle, 
     * 'J'ava identifier
     * 'E'ncrpted password/encrypt
     * 'S'HA password
     */
    protected char conversion;
    
    /**
        Create an unbound TextField.
    */
    public TextFieldController(JTextField tf) {
        create(tf);
    }

    /**
        Create TextField that is bound to a property path in a Hub.
        @param propertyPath path from Hub, used to find bound property.
    */
    public TextFieldController(Hub hub, JTextField tf, String propertyPath) {
        super(hub, propertyPath, tf); // this will add hub listener
        create(tf);
    }

    /**
        Create TextField that is bound to a property path in a Hub.
        @param propertyPath path from Hub, used to find bound property.
    */
    public TextFieldController(Object object, JTextField tf, String propertyPath) {
        super(object, propertyPath, tf); // this will add hub listener
        create(tf);
    }

    
    
    
    protected void create(JTextField tf) {
        if (textField != null) {
            textField.removeFocusListener(this);
            textField.removeKeyListener(this);
            textField.removeActionListener(this);
            textField.removeMouseListener(this);
        }
        textField = tf;
        if (actualHub == null) return; 
        
        Class c = OAReflect.getClass(getLastMethod());
        if (OAReflect.isNumber(c)) {
            textField.setHorizontalAlignment(JTextField.RIGHT);
        }
        else {
            textField.setHorizontalAlignment(JTextField.LEFT);
        }

        if (textField != null) {
            textField.addFocusListener(this);
            textField.addKeyListener(this);
            textField.addActionListener(this);
            textField.addMouseListener(this);
        }
        // set initial value of textField
        // this needs to run before listeners are added
        if (getActualHub() != null) {
            HubEvent e = new HubEvent(getActualHub(),getActualHub().getActiveObject());
            this.afterChangeActiveObject(e);
            getEnabledController().add(getActualHub());
        }
        else {
            aiSettingText.incrementAndGet();
            if (document != null) document.setAllowAll(true);
            if (tf != null) {
                if (tf instanceof OATextField) ((OATextField)tf).setText("", false);
                else tf.setText("");
            }
            if (document != null) document.setAllowAll(false);
            aiSettingText.decrementAndGet();
        }

        document = new OAPlainDocument() {
            public void handleError(int errorType) {
            	super.handleError(errorType);
            	if (!TextFieldController.this.textField.hasFocus()) return;
            	String msg = "";
            	switch (errorType) {
            	case OAPlainDocument.ERROR_MAX_LENGTH:
            	    //int max = getDataSourceMaxColumns();
            	    //if (max <= 0) { 
            	        int max = getMaximumColumns();
            	        if (max <= 0) max = getPropertyInfoMaxColumns();
            	    //}
            	    
            		msg = "Maximum input exceeded, currently set to " + max;

            		if (textField instanceof OATextField) {
            		    msg += " for " + ((OATextField)textField).getPropertyPath();
            		    Hub h = ((OATextField)textField).getHub();
            		    if (h != null) msg += ", in "+OAString.getDisplayName(h.getObjectClass().getSimpleName());
            		}
            		
            		break;
            	case OAPlainDocument.ERROR_INVALID_CHAR:
            		return;
            	}
            	if (!OAString.isEmpty(msg)) LOG.warning(msg);
                if (textField != null && textField.hasFocus()) {
                    JOptionPane.showMessageDialog(SwingUtilities.getWindowAncestor(TextFieldController.this.textField), msg, "Error", JOptionPane.ERROR_MESSAGE);
                }
            }
            @Override
            public void insertString(int offset, String str, AttributeSet attr)
                    throws BadLocationException {
                super.insertString(offset, str, attr);
            }
            @Override
            protected void insertUpdate(DefaultDocumentEvent chng,
                    AttributeSet attr) {
                super.insertUpdate(chng, attr);
            }
        };
        
        int max = getPropertyInfoMaxColumns();
        // if (max <= 0) max = getDataSourceMaxColumns();  //qqqqqqqqqqqqq use getOAColumn max instead 
        
        if (max > 0) document.setMaxLength(max);
        textField.setDocument(document);
        
        c = OAReflect.getClass(getLastMethod());
        if (OAReflect.isNumber(c)) {
            
            final boolean bFloat = !OAReflect.isInteger(c);
            if (bFloat) {
                document.setValidChars("0123456789-. ");
            }
            else {
                document.setValidChars("0123456789- ");
            }

            
            // 20121101
            document.setDocumentFilter(new DocumentFilter() {
                @Override
                public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException {
                    String s = "";
                    for (int i=0; i 0) fb.insertString(offset, s, attr);
                }
                @Override
                public void remove(FilterBypass fb, int offset, int length) throws BadLocationException {
                    super.remove(fb, offset, length);
                }
                @Override
                public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
                    String s = "";
                    for (int i=0; i 0) return;
        if (bSaving) return;
        try {
            bSaving = true;
            _saveText();
        }
        finally {
            bSaving = false;
        }
    }

    private void _saveText() {
        /* 20101121  not valid when used in table, and arrow key to next column is used
        // 2006/06/14 bug with password always failing this while being used for a table
        if (!textField.isValid()) {
    	   if (!(textField instanceof OAPasswordField)) return;
        }
        */
        
        if (activeObject == null) return;
        String text = textField.getText();

        if (text.equals(prevText)) return;
        
        if (text != null && conversion != 0) {
            String hold = text;
            
            if (conversion == 'U' || conversion == 'u') {
                text = text.toUpperCase();
            }
            else if (conversion == 'L' || conversion == 'l') {
                text = text.toLowerCase();
            }
            else if (conversion == 'T' || conversion == 't') {
                if (text.toLowerCase().equals(text) || text.toUpperCase().equals(text)) {
                    text = OAString.toTitleCase(text);
                }
            }
            else if (conversion == 'J' || conversion == 'j') {
                text = OAString.makeJavaIndentifier(text);
            }
            else if (conversion == 'S' || conversion == 's') {
                text = OAString.getSHAHash(text);
            }
            else if (conversion == 'P' || conversion == 'p') {
                text = OAString.getSHAHash(text);
            }
            else if (conversion == 'E' || conversion == 'e') {
                try {
                    text = OAEncryption.encrypt(text);
                }
                catch (Exception e) {
                    throw new RuntimeException("encryption failed", e);
                }
            }

            if (text.equals(prevText)) return;
            if (hold != text) textField.setText(text);
        }
        
        try {
            Object convertedValue = getConvertedValue(text, null); // dont include format - it is for display only
            // Object convertedValue = OAReflect.convertParameterFromString(getSetMethod(), text, null); // dont include format - it is for display only
            
            if (convertedValue == null && text.length() > 0) {
                JOptionPane.showMessageDialog(SwingUtilities.getRoot(textField), 
                        "Invalid Entry \""+text+"\"", 
                        "Invalid Entry", JOptionPane.ERROR_MESSAGE);
                return;
            }
            
            String msg = null;
            OAEditMessage em = new OAEditMessage();
            boolean b = isValid(activeObject, convertedValue, em);
            if (!b) {
                msg = em.getMessage();
                if (msg == null) msg = "";
                if (em.getThrowable() != null) {
                    if (msg.length() > 0) msg += "\nError: ";
                    msg += em.getThrowable().toString();
                }
            }
            
            if (msg != null) {
                JOptionPane.showMessageDialog(SwingUtilities.getRoot(textField), 
                        "Invalid Entry \""+text+"\"\n"+msg,
                        "Invalid Entry", JOptionPane.ERROR_MESSAGE);
                return;
            }

            prevText = text;
            Object prevValue = getPropertyPathValue(activeObject);
            
            String prop = getHubListenerPropertyName();
            if (prop == null || prop.length() == 0) {  // use object.  (ex: String.class)
                Object oldObj = activeObject;
                Hub h = getActualHub();
                Object newObj = OAReflect.convertParameterFromString(h.getObjectClass(), text);
                if (newObj != null) {
                    int posx = h.getPos(oldObj);
                    h.remove(posx);
                    h.insert(newObj, posx);
                }
            }
            else {
                setPropertyPathValue(activeObject, convertedValue);
                // OAReflect.setPropertyValue(activeObject, getSetMethod(), convertedValue);
                if (text == null || text.length() == 0) {
                    Class c = getLastMethod().getReturnType();
                    if (OAReflect.isNumber(c) && activeObject instanceof OAObject) {
                    	OAObjectReflectDelegate.setProperty((OAObject)activeObject, getHubListenerPropertyName(), null, null);  // was: setNull(prop)
                    }
                }
            }
            if (getEnableUndo()) {
                OAUndoableEdit ue = OAUndoableEdit.createUndoablePropertyChange(undoDescription, activeObject, getPropertyPathFromActualHub(), prevValue, getPropertyPathValue(activeObject) );
                OAUndoManager.add(ue);
            }
        }
        catch (Throwable t) {
            System.out.println("Error in TextFieldController, "+t);
            t.printStackTrace();
            String msg = t.getMessage();
            for (;;) {
                t = t.getCause();
                if (t == null) break;
                msg = t.getMessage();
            }
            
            
        	JOptionPane.showMessageDialog(SwingUtilities.getRoot(textField), 
        	        "Invalid Entry \""+msg+"\"", 
        	        "Invalid Entry", JOptionPane.ERROR_MESSAGE);
        }
    }

    private String undoDescription;
    /**
        Description to use for Undo and Redo presentation names.
        @see OAUndoableEdit#setPresentationName
    */
    public void setUndoDescription(String s) {
        undoDescription = s;
    }
    /**
        Description to use for Undo and Redo presentation names.
        @see OAUndoableEdit#setPresentationName
    */
    public String getUndoDescription() {
        return undoDescription;
    }
    

    // Key Events
    private boolean bConsumeEsc;
    @Override
    public void keyPressed(KeyEvent e) {
    	if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
        	bConsumeEsc = false;
            if (!textField.getText().equals(prevText)) {
        		bConsumeEsc = true;
            	e.consume();
	    		textField.setText(prevText);
            }
        	textField.selectAll();
    	}
    }
    
    @Override
    public void keyReleased(KeyEvent e) {
    	if (e.getKeyCode() == KeyEvent.VK_ESCAPE && bConsumeEsc) {
            e.consume();
    	}
    }
    @Override
    public void keyTyped(KeyEvent e) {
    	if (e.getKeyCode() == KeyEvent.VK_ESCAPE && bConsumeEsc) {
            e.consume();
            return;
    	}
    }

    
    private boolean bMousePressed;
    @Override
    public void mouseClicked(MouseEvent e) {
    	//bMousePressed = true;
    }
    @Override
    public void mouseEntered(MouseEvent e) {
    }
    @Override
    public void mouseExited(MouseEvent e) {
    	bMousePressed = false;
    }
    @Override
    public void mousePressed(MouseEvent e) {
    	bMousePressed = true;
    }
    @Override
    public void mouseReleased(MouseEvent e) {
    	bMousePressed = false;
    }
    
    private boolean bAllowChangesWhileFocused;
    public void setAllowChangesWhileFocused() {
        // set by OAComboBox.setEditor(OATextField) so that user can select combo item while textField is focused
        bAllowChangesWhileFocused = true;
    }
    
    @Override
    protected void update() {
        if (textField == null) return;
        if (focusActiveObject == null || bAllowChangesWhileFocused) {
            if (getActualHub() != null) {
                String text = null;
                if (activeObject != null) {
                    Object value = getPropertyValue(activeObject);
                    if (value == null) text = "";
                    else text = OAConv.toString(value, getFormat());
                }
                if (text == null) {
                    text = getNullDescription();
                    if (text == null) text = " ";
                }
                aiSettingText.incrementAndGet();
                try {
                    // 20110605 see if select all is currently done
                    int p1 = textField.getSelectionStart();
                    int p2 = textField.getSelectionEnd();
                    boolean b = p1 == 0 && text != null && p2 == text.length(); 
                    
                    textField.setText(text);
                    prevText = text; // 20110112 to fix bug found while testing undo
                    
                    if (b) {
                        textField.selectAll();
                    }
                }
                finally {
                    aiSettingText.decrementAndGet();
                }
            }   
        }        
        super.update();
        super.update(textField, activeObject);
    }
    
    protected Object getPropertyValue(Object obj) {
        if (obj == null) return null;
        if (getPropertyPath() == null) return null;
        Object value = getPropertyPathValue(obj);
        if (value instanceof OANullObject) value = null;
        
        if (value != null && obj instanceof OAObject) {
            if (isPropertyPathValueNull(obj)) value = null;
            //was: String ss = getPropertyName();
            //was: if (OAObjectReflectDelegate.getPrimitiveNull((OAObject)obj, ss) ) value = null;
        }
        
        return value;
    }
    
    public Component getTableRenderer(JLabel label, JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        super.getTableRenderer(label, table, value, isSelected, hasFocus, row, column);
        return label;
    }
    
}







© 2015 - 2025 Weber Informatics LLC | Privacy Policy