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

net.anwiba.commons.swing.object.AbstractObjectTextField Maven / Gradle / Ivy

There is a newer version: 1.2.50
Show newest version
/*
 * #%L
 * anwiba commons swing
 * %%
 * Copyright (C) 2007 - 2016 Andreas Bartels
 * %%
 * This program 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.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */
package net.anwiba.commons.swing.object;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Collection;

import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.ToolTipManager;
import javax.swing.border.Border;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.plaf.metal.MetalBorders;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.PlainDocument;

import net.anwiba.commons.lang.functional.IBlock;
import net.anwiba.commons.lang.functional.IConverter;
import net.anwiba.commons.logging.ILogger;
import net.anwiba.commons.logging.Logging;
import net.anwiba.commons.model.IChangeableObjectListener;
import net.anwiba.commons.model.IObjectDistributor;
import net.anwiba.commons.model.IObjectModel;
import net.anwiba.commons.swing.utilities.JTextComponentUtilities;
import net.anwiba.commons.utilities.validation.IValidationResult;
import net.anwiba.commons.utilities.validation.IValidator;

public abstract class AbstractObjectTextField implements IObjectTextField {

  static ILogger logger = Logging.getLogger(AbstractObjectTextField.class.getName());

  @SuppressWarnings("serial")
  public static final class TextField extends JTextField {
    private final IObjectFieldConfiguration configuration;
    private boolean isInititalized = false;
    private final IObjectDistributor validationResult;

    public TextField(
        final PlainDocument document,
        final IObjectFieldConfiguration configuration,
        final IObjectDistributor validationResult) {
      super(document, null, configuration.getColumns());
      this.validationResult = validationResult;
      this.isInititalized = true;
      this.configuration = configuration;
      final ToolTipManager toolTipManager = ToolTipManager.sharedInstance();
      if (configuration.getToolTipFactory() != null) {
        toolTipManager.registerComponent(this);
      }
    }

    @Override
    public void setBorder(final Border border) {
      super.setBorder(border);
    }

    @Override
    public void setDocument(final Document doc) {
      if (this.isInititalized) {
        throw new UnsupportedOperationException();
      }
      if (doc instanceof PlainDocument) {
        super.setDocument(doc);
        return;
      }
      throw new UnsupportedOperationException();
    }

    @Override
    public PlainDocument getDocument() {
      return (PlainDocument) super.getDocument();
    }

    @Override
    public void setToolTipText(final String text) {
      super.setToolTipText(text);
      final ToolTipManager toolTipManager = ToolTipManager.sharedInstance();
      if (text == null && this.configuration.getToolTipFactory() != null) {
        toolTipManager.registerComponent(this);
      }
    }

    @Override
    public String getToolTipText() {
      final IToolTipFactory toolTipFactory = this.configuration.getToolTipFactory();
      if (toolTipFactory == null) {
        return super.getToolTipText();
      }
      final String value = getText();
      final int columnWidth = getWidth();
      final double valueWidth = JTextComponentUtilities.getValueWidth(this, value);
      if (valueWidth > columnWidth - 2) {
        return toolTipFactory.create(this.validationResult.get(), value);
      }
      return toolTipFactory.create(this.validationResult.get(), null);
    }
  }

  private final IObjectModel model;
  private final IObjectModel validStateModel;
  private final TextField textField;
  private final JComponent component;
  private final IValidator validator;
  private final IConverter toObjectConverter;
  private final IConverter toStringConverter;
  private final IActionNotifier actionNotifier;
  private FieldValueController controller;

  public AbstractObjectTextField(final IObjectFieldConfiguration configuration) {
    this.model = configuration.getModel();
    this.validStateModel = configuration.getValidationResultModel();
    this.validator = configuration.getValidator();
    this.toObjectConverter = configuration.getToObjectConverter();
    this.toStringConverter = configuration.getToStringConverter();
    final PlainDocument document = new PlainDocument();
    final TextField field = new TextField<>(document, configuration, this.validStateModel);
    final IKeyListenerFactory keyListenerFactory = configuration.getKeyListenerFactory();
    if (keyListenerFactory != null) {
      field.addKeyListener(keyListenerFactory.create(this.model, document));
    }

    this.textField = field;
    final Collection> actionFactorys = configuration.getActionFactorys();
    if (configuration.getBackgroundColor() != null) {
      this.textField.setBackground(configuration.getBackgroundColor());
    }
    if (actionFactorys.isEmpty()) {
      this.component = field;
    } else {
      final Border border = new MetalBorders.TextFieldBorder();
      field.getBorder();
      this.component = new JPanel(new BorderLayout());
      this.component.setBackground(field.getBackground());
      this.component.setBorder(new MetalBorders.TextFieldBorder());
      field.setBorder(BorderFactory.createEmptyBorder());
      this.component.add(field, BorderLayout.CENTER);
      final JPanel actionContainer = new JPanel();
      actionContainer.setBackground(field.getBackground());
      actionContainer.setBorder(BorderFactory.createEmptyBorder());
      int width = 0;
      int height = 0;
      for (final IActionFactory actionFactory : actionFactorys) {
        final AbstractAction action = actionFactory.create(this.model, document, new IBlock() {

          @Override
          public void execute() throws RuntimeException {
            if (document.getLength() == 0) {
              return;
            }
            if (!AbstractObjectTextField.this.validStateModel.get().isValid()) {
              try {
                document.remove(0, document.getLength());
              } catch (final BadLocationException exception) {
                // nothing to do
              }
              return;
            }
            AbstractObjectTextField.this.model.set(null);
          }
        });
        final JButton buttom = new JButton(action);
        buttom.setBackground(field.getBackground());
        buttom.setBorder(BorderFactory.createEmptyBorder());
        width = width + buttom.getMinimumSize().width;
        height = Math.max(height, buttom.getMinimumSize().height);
        actionContainer.add(buttom);
      }
      actionContainer.setMinimumSize(new Dimension(width, height));
      actionContainer.setMaximumSize(new Dimension(width, height));
      this.component.add(actionContainer, BorderLayout.EAST);
      final Insets borderInsets = border.getBorderInsets(this.component);
      final int componentHeight = borderInsets.top + borderInsets.bottom + height;
      this.component.setMinimumSize(new Dimension(field.getMinimumSize().width + width, componentHeight));
      this.component.setPreferredSize(new Dimension(field.getPreferredSize().width + width, componentHeight + 10));
      this.component.setMaximumSize(new Dimension(Integer.MAX_VALUE, componentHeight + 10));
    }
    this.textField.setEditable(configuration.isEditable());
    this.actionNotifier = new IActionNotifier() {

      @Override
      public void removeActionListener(final ActionListener listener) {
        field.removeActionListener(listener);
      }

      @Override
      public void addActionListener(final ActionListener listener) {
        field.addActionListener(listener);
      }
    };

    final FieldValueController valuesController = new FieldValueController<>(
        document,
        this.model,
        () -> this.textField.isEditable(),
        this.toObjectConverter,
        this.toStringConverter,
        this.validStateModel,
        this.validator);
    this.controller = valuesController;
    document.addDocumentListener(new DocumentListener() {

      private void documentChanged() {
        valuesController.documentChanged();
      }

      @Override
      public void removeUpdate(final DocumentEvent e) {
        //        logger.log(ILevel.DEBUG, "document changed"); //$NON-NLS-1$
        documentChanged();
      }

      @Override
      public void insertUpdate(final DocumentEvent e) {
        //        logger.log(ILevel.DEBUG, "document changed"); //$NON-NLS-1$
        documentChanged();
      }

      @Override
      public void changedUpdate(final DocumentEvent e) {
        //        logger.log(ILevel.DEBUG, "document changed"); //$NON-NLS-1$
        documentChanged();
      }
    });
    this.model.addChangeListener(new IChangeableObjectListener() {

      @Override
      public void objectChanged() {
        //        logger.log(ILevel.DEBUG, "document changed"); //$NON-NLS-1$
        AbstractObjectTextField.this.controller.modelChanged();
      }
    });
    this.textField.addKeyListener(new KeyListener() {

      @Override
      public void keyTyped(final KeyEvent event) {
        if (event.getKeyChar() == 0x1b) {
          valuesController.modelChanged();
        }
      }

      @Override
      public void keyReleased(final KeyEvent event) {
        // nothing to do
      }

      @Override
      public void keyPressed(final KeyEvent event) {
        // nothing to do
      }
    });
    field.addFocusListener(new FocusListener() {

      @Override
      public void focusLost(final FocusEvent e) {
        valuesController.format();
      }

      @Override
      public void focusGained(final FocusEvent e) {
        // nothing to do
      }
    });
    valuesController.modelChanged();
    this.validStateModel.set(this.validator.validate(getText()));
  }

  @Override
  public IObjectModel getModel() {
    return this.model;
  }

  public void setHorizontalAlignment(final int alignment) {
    this.textField.setHorizontalAlignment(alignment);
  }

  @Override
  public JComponent getComponent() {
    return this.component;
  }

  @Override
  public IObjectDistributor getValidationResultDistributor() {
    return this.validStateModel;
  }

  @Override
  public void setEditable(final boolean isEditable) {
    this.textField.setEditable(isEditable);
  }

  @Override
  public void setText(final String text) {
    this.controller.setText(text);
  }

  @Override
  public String getText() {
    return this.controller.getText();
  }

  public IActionNotifier getActionNotifier() {
    return this.actionNotifier;
  }

  public void selectAll() {
    this.textField.selectAll();
  }

  public IColorReciever getColorReciever() {
    return new IColorReciever() {

      @Override
      public void setForeground(final Color color) {
        AbstractObjectTextField.this.textField.setForeground(color);
      }

      @Override
      public void setBackground(final Color color) {
        AbstractObjectTextField.this.textField.setBackground(color);
      }
    };
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy