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.
package io.ultreia.java4all.jaxx.widgets.combobox;
/*-
* #%L
* JAXX :: Widgets
* %%
* Copyright (C) 2008 - 2024 Code Lutin, Ultreia.io
* %%
* 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 3 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%
*/
import io.ultreia.java4all.bean.JavaBean;
import io.ultreia.java4all.decoration.Decorator;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.nuiton.jaxx.runtime.swing.model.JaxxFilterableComboBoxModel;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.ComboBoxEditor;
import javax.swing.InputMap;
import javax.swing.JComboBox;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.text.JTextComponent;
import java.awt.Component;
import java.awt.FocusTraversalPolicy;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Objects;
/**
* Editor for the Combobox of the UI - uses the decorator
*/
public class JaxxComboBoxEditor implements ComboBoxEditor {
private static final Logger log = LogManager.getLogger(JaxxComboBoxEditor.class);
private final JaxxComboBox ui;
private final String logPrefix;
private final ComboBoxEditor wrapped;
private final JaxxComboBoxModel model;
private final JaxxFilterableComboBoxModel comboBoxModel;
private final JaxxComboBoxConfig config;
private final JComboBox combobox;
static class DocumentKeyListener extends KeyAdapter {
private final JComboBox combobox;
private final JTextComponent editorComponent;
private final JaxxComboBoxModel model;
private final JaxxFilterableComboBoxModel comboBoxModel;
private final boolean filterable;
private final String logPrefix;
Boolean doOpenPopup = null;
DocumentKeyListener(JaxxComboBox ui, JTextComponent editorComponent) {
this.combobox = ui.getCombobox();
this.logPrefix = ui.getName() + " →";
this.comboBoxModel = ui.getComboBoxModel();
this.model = ui.getModel();
this.editorComponent = editorComponent;
this.filterable = ui.getConfig().isFilterable();
}
@Override
public void keyTyped(KeyEvent e) {
doOpenPopup = false;
if (e.getKeyChar() == KeyEvent.VK_ENTER) {
doOpenPopup = true;
} else if (Character.isAlphabetic(e.getKeyChar()) || Character.isSpaceChar(e.getKeyChar())) {
doOpenPopup = true;
}
}
@Override
public void keyReleased(KeyEvent e) {
if (KeyEvent.VK_ESCAPE == e.getKeyCode()) {
log.debug(String.format("%s ESC , hide popup", logPrefix));
e.consume();
combobox.hidePopup();
return;
}
if (KeyEvent.VK_ENTER == e.getKeyCode()) {
if (combobox.isPopupVisible()) {
log.debug(String.format("%s Enter, hide popup ", logPrefix));
combobox.hidePopup();
e.consume();
return;
}
}
if (KeyEvent.VK_TAB == e.getKeyCode()) {
log.debug(String.format("%s Tab, consume event", logPrefix));
return;
}
if (e.isActionKey() || e.isControlDown() || e.isShiftDown() || e.isAltDown() || e.isAltGraphDown()) {
log.debug(String.format("%s Consume action key!!!!!", logPrefix));
e.consume();
return;
}
if (e.isConsumed()) {
log.debug(String.format("%s Already consumed key!!!!!", logPrefix));
return;
}
if (doOpenPopup != null && doOpenPopup && !combobox.isPopupVisible()) {
log.debug(String.format("%s Will show popup, key event: %s", logPrefix, e.paramString()));
combobox.showPopup();
doOpenPopup = null;
}
// if the typed text does not match the selected item,
// set the selected item to null
O selectedItem = model.getSelectedItem();
String text = editorComponent.getText();
//FIXME Use BeanDecoratorAware
String selectedItemString = comboBoxModel.decorateElement(selectedItem);
if (selectedItem != null && !selectedItemString.equals(text)) {
log.debug(String.format("%s Unselect previous selected item ('%s), since it does not match the text: '%s'", logPrefix, selectedItemString, text));
selectedItem = model.selectedItem = null;
model.mutateBeanProperty(null);
}
if (filterable && selectedItem == null) {
log.debug(String.format("%s filterText: %s, keyEvent: '%s'", logPrefix, text, e.paramString()));
String filterText = comboBoxModel.getFilterText();
if (!Objects.equals(text, filterText)) {
log.info(String.format("%s Apply filter: '%s'", logPrefix, text));
updateFilter(logPrefix, combobox, comboBoxModel, editorComponent, text, text);
// // push back text (it was removed by UI after updating filtered elements
// editorComponent.setText(text);
}
}
}
}
static void updateFilter(String logPrefix, JComboBox combobox, JaxxFilterableComboBoxModel comboBoxModel, JTextComponent editorComponent, String text, String finalText) {
// hide the popup before setting the filter, otherwise the popup height does not fit
boolean wasPopupVisible = combobox.isShowing() && combobox.isPopupVisible();
if (wasPopupVisible) {
log.debug(String.format("%s hide popup before update filter '%s'", logPrefix, text));
combobox.hidePopup();
}
log.debug(String.format("%s update filter '%s'", logPrefix, text));
comboBoxModel.setFilterText(text);
if (wasPopupVisible) {
log.warn(String.format("%s show back popup after update filter '%s'", logPrefix, text));
combobox.showPopup();
}
editorComponent.setText(finalText);
}
public JaxxComboBoxEditor(JaxxComboBox ui) {
this.ui = Objects.requireNonNull(ui);
this.logPrefix = ui.getName() + " →";
this.combobox = ui.getCombobox();
this.model = ui.getModel();
this.comboBoxModel = ui.getComboBoxModel();
this.config = model.getConfig();
Decorator decorator = Objects.requireNonNull(config.getDecorator());
this.wrapped = Objects.requireNonNull(ui.getCombobox().getEditor());
JTextComponent editorComponent = getEditorComponent();
InputMap inputMap = editorComponent.getInputMap();
ActionMap actionMap = editorComponent.getActionMap();
if (config.isTabToSelect()) {
editorComponent.setFocusTraversalKeysEnabled(false);
inputMap.put(KeyStroke.getKeyStroke("pressed TAB"), "focusNext");
actionMap.put("focusNext", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
log.debug(String.format("%s → focusNext", ui.getName()));
autoSelect();
combobox.hidePopup();
FocusTraversalPolicy focusTraversalPolicy = ui.getFocusCycleRootAncestor().getFocusTraversalPolicy();
Component focusComponent = focusTraversalPolicy.getComponentAfter(ui.getFocusCycleRootAncestor(), combobox.getEditor().getEditorComponent());
changeFocus(focusComponent);
}
});
inputMap.put(KeyStroke.getKeyStroke("shift pressed TAB"), "focusPrevious");
actionMap.put("focusPrevious", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
log.debug(String.format("%s → focusPrevious", ui.getName()));
autoSelect();
combobox.hidePopup();
FocusTraversalPolicy focusTraversalPolicy = ui.getFocusCycleRootAncestor().getFocusTraversalPolicy();
Component focusComponent = focusTraversalPolicy.getComponentBefore(ui.getFocusCycleRootAncestor(), combobox.getEditor().getEditorComponent());
changeFocus(focusComponent);
}
});
}
if (config.isEnterToSelectUniqueUniverse()) {
KeyStroke enterKeyStroke = KeyStroke.getKeyStroke("pressed ENTER");
Object oldEnterKey = inputMap.get(enterKeyStroke);
inputMap.put(enterKeyStroke, "enter");
Action oldEnterAction = actionMap.get(oldEnterKey);
actionMap.put("enter", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
log.debug(String.format("%s → enter pressed", ui.getName()));
if (autoSelect()) {
combobox.hidePopup();
return;
}
oldEnterAction.actionPerformed(e);
}
});
}
editorComponent.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (ui.isEnabled()) {
combobox.showPopup();
}
}
});
// if the typed text does not match the selected item,
// set the selected item to null
editorComponent.addKeyListener(new DocumentKeyListener<>(ui, editorComponent));
if (!config.isBeanDecoratorAware()) {
comboBoxModel.setDecorator(decorator);
// init combobox renderer base on given decorator
// combobox.setRenderer(new DecoratorListCellRenderer<>(decorator));
}
// Let's always act as in a cell (means selected value in popup is not selected for user, he must enter or click
// to set new selected item)
combobox.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);
// FIXME: Check why we use also this to set selected item in model
combobox.addItemListener(e -> {
Object item1 = e.getItem();
if (item1 instanceof String) {
// Side effect of lost focus in cell editor with no real selected value
return;
}
@SuppressWarnings("unchecked") O item = (O) e.getItem();
if (e.getStateChange() == ItemEvent.SELECTED) {
log.debug(String.format("itemStateChanged selected %s - %s", item, item != null ? item.getClass() : null));
editorComponent.setForeground(null);
model.setSelectedItem(item);
} else {
log.debug(String.format("itemStateChanged deselected %s - %s", item, item != null ? item.getClass() : null));
editorComponent.setForeground(config.getInvalidComboEditorTextColor());
}
});
}
private void changeFocus(Component focusComponent) {
if (focusComponent != null) {
log.debug(String.format("%s → Change focus to %s", ui.getName(), focusComponent));
SwingUtilities.invokeLater(focusComponent::requestFocusInWindow);
}
}
private boolean autoSelect() {
if (!combobox.isPopupVisible()) {
// if not editing any longer, then selected nothing
return false;
}
if (combobox.getItemCount() > 0) {
int selectedIndex = ui.getHandler().getSelectedIndex();
if (selectedIndex != -1) {
log.debug(String.format("%s → Auto-select with *TAB* or *Enter* key", ui.getName()));
combobox.setSelectedIndex(selectedIndex);
return true;
} else if (combobox.getItemCount() == 1) {
log.debug(String.format("%s → Auto-select unique result with *TAB* or *Enter* key", ui.getName()));
combobox.setSelectedIndex(0);
return true;
}
}
return false;
}
@Override
public JTextComponent getEditorComponent() {
return (JTextComponent) wrapped.getEditorComponent();
}
@Override
public Object getItem() {
return wrapped.getItem();
}
@Override
public void setItem(Object anObject) {
wrapped.setItem(anObject);
}
@Override
public void selectAll() {
wrapped.selectAll();
}
@Override
public void addActionListener(ActionListener l) {
wrapped.addActionListener(l);
}
@Override
public void removeActionListener(ActionListener l) {
wrapped.removeActionListener(l);
}
public void resetFilter(boolean force) {
JTextComponent editorComponent = getEditorComponent();
String text = editorComponent.getText();
log.info(String.format("%s → Remove filter text, selected value was set from text '%s'", ui.getName(), text));
updateFilter(logPrefix, combobox, comboBoxModel, editorComponent, "", force ? "" : text);
}
}