You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by sk...@apache.org on 2015/12/07 16:31:44 UTC
[5/8] cayenne git commit: cleanup
http://git-wip-us.apache.org/repos/asf/cayenne/blob/b444b1df/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/PathChooserComboBoxCellEditor.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/PathChooserComboBoxCellEditor.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/PathChooserComboBoxCellEditor.java
new file mode 100644
index 0000000..ae4a639
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/PathChooserComboBoxCellEditor.java
@@ -0,0 +1,192 @@
+/*****************************************************************
+ * 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
+ *
+ * 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 org.apache.cayenne.modeler.util;
+
+import org.apache.cayenne.modeler.Application;
+import org.apache.cayenne.modeler.util.combo.AutoCompletion;
+import org.apache.commons.lang.StringUtils;
+
+import javax.swing.AbstractCellEditor;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JComboBox;
+import javax.swing.JTable;
+import javax.swing.table.TableCellEditor;
+import javax.swing.text.JTextComponent;
+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.
+ */
+public abstract class PathChooserComboBoxCellEditor extends AbstractCellEditor implements TableCellEditor {
+
+ protected JComboBox comboBoxPathChooser;
+ protected int previousEmbeddedLevel = 0;
+ protected EntityTreeModel treeModel;
+ protected int row;
+
+ 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<String> nodeChildren = getChildren(currentNode, dbAttributePath);
+ 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, false, true);
+ }
+
+ private void setComboModelAccordingToPath(String pathString) {
+ List<String> currentNodeChildren = new ArrayList<>();
+ currentNodeChildren.add(pathString);
+ currentNodeChildren.addAll(getChildren(getCurrentNode(pathString), pathString));
+ comboBoxPathChooser.setModel(new DefaultComboBoxModel(currentNodeChildren.toArray()));
+ comboBoxPathChooser.showPopup();
+ comboBoxPathChooser.setPopupVisible(true);
+ }
+
+ protected void parsePathString(char lastEnteredCharacter) {
+ JTextComponent editorComponent = (JTextComponent) (comboBoxPathChooser).getEditor().getEditorComponent();
+
+ String pathString = editorComponent.getText();
+ if (pathString != null && pathString.isEmpty()) {
+ setComboModelAccordingToPath("");
+ previousEmbeddedLevel = StringUtils.countMatches(pathString, ".");
+ return;
+ }
+
+ if (lastEnteredCharacter == '.') {
+ processDotEntered();
+ previousEmbeddedLevel = StringUtils.countMatches(pathString, ".");
+ return;
+ }
+
+ int currentEmbeddedLevel = StringUtils.countMatches(pathString, ".");
+ if (previousEmbeddedLevel != currentEmbeddedLevel) {
+ previousEmbeddedLevel = currentEmbeddedLevel;
+ List<String> currentNodeChildren = new ArrayList<>();
+ String[] pathStrings = pathString.split(Pattern.quote("."));
+ String lastStringInPath = pathStrings[pathStrings.length - 1];
+ String saveDbAttributePath = pathString;
+ pathString = pathString.replaceAll(lastStringInPath + "$", "");
+ currentNodeChildren.addAll(getChildren(getCurrentNode(pathString), pathString));
+ comboBoxPathChooser.setModel(new DefaultComboBoxModel(currentNodeChildren.toArray()));
+ editorComponent.setText(saveDbAttributePath);
+ return;
+ }
+ }
+
+ private 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.replace('.' + lastStringInPath, "");
+ }
+ List<String> potentialVariantsToChoose = getChildren(getCurrentNode(dbAttributePathForPreviousNode), "");
+ if (potentialVariantsToChoose.contains(lastStringInPath)) {
+ setComboModelAccordingToPath(dbAttributePath);
+ } else {
+ editorComponent.setText(dbAttributePath.substring(0, dbAttributePath.length() - 1));
+ }
+ previousEmbeddedLevel = StringUtils.countMatches(dbAttributePath, ".");
+ }
+
+ /**
+ * find current node by dbAttributePath
+ *
+ * @param pathString
+ * @return last node in dbAttributePath 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<String> getChildren(Object node, String pathString) {
+ List<String> 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;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/b444b1df/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/ProjectUtil.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/ProjectUtil.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/ProjectUtil.java
index 20aaf3d..fc7735d 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/ProjectUtil.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/ProjectUtil.java
@@ -19,11 +19,6 @@
package org.apache.cayenne.modeler.util;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
import org.apache.cayenne.configuration.DataChannelDescriptor;
import org.apache.cayenne.configuration.DataNodeDescriptor;
import org.apache.cayenne.map.Attribute;
@@ -48,6 +43,11 @@ import org.apache.cayenne.query.EJBQLQuery;
import org.apache.cayenne.query.Query;
import org.apache.cayenne.util.Util;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
/**
* Provides utility methods to perform various manipulations with project objects.
*/
@@ -198,7 +198,7 @@ public class ProjectUtil {
}
}
-
+
/**
* Changes the name of the embeddable attribute and all references to this embeddable attribute.
*/
@@ -207,7 +207,7 @@ public class ProjectUtil {
attribute.setName(newName);
Embeddable embeddable = attribute.getEmbeddable();
-
+
if (embeddable != null) {
embeddable.removeAttribute(oldName);
embeddable.addAttribute(attribute);
@@ -245,46 +245,15 @@ public class ProjectUtil {
for (ObjAttribute att : entity.getAttributes()) {
// If flattenet atribute
- if (att.getDbAttributePath() != null
- && att.getDbAttributePath().contains(".")) {
- String[] pathSplit = att.getDbAttributePath().split("\\.");
+ String dbAttributePath = att.getDbAttributePath();
+ if (dbAttributePath != null
+ && dbAttributePath.contains(".")) {
+ String[] pathSplit = dbAttributePath.split("\\.");
// If flattened attribute
if (pathSplit.length > 1) {
- DbEntity currentEnt = dbEnt;
- StringBuilder pathBuf = new StringBuilder();
- boolean isTruePath = true;
-
- if (currentEnt != null) {
-
- for (int j = 0; j < pathSplit.length; j++) {
-
- if (j == pathSplit.length - 1 && isTruePath) {
- DbAttribute dbAttribute = (DbAttribute) currentEnt
- .getAttribute(pathSplit[j]);
- if (dbAttribute != null) {
- pathBuf.append(dbAttribute.getName());
- }
- else {
- isTruePath = false;
- }
- }
- else if (isTruePath) {
- DbRelationship dbRelationship = (DbRelationship) currentEnt
- .getRelationship(pathSplit[j]);
- if (dbRelationship != null) {
- currentEnt = (DbEntity) dbRelationship
- .getTargetEntity();
- pathBuf.append(dbRelationship.getName());
- pathBuf.append(".");
- }
- else {
- isTruePath = false;
- }
- }
- }
- }
+ boolean isTruePath = isDbAttributePathCorrect(dbEnt, dbAttributePath);
if (!isTruePath) {
att.setDbAttributePath(null);
@@ -319,6 +288,34 @@ public class ProjectUtil {
}
/**
+ * check if path is correct. path is correct when he consist from <code>DbRelationship</code>
+ * objects, each <code>DbRelationship</code> object have following <code>DbRelationship</code>
+ * object as a target, last component is <code>DbAttribute</code>
+ *
+ * @param currentEnt current db entity
+ * @param dbAttributePath path to check
+ * @return if path is correct return true
+ */
+ public static boolean isDbAttributePathCorrect(DbEntity currentEnt, String dbAttributePath) {
+ if (currentEnt == null) {
+ return true;
+ }
+
+ String[] pathSplit = dbAttributePath.split("\\.");
+
+ int size = pathSplit.length - 1;
+ for (int j = 0; j < size; j++) {
+ DbRelationship relationship = currentEnt.getRelationship(pathSplit[j]);
+ if (relationship == null) {
+ return false;
+ }
+ currentEnt = relationship.getTargetEntity();
+ }
+
+ return currentEnt.getAttribute(pathSplit[(size)]) != null;
+ }
+
+ /**
* Clears all the mapping between this obj entity and its current db entity. Clears
* mapping between entities, attributes and relationships.
*/
@@ -439,4 +436,4 @@ public class ProjectUtil {
}
return relationships;
}
-}
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cayenne/blob/b444b1df/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/SortButtonRenderer.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/SortButtonRenderer.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/SortButtonRenderer.java
index 524d8ba..595ba4d 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/SortButtonRenderer.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/SortButtonRenderer.java
@@ -18,51 +18,33 @@
****************************************************************/
package org.apache.cayenne.modeler.util;
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.Insets;
-import java.util.Hashtable;
-
import javax.swing.BorderFactory;
-import javax.swing.JButton;
+import javax.swing.JLabel;
import javax.swing.JTable;
-import javax.swing.border.MatteBorder;
+import javax.swing.border.Border;
import javax.swing.table.TableCellRenderer;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Font;
+import java.util.Hashtable;
-public class SortButtonRenderer extends JButton implements TableCellRenderer {
+public class SortButtonRenderer extends JLabel implements TableCellRenderer {
public static final int NONE = 0;
public static final int DOWN = 1;
public static final int UP = 2;
- private int pushedColumn;
private Hashtable state;
- private JButton downButton, upButton;
+ private JLabel downLabel , upLabel;
public SortButtonRenderer() {
- MatteBorder matteBorder = BorderFactory.createMatteBorder(0, 0, 1, 1, Color.gray);
- setBorder(matteBorder);
-
- pushedColumn = -1;
state = new Hashtable();
- setMargin(new Insets(0, 0, 0, 0));
- setHorizontalTextPosition(CENTER);
- setIcon(new BlankIcon());
+ downLabel = new JLabel();
+ downLabel.setIcon(new BevelArrowIcon(BevelArrowIcon.DOWN, false, false));
- downButton = new JButton();
-
- downButton.setBorder(matteBorder);
- downButton.setMargin(new Insets(0, 0, 0, 0));
- downButton.setHorizontalTextPosition(LEFT);
- downButton.setIcon(new BevelArrowIcon(BevelArrowIcon.DOWN, false, false));
- downButton.setPressedIcon(new BevelArrowIcon(BevelArrowIcon.DOWN, false, true));
-
- upButton = new JButton();
- upButton.setBorder(matteBorder);
- upButton.setMargin(new Insets(0, 0, 0, 0));
- upButton.setHorizontalTextPosition(LEFT);
- upButton.setIcon(new BevelArrowIcon(BevelArrowIcon.UP, false, false));
+ upLabel = new JLabel();
+ upLabel.setIcon(new BevelArrowIcon(BevelArrowIcon.UP, false, false));
}
public Component getTableCellRendererComponent(
@@ -72,49 +54,51 @@ public class SortButtonRenderer extends JButton implements TableCellRenderer {
boolean hasFocus,
int row,
int column) {
- JButton button = this;
- Object obj = state.get(new Integer(column));
+ JLabel label = this;
+ Object obj = state.get(column);
if (obj != null) {
- if (((Integer) obj).intValue() == DOWN) {
- button = downButton;
+ if ((Integer) obj == DOWN) {
+ label = downLabel;
}
else {
- button = upButton;
+ label = upLabel;
}
}
- button.setText((value == null) ? "" : value.toString());
- return button;
- }
-
- public void setPressedColumn(int col) {
- pushedColumn = col;
+ Border border = BorderFactory.createLineBorder(Color.GRAY, 1);
+ label.setText(' ' + ((value == null) ? "" : value.toString()));
+ label.setFont(new Font("Verdana", Font.BOLD , 13));
+ label.setHorizontalTextPosition(JLabel.LEFT);
+ label.setBorder(border);
+ label.setOpaque(true);
+ label.setBackground(new Color(204, 238, 255));
+ return label;
}
public void setSelectedColumn(int col, boolean isAscOrder) {
- if (col < 0)
+ if (col < 0) {
return;
+ }
Integer value = null;
//shows the direction of ordering
if (isAscOrder) {
- value = new Integer(DOWN);
- }
- else {
- value = new Integer(UP);
+ value = DOWN;
+ } else {
+ value = UP;
}
state.clear();
- state.put(new Integer(col), value);
+ state.put(col, value);
}
public int getState(int col) {
int retValue;
- Object obj = state.get(new Integer(col));
+ Object obj = state.get(col);
if (obj == null) {
retValue = NONE;
}
else {
- if (((Integer) obj).intValue() == DOWN) {
+ if ((Integer) obj == DOWN) {
retValue = DOWN;
}
else {
http://git-wip-us.apache.org/repos/asf/cayenne/blob/b444b1df/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/TableHeaderListener.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/TableHeaderListener.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/TableHeaderListener.java
index 29bf1a7..b665730 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/TableHeaderListener.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/TableHeaderListener.java
@@ -72,14 +72,12 @@ public class TableHeaderListener extends MouseAdapter {
}
public void mouseReleased(MouseEvent e) {
- renderer.setPressedColumn(-1); // clear
header.repaint();
}
public void sortByDefinedColumn(int col, int sortCol, boolean order) {
CayenneTableModel model = (CayenneTableModel) table.getModel();
if (model.isColumnSortable(sortCol)) {
- renderer.setPressedColumn(col);
renderer.setSelectedColumn(col, order);
header.repaint();
http://git-wip-us.apache.org/repos/asf/cayenne/blob/b444b1df/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/AutoCompletion.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/AutoCompletion.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/AutoCompletion.java
index 2e86251..9c8a371 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/AutoCompletion.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/combo/AutoCompletion.java
@@ -19,15 +19,17 @@
package org.apache.cayenne.modeler.util.combo;
+import javax.swing.JComboBox;
+import javax.swing.JScrollBar;
+import javax.swing.JScrollPane;
+import javax.swing.SwingUtilities;
+import javax.swing.text.JTextComponent;
+import java.awt.Component;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
-import javax.swing.JComboBox;
-import javax.swing.SwingUtilities;
-import javax.swing.text.JTextComponent;
-
/**
* AutoCompletion class handles user input and suggests matching variants (see CAY-911)
*
@@ -55,8 +57,8 @@ public class AutoCompletion implements FocusListener, KeyListener, Runnable {
protected AutoCompletion(final JComboBox comboBox, boolean strict, boolean allowsUserValues) {
this.comboBox = comboBox;
textEditor = ((JTextComponent)comboBox.getEditor().getEditorComponent());
-
- this.allowsUserValues = allowsUserValues;
+
+ this.allowsUserValues = allowsUserValues;
suggestionList = new SuggestionList(comboBox, strict);
@@ -75,13 +77,17 @@ public class AutoCompletion implements FocusListener, KeyListener, Runnable {
*/
public static void enable(JComboBox comboBox, boolean strict, boolean allowsUserValues) {
comboBox.setEditable(true);
-
+ KeyListener[] listeners = comboBox.getEditor().getEditorComponent().getListeners(KeyListener.class);
comboBox.setEditor(new CustomTypeComboBoxEditor(comboBox, allowsUserValues));
-
+ for (KeyListener listener : listeners) {
+ comboBox.getEditor().getEditorComponent().addKeyListener(listener);
+ }
+
+
AutoCompletion ac = new AutoCompletion(comboBox, strict, allowsUserValues);
comboBox.addFocusListener(ac);
ac.textEditor.addKeyListener(ac);
-
+
//original keys would not work properly
SwingUtilities.replaceUIActionMap(comboBox, null);
}
@@ -100,23 +106,34 @@ public class AutoCompletion implements FocusListener, KeyListener, Runnable {
}
public void keyPressed(KeyEvent e) {
- handleKeyPressed(comboBox, e);
+ handleKeyPressed(e);
}
- public void keyReleased(KeyEvent e) {}
+ public void keyReleased(KeyEvent e) {
+ if (e.getKeyCode() == KeyEvent.VK_BACK_SPACE ||
+ e.getKeyCode() == KeyEvent.VK_ENTER) {
+
+ String text = textEditor.getText();
+ if (comboBox.isShowing()) {
+ suggestionList.hide();
+ suggestionList.filter(text);
+ suggestionList.show();
+ }
+ }
+ }
public void keyTyped(KeyEvent e) {}
-
+
public void run() {
String text = textEditor.getText();
-
+
//need to hide first because Swing incorrectly updates popups (getSize() returns
//dimension not the same as seen on the screen)
suggestionList.hide();
-
+
if (comboBox.isShowing()) {
suggestionList.filter(text);
-
+
if (suggestionList.getItemCount() > 0) {
suggestionList.show();
}
@@ -127,24 +144,31 @@ public class AutoCompletion implements FocusListener, KeyListener, Runnable {
* Calculates next selection row, according to a pressed key and selects it.
* This might affect either suggestion list or original popup
*/
- private void handleKeyPressed(JComboBox comboBox, KeyEvent e) {
+ private void handleKeyPressed(KeyEvent e) {
boolean suggest = suggestionList.isVisible();
-
- int sel, next, max;
-
+
if (suggest) {
- sel = suggestionList.getSelectedIndex();
- max = suggestionList.getItemCount() - 1;
+ processKeyPressedWhenSuggestionListIsVisible(e);
}
else {
- sel = comboBox.getSelectedIndex();
- max = comboBox.getItemCount() - 1;
+ processKeyPressedWhenSuggestionListIsInvisible(e);
}
-
+
+ //scroll doesn't work in suggestionList..so we will scroll manually
+ suggestionListScrolling();
+
+ textEditor.requestFocus();
+ }
+
+ private void processKeyPressedWhenSuggestionListIsInvisible(KeyEvent e){
+ int sel = comboBox.getSelectedIndex();
+ int max = comboBox.getItemCount() - 1;
+
+ int next;
switch (e.getKeyCode()) {
case KeyEvent.VK_UP:
case KeyEvent.VK_NUMPAD8:
- next = sel - 1;
+ next = sel - 1;
break;
case KeyEvent.VK_DOWN:
case KeyEvent.VK_NUMPAD2:
@@ -163,42 +187,71 @@ public class AutoCompletion implements FocusListener, KeyListener, Runnable {
next = max;
break;
case KeyEvent.VK_ENTER:
- if (suggest) {
- Object value = suggestionList.getSelectedValue();
- if (!allowsUserValues && value == null && suggestionList.getItemCount() > 0) {
- value = suggestionList.getItemAt(0);
- }
-
- //reset the item (value == null) only if user values are not supported
- if (value != null || !allowsUserValues) {
- comboBox.setSelectedItem(value);
- }
- suggestionList.hide();
- }
return;
-
case KeyEvent.VK_ESCAPE:
- if (suggest) {
- suggestionList.hide();
- }
return;
-
- case KeyEvent.VK_CONTROL:
- case KeyEvent.VK_ALT:
- case KeyEvent.VK_SHIFT:
- return;
-
default:
//invoke in end of AWT thread so that information in textEditor would update
SwingUtilities.invokeLater(this);
return;
}
-
- /**
- * Handle navigation keys
- */
+ e.consume();
+ handleNavigationKeys(false,next,sel,max);
+ }
+ private void processKeyPressedWhenSuggestionListIsVisible(KeyEvent e){
+ int sel = suggestionList.getSelectedIndex();
+ int max = suggestionList.getItemCount() - 1;
+ int next;
+ switch (e.getKeyCode()) {
+ case KeyEvent.VK_UP:
+ case KeyEvent.VK_NUMPAD8:
+ next = sel - 1;
+ break;
+ case KeyEvent.VK_DOWN:
+ case KeyEvent.VK_NUMPAD2:
+ next = sel + 1;
+ break;
+ case KeyEvent.VK_PAGE_UP:
+ next = sel - comboBox.getMaximumRowCount();
+ break;
+ case KeyEvent.VK_PAGE_DOWN:
+ next = sel + comboBox.getMaximumRowCount();
+ break;
+ case KeyEvent.VK_HOME:
+ next = 0;
+ break;
+ case KeyEvent.VK_END:
+ next = max;
+ break;
+ case KeyEvent.VK_ENTER:
+ processEnterPressed();
+ return;
+ case KeyEvent.VK_ESCAPE:
+ suggestionList.hide();
+ return;
+ default:
+ //invoke in end of AWT thread so that information in textEditor would update
+ SwingUtilities.invokeLater(this);
+ return;
+ }
e.consume();
+ handleNavigationKeys(true,next,sel,max);
+ }
+
+ private void processEnterPressed(){
+ Object value = suggestionList.getSelectedValue();
+ if (!allowsUserValues && value == null && suggestionList.getItemCount() > 0) {
+ value = suggestionList.getItemAt(0);
+ }
+ //reset the item (value == null) only if user values are not supported
+ if (value != null || !allowsUserValues) {
+ comboBox.setSelectedItem(value);
+ }
+ suggestionList.hide();
+ }
+
+ private void handleNavigationKeys(boolean suggest, int next, int sel, int max){
if (!suggest && !comboBox.isPopupVisible()) {
comboBox.setPopupVisible(true);
return;
@@ -208,22 +261,33 @@ public class AutoCompletion implements FocusListener, KeyListener, Runnable {
if (next < 0) {
next = 0;
}
-
+
if (next > max) {
next = max;
}
-
+
if (next != sel) {
if (suggest) {
suggestionList.setSelectedIndex(next);
- }
- else {
- comboBox.setPopupVisible(true);
- comboBox.setSelectedIndex(next);
+ } else {
+ comboBox.setPopupVisible(true);
+ comboBox.setSelectedIndex(next);
}
}
-
- textEditor.requestFocus();
+ }
+ }
+
+ private void suggestionListScrolling(){
+ Component c = suggestionList.getComponent(0);
+ if (c instanceof JScrollPane) {
+ double height = suggestionList.getPreferredSize().getHeight();
+ int itemCount = suggestionList.getItemCount();
+ int selectedIndex = suggestionList.getSelectedIndex();
+ double scrollValue = Math.ceil(height*selectedIndex/itemCount);
+ JScrollPane scrollPane = (JScrollPane) c;
+ JScrollBar scrollBar = scrollPane.getVerticalScrollBar();
+ scrollBar.setValue((int) scrollValue);
}
}
}
+