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.
/*****************************************************************
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* https://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 org.apache.cayenne.modeler.util;
import org.apache.cayenne.map.DbAttribute;
import org.apache.cayenne.modeler.Application;
import org.apache.cayenne.modeler.util.combo.AutoCompletion;
import org.apache.cayenne.util.Util;
import javax.swing.AbstractCellEditor;
import javax.swing.BorderFactory;
import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.ImageIcon;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.ListCellRenderer;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.table.TableCellEditor;
import javax.swing.text.JTextComponent;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
/**
* This class used as cell editor, when you need to
* choose path in comboBox and use autocompletion.
*/
@SuppressWarnings("WeakerAccess")
public abstract class PathChooserComboBoxCellEditor extends AbstractCellEditor implements TableCellEditor, ActionListener, PopupMenuListener {
protected JComboBox comboBoxPathChooser;
protected int previousEmbeddedLevel = 0;
protected EntityTreeModel treeModel;
protected int row;
private JTable table;
protected abstract void enterPressed(JTable table);
protected abstract EntityTreeModel createTreeModelForComboBox(int indexInTable);
protected abstract Object getCurrentNodeToInitializeCombo(CayenneTableModel model, int row);
protected abstract String getPathToInitializeCombo(CayenneTableModel model, int row);
protected void initializeCombo(CayenneTableModel model, int row, final JTable table) {
Object currentNode = getCurrentNodeToInitializeCombo(model, row);
String dbAttributePath = getPathToInitializeCombo(model, row);
List nodeChildren = getChildren(currentNode, dbAttributePath);
this.table = table;
comboBoxPathChooser = Application.getWidgetFactory().createComboBox(
nodeChildren,
false);
comboBoxPathChooser.getEditor().getEditorComponent().addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent event) {
if (event.getKeyCode() == KeyEvent.VK_ENTER) {
enterPressed(table);
return;
}
parsePathString(event.getKeyChar());
}
});
AutoCompletion.enable(comboBoxPathChooser, true, true);
((JComponent) comboBoxPathChooser.getEditor().getEditorComponent()).setBorder(null);
comboBoxPathChooser.setBorder(BorderFactory.createEmptyBorder(0,5,0,0));
comboBoxPathChooser.setRenderer(new PathChooserComboBoxCellRenderer());
comboBoxPathChooser.addActionListener(this);
comboBoxPathChooser.addPopupMenuListener(this);
}
private void setComboModelAccordingToPath(String pathString) {
List currentNodeChildren = new ArrayList<>(getChildren(getCurrentNode(pathString), pathString));
comboBoxPathChooser.setModel(new DefaultComboBoxModel<>(currentNodeChildren.toArray(new String[0])));
comboBoxPathChooser.setSelectedItem(pathString);
if(!pathString.isEmpty()) {
comboBoxPathChooser.showPopup();
}
}
protected void parsePathString(char lastEnteredCharacter) {
JTextComponent editorComponent = (JTextComponent) (comboBoxPathChooser).getEditor().getEditorComponent();
String pathString = editorComponent.getText();
if (pathString != null && pathString.isEmpty()) {
setComboModelAccordingToPath("");
previousEmbeddedLevel = 0;
return;
}
if (lastEnteredCharacter == '.') {
processDotEntered();
previousEmbeddedLevel = Util.countMatches(pathString, ".");
return;
}
int currentEmbeddedLevel = Util.countMatches(pathString, ".");
if (previousEmbeddedLevel != currentEmbeddedLevel) {
previousEmbeddedLevel = currentEmbeddedLevel;
String[] pathStrings = pathString.split(Pattern.quote("."));
String lastStringInPath = pathStrings[pathStrings.length - 1];
String saveDbAttributePath = pathString;
pathString = pathString.replaceAll(lastStringInPath + "$", "");
List currentNodeChildren = new ArrayList<>(getChildren(getCurrentNode(pathString), pathString));
comboBoxPathChooser.setModel(new DefaultComboBoxModel<>(currentNodeChildren.toArray(new String[0])));
comboBoxPathChooser.setSelectedItem(saveDbAttributePath);
}
}
protected void processDotEntered() {
JTextComponent editorComponent = (JTextComponent) (comboBoxPathChooser).getEditor().getEditorComponent();
String dbAttributePath = editorComponent.getText();
if (".".equals(dbAttributePath)) {
setComboModelAccordingToPath("");
return;
}
char secondFromEndCharacter = dbAttributePath.charAt(dbAttributePath.length() - 2);
if (secondFromEndCharacter == '.') {
// two dots entered one by one , we replace it by one dot
editorComponent.setText(dbAttributePath.substring(0, dbAttributePath.length() - 1));
return;
}
String[] pathStrings = dbAttributePath.split(Pattern.quote("."));
String lastStringInPath = pathStrings[pathStrings.length - 1];
//we will check if lastStringInPath is correct name of DbAttribute or DbRelationship
//for appropriate previous node in path. if it is not we won't add entered dot to dbAttributePath
String dbAttributePathForPreviousNode;
if (pathStrings.length == 1) {
//previous root is treeModel.getRoot()
dbAttributePathForPreviousNode = "";
} else {
dbAttributePathForPreviousNode = dbAttributePath.replaceAll('.' + lastStringInPath + ".$", "");
}
List potentialVariantsToChoose = getChildren(getCurrentNode(dbAttributePathForPreviousNode), "");
if (potentialVariantsToChoose.contains(lastStringInPath) &&
!(getCurrentNode(dbAttributePath) instanceof DbAttribute)) {
setComboModelAccordingToPath(dbAttributePath);
} else {
editorComponent.setText(dbAttributePath.substring(0, dbAttributePath.length() - 1));
}
}
/**
* find current node by path
*
* @param pathString db path
* @return last node in path which matches DbRelationship or DbAttribute
*/
protected Object getCurrentNode(String pathString) {
//case for new attribute
if (pathString == null || pathString.isEmpty()) {
return treeModel.getRoot();
}
String[] pathStrings = pathString.split(Pattern.quote("."));
Object root = treeModel.getRoot();
for (String rootChildText : pathStrings) {
for (int j = 0; j < treeModel.getChildCount(root); j++) {
Object child = treeModel.getChild(root, j);
String objectName = ModelerUtil.getObjectName(child);
if (objectName.equals(rootChildText)) {
root = child;
break;
}
}
}
return root;
}
/**
* @param node for which we will find children
* @param pathString string which will be added to each child to make right autocomplete
* @return list with children , which will be used to autocomplete
*/
protected List getChildren(Object node, String pathString) {
List currentNodeChildren = new ArrayList<>();
for (int j = 0; j < treeModel.getChildCount(node); j++) {
Object child = treeModel.getChild(node, j);
String relationshipName = ModelerUtil.getObjectName(child);
currentNodeChildren.add(pathString + relationshipName);
}
return currentNodeChildren;
}
@Override
public void actionPerformed(ActionEvent e) {
//for some reason comboBoxPathChooser don't load selected item text, so we made it by hand
if (comboBoxPathChooser.getSelectedIndex() != (-1)) {
((JTextComponent) (comboBoxPathChooser).
getEditor().getEditorComponent()).setText(comboBoxPathChooser.getSelectedItem().toString());
}
}
@Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
if (comboBoxPathChooser.getSelectedIndex() != -1 &&
!((JTextComponent) (comboBoxPathChooser).
getEditor().getEditorComponent()).getText().isEmpty()) {
enterPressed(table);
}
}
@Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
}
@Override
public void popupMenuCanceled(PopupMenuEvent e) {
}
private final class PathChooserComboBoxCellRenderer extends DefaultListCellRenderer {
private final ImageIcon rightArrow = ModelerUtil.buildIcon("icon-arrow-closed.png");
@SuppressWarnings("unchecked")
@Override
public Component getListCellRendererComponent(JList> list, Object value, int index,
boolean isSelected, boolean cellHasFocus) {
JPanel panel = new JPanel(new BorderLayout());
JLabel label = new JLabel((String) value);
panel.add(label);
Object currentNode = getCurrentNode((String) value);
if (treeModel.isLeaf(currentNode)) {
ListCellRenderer leafRenderer = CellRenderers.listRenderer();
return leafRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
} else {
DefaultListCellRenderer nonLeafTextRenderer = new DefaultListCellRenderer();
Component text = nonLeafTextRenderer.getListCellRendererComponent(list, value, index, isSelected,
cellHasFocus);
panel.setBackground(text.getBackground());
panel.add(new JLabel(rightArrow), BorderLayout.EAST);
return panel;
}
}
}
}