/*
* Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code 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 Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package com.sun.dtv.lwuit;
import com.sun.dtv.lwuit.events.ActionEvent;
import com.sun.dtv.lwuit.events.ActionListener;
import com.sun.dtv.lwuit.events.DataChangedListener;
import com.sun.dtv.lwuit.geom.Dimension;
import com.sun.dtv.lwuit.layouts.GridLayout;
import com.sun.dtv.lwuit.plaf.UIManager;
import java.util.Hashtable;
import java.util.Vector;
/**
* Allows in place editing using a lightweight API without necessarily moving to
* the external native text box. The main drawback in this approach is that editing
* can't support features such as T9 and might not have the same keymapping or
* behavior of the native text input.
* <p>Notice that due to limitations of text area and text field input modes in
* text area aren't properly supported since they won't work properly across devices.
* To limit input modes please use the setInputModeOrder method. All constants
* declated in TextArea are ignored with the exception of PASSWORD.
*
* @author Shai Almog
*/
public class TextField extends TextArea {
private static boolean replaceMenuDefault = true;
private long cursorBlinkTime = System.currentTimeMillis();
private boolean drawCursor = true;
private int cursorCharPosition = -1;
private boolean pressedAndNotReleased;
private long pressTime;
private boolean useSoftkeys = true;
private long releaseTime;
private String previousText;
private int commitTimeout = 1000;
private boolean pendingCommit;
private int pressCount = 0;
private int lastKeyCode;
private int pressedKeyCode;
private static String clearText = "Clear";
private static String t9Text = "T9";
private boolean longClick;
private Command originalClearCommand;
private static Hashtable inputModes;
private String inputMode = "Abc";
private static String[] defaultInputModeOrder = {"Abc", "ABC", "abc", "123"};
private String[] inputModeOrder = defaultInputModeOrder;
private static Vector firstUppercaseInputMode = new Vector();
private Vector listeners = null;
private int blinkOnTime = 800;
private int blinkOffTime = 200;
private boolean qwerty;
private boolean replaceMenu = replaceMenuDefault;
private Command[] originalCommands;
/**
* Set the text that should appear on the clear softkey
*/
public static void setClearText(String text) {
clearText = text;
}
/**
* Set the text that should appear on the T9 softkey
*/
public static void setT9Text(String text) {
t9Text = text;
}
private Command DELETE_COMMAND = new Command(clearText) {
public void actionPerformed(ActionEvent ev) {
deleteChar();
}
};
private Command T9_COMMAND = new Command(t9Text) {
public void actionPerformed(ActionEvent ev) {
editString();
}
};
private static final char[] DEFAULT_SYMBOL_TABLE = new char[] {
'.', ',', '?', '!', '$', '@', '\'', '-',
'_', ')', '(', ':', ';', '&', '/', '~',
'\\', '%', '*', '#', '+', '>', '=', '<',
'"'
};
private static char[] symbolTable = DEFAULT_SYMBOL_TABLE;
private static final String[] DEFAULT_KEY_CODES = {
// 0
" 0",
// 1
".,?!'\"1-()@/:_",
// 2
"ABC2",
// 3
"DEF3",
// 4
"GHI4",
// 5
"JKL5",
// 6
"MNO6",
// 7
"PQRS7",
// 8
"TUV8",
// 9
"WXYZ9",
};
/**
* Default constructor
*/
public TextField() {
super(1, 20);
}
/**
* Construct a text field with space reserved for columns
*/
public TextField(int columns) {
super(1, columns);
}
/**
* Construct text field
*/
public TextField(String text) {
super(text, 1, 20);
}
/**
* Performs a backspace operation
*/
protected void deleteChar() {
String text = getText();
if(text.length() > 0) {
if(cursorCharPosition > 0) {
cursorCharPosition--;
}
text = text.substring(0, cursorCharPosition) +
text.substring(cursorCharPosition + 1, text.length());
super.setText(text);
fireDataChanged(DataChangedListener.REMOVED, cursorCharPosition);
}
}
/**
* Construct text field
*/
public TextField(String text, int columns) {
super(text, 1, columns);
}
/**
* @inheritDoc
*/
protected String getUIID() {
return "TextField";
}
/**
* Commit the changes made to the text field as a complete edit operation. This
* is used in a numeric keypad to allow the user to repeatedly press a number
* to change values.
*/
protected void commitChange() {
pendingCommit = false;
previousText = null;
pressCount = 0;
}
/**
* Returns true if the text field is waiting for a commit on editing
*/
public boolean isPendingCommit() {
return pendingCommit;
}
/**
* The amount of time in milliseconds it will take for a change to get commited into
* the field.
*
* @param commitTimeout indicates the amount of time that should elapse for a commit
* to automatically occur
*/
public void setCommitTimeout(int commitTimeout) {
this.commitTimeout = commitTimeout;
}
/**
* The amount of time in milliseconds it will take for a change to get commited into
* the field.
*/
public int getCommitTimeout() {
return commitTimeout;
}
/**
* Sets the current selected input mode matching one of the existing input
* modes
*
* @param inputMode the display name of the input mode by default the following modes
* are supported: Abc, ABC, abc, 123
*/
public void setInputMode(String inputMode) {
this.inputMode = inputMode;
repaint();
}
/**
* Returns the currently selected input mode
*
* @return the display name of the input mode by default the following modes
* are supported: Abc, ABC, abc, 123
*/
public String getInputMode() {
return inputMode;
}
/**
* Indicates whether the key changes the current input mode
*
* @return true for the hash (#) key code
*/
protected boolean isChangeInputMode(int keyCode) {
return keyCode == '#';
}
private static void initInputModes() {
if(inputModes == null) {
firstUppercaseInputMode.addElement("Abc");
inputModes = new Hashtable();
Hashtable upcase = new Hashtable();
for(int iter = 0 ; iter < DEFAULT_KEY_CODES.length ; iter++) {
upcase.put(new Integer('0' + iter), DEFAULT_KEY_CODES[iter]);
}
inputModes.put("ABC", upcase);
Hashtable lowcase = new Hashtable();
for(int iter = 0 ; iter < DEFAULT_KEY_CODES.length ; iter++) {
lowcase.put(new Integer('0' + iter), DEFAULT_KEY_CODES[iter].toLowerCase());
}
inputModes.put("abc", lowcase);
Hashtable numbers = new Hashtable();
for(int iter = 0 ; iter < 10 ; iter++) {
numbers.put(new Integer('0' + iter), "" + iter);
}
inputModes.put("123", numbers);
}
}
/**
* Adds a new inputmode hashtable with the given name and set of values
*
* @param name a unique display name for the input mode e.g. ABC, 123 etc...
* @param values The key for the hashtable is an Integer keyCode and the value
* is a String containing the characters to toggle between for the given keycode
* @param firstUpcase indicates if this input mode in an input mode used for the special
* case where the first letter is an upper case letter
*/
public static void addInputMode(String name, Hashtable values, boolean firstUpcase) {
initInputModes();
inputModes.put(name, values);
if(firstUpcase) {
firstUppercaseInputMode.addElement(name);
}
}
/**
* Returns the order in which input modes are toggled
*/
public String[] getInputModeOrder() {
return inputModeOrder;
}
/**
* Sets the order in which input modes are toggled and allows disabling/hiding
* an input mode
*
* @param order the order for the input modes in this field
*/
public void setInputModeOrder(String[] order) {
inputModeOrder = order;
inputMode = order[0];
}
/**
* Returns the order in which input modes are toggled by default
*/
public static String[] getDefaultInputModeOrder() {
return defaultInputModeOrder;
}
/**
* Sets the order in which input modes are toggled by default and allows
* disabling/hiding an input mode
*
* @param order the order for the input modes in all future created fields
*/
public static void setDefaultInputModeOrder(String[] order) {
defaultInputModeOrder = order;
}
/**
* Used for the case of first sentence character should be upper case
*/
private String pickLowerOrUpper(String inputMode) {
// check the character before the cursor..
int pos = cursorCharPosition - 1;
// we have input which has moved the cursor position further
if(pendingCommit) {
pos--;
}
String text = getText();
if(pos >= text.length()) {
pos = text.length() - 1;
}
while(pos > -1) {
if(text.charAt(pos) == '.') {
return inputMode.toUpperCase();
}
if(text.charAt(pos) != ' ') {
return inputMode.toLowerCase();
}
pos--;
}
return inputMode.toUpperCase();
}
/**
* Returns the input mode for the ong click mode
*
* @return returns 123 by default
*/
protected String getLongClickInputMode() {
return "123";
}
/**
* Returns the character matching the given key code after the given amount
* of user presses
*
* @param pressCount number of times this keycode was pressed
* @param keyCode the actual keycode input by the user
* @param longClick does this click constitute a long click
* @return the char mapping to this key or 0 if no appropriate char was found
* (navigation, input mode change etc...).
*/
protected char getCharPerKeyCode(int pressCount, int keyCode, boolean longClick) {
initInputModes();
String input = inputMode;
// if this is a first letter uppercase input mode then we need to pick either
// the upper case mode or the lower case mode...
if(longClick) {
input = getLongClickInputMode();
} else {
if(firstUppercaseInputMode.contains(input)) {
input = pickLowerOrUpper(input);
}
}
Hashtable mode = (Hashtable)inputModes.get(input);
String s = (String)mode.get(new Integer(keyCode));
if(s != null) {
pressCount = pressCount % s.length();
return s.charAt(pressCount);
}
return 0;
}
/**
* Blocks the text area from opening the native text box editing on touchscreen click
*/
void onClick() {
}
/**
* Set the position of the cursor
*/
public void setCursorPosition(int pos) {
if(pos < -1 || pos > getText().length()) {
throw new IllegalArgumentException("Illegal cursor position: " + pos);
}
cursorCharPosition = pos;
}
/**
* Returns the position of the cursor
*/
public int getCursorPosition() {
if(getText() == null) {
return 0;
}
return Math.min(getText().length(), cursorCharPosition);
}
/**
* @inheritDoc
*/
public void setText(String text) {
super.setText(text);
fireDataChanged(DataChangedListener.CHANGED, -1);
if(cursorCharPosition < 0) {
cursorCharPosition = text.length();
} else {
if(cursorCharPosition > text.length()) {
cursorCharPosition = text.length();
}
}
}
/**
* Invoked on a long click by the user
*/
private void longClick(int keyCode) {
longClick = true;
keyReleaseOrLongClick(keyCode, true);
}
/**
* Returns true if this is the clear key on the device, many devices don't contain
* a clear key and even in those that contain it this might be an issue
*
* @param keyCode the key code that might be the clear key
* @return true if this is the clear key.
*/
protected boolean isClearKey(int keyCode) {
return keyCode == Form.clearSK;
}
/**
* True is this is a qwerty device or a device that is currently in
* qwerty mode.
*
* @return currently defaults to false
*/
public boolean isQwertyInput() {
return qwerty;
}
/**
* True is this is a qwerty device or a device that is currently in
* qwerty mode.
*/
public void setQwertyInput(boolean qwerty) {
this.qwerty = qwerty;
}
private boolean keyReleaseOrLongClick(int keyCode, boolean longClick) {
// user pressed a different key, autocommit everything
if(lastKeyCode != keyCode && pendingCommit) {
commitChange();
}
lastKeyCode = keyCode;
if(isQwertyInput()) {
if(keyCode > 0) {
String text;
if(previousText == null) {
previousText = getText();
}
if(cursorCharPosition < 0) {
cursorCharPosition = 0;
}
cursorCharPosition++;
text = previousText.substring(0, cursorCharPosition - 1) + ((char)keyCode) +
previousText.substring(cursorCharPosition - 1, previousText.length());
super.setText(text);
commitChange();
fireDataChanged(DataChangedListener.ADDED, cursorCharPosition);
return true;
}
} else {
char c = getCharPerKeyCode(pressCount, keyCode, longClick);
cursorCharPosition = Math.max(cursorCharPosition, 0);
if (c != 0) {
String text;
if(previousText == null) {
previousText = getText();
}
if(!pendingCommit) {
cursorCharPosition++;
}
text = previousText.substring(0, cursorCharPosition - 1) + c +
previousText.substring(cursorCharPosition - 1, previousText.length());
pendingCommit = true;
pressCount++;
super.setText(text);
if(inputMode.equals("123")) {
commitChange();
fireDataChanged(DataChangedListener.ADDED, cursorCharPosition);
} else {
if(pressCount == 1) {
fireDataChanged(DataChangedListener.ADDED, cursorCharPosition);
} else {
fireDataChanged(DataChangedListener.CHANGED, cursorCharPosition);
}
}
return true;
}
}
int game = Display.getInstance().getGameAction(keyCode);
if(game == Display.GAME_RIGHT) {
cursorCharPosition++;
if(cursorCharPosition > getText().length()) {
if(isCursorPositionCycle()) {
cursorCharPosition = 0;
} else {
cursorCharPosition = getText().length();
}
}
repaint();
return true;
} else {
if(game == Display.GAME_LEFT) {
cursorCharPosition--;
if(cursorCharPosition < 0) {
if(isCursorPositionCycle()) {
cursorCharPosition = getText().length();
} else {
cursorCharPosition = 0;
}
}
repaint();
return true;
}
}
if(isChangeInputMode(keyCode)) {
for(int iter = 0 ; iter < inputModeOrder.length ; iter++) {
if(inputModeOrder[iter].equals(inputMode)) {
iter++;
if(iter < inputModeOrder.length) {
setInputMode(inputModeOrder[iter]);
} else {
setInputMode(inputModeOrder[0]);
}
return true;
}
}
return true;
}
if(isClearKey(keyCode)) {
deleteChar();
return true;
}
if(isSymbolDialogKey(keyCode)) {
ActionListener listener = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
String text = ((Button)evt.getSource()).getText();
String currentText = getText();
cursorCharPosition++;
setText(currentText.substring(0, cursorCharPosition - 1) + text +
currentText.substring(cursorCharPosition - 1, currentText.length()));
fireDataChanged(DataChangedListener.ADDED, cursorCharPosition);
Display.getInstance().getCurrent().dispose();
}
};
char[] symbolArray = getSymbolTable();
Container symbols = new Container(new GridLayout(symbolArray.length / 5, 5));
for(int iter = 0 ; iter < symbolArray.length ; iter++) {
Button button = new Button("" + symbolArray[iter]);
button.setAlignment(CENTER);
button.addActionListener(listener);
symbols.addComponent(button);
}
Command cancel = new Command("Cancel");
Dialog.show(null, symbols, new Command[] {cancel});
return true;
}
return false;
}
/**
* @inheritDoc
*/
public void keyReleased(int keyCode) {
pressedAndNotReleased = false;
releaseTime = System.currentTimeMillis();
if(!longClick) {
if(keyReleaseOrLongClick(keyCode, false)) {
return;
}
}
longClick = false;
super.keyReleased(keyCode);
}
/**
* The amount of time considered as a "long click" causing the long click method
* to be invoked.
*
* @return currently defaults to 800
*/
protected int getLongClickDuration() {
return 800;
}
/**
* Returns the symbol table for the device
*/
public static char[] getSymbolTable() {
return symbolTable;
}
/**
* Sets the symbol table to show when the user clicks the symbol table key
*/
public static void setSymbolTable(char[] table) {
symbolTable = table;;
}
/**
* Returns true if the cursor should cycle to the begining of the text when the
* user navigates beyond the edge of the text and visa versa.
* @return true by default
*/
protected boolean isCursorPositionCycle() {
return true;
}
/**
* Returns true if this keycode is the one mapping to the symbol dialog popup
*
* @param keyCode the keycode to check
* @return true if this is the star symbol *
*/
protected boolean isSymbolDialogKey(int keyCode) {
return keyCode == '*';
}
/**
* @inheritDoc
*/
public void keyPressed(int keyCode) {
pressedAndNotReleased = true;
pressedKeyCode = keyCode;
pressTime = System.currentTimeMillis();
if((!handlesInput()) && isEditingTrigger(keyCode)) {
setHandlesInput(true);
if(useSoftkeys) {
T9_COMMAND.setDisposesDialog(false);
DELETE_COMMAND.setDisposesDialog(false);
originalClearCommand = installCommands(DELETE_COMMAND, T9_COMMAND);
}
return;
}
if(handlesInput() && isEditingEndTrigger(keyCode)) {
setHandlesInput(false);
if(useSoftkeys) {
removeCommands(DELETE_COMMAND, T9_COMMAND, originalClearCommand);
}
fireActionEvent();
return;
} else {
if(handlesInput()) {
return;
}
}
super.keyPressed(keyCode);
}
/**
* Installs the clear and t9 commands onto the parent form, this method can
* be overriden to provide device specific placement for these commands
*
* @param clear the clear command
* @param t9 the t9 command
* @return clear command already installed in the form if applicable, none if no
* clear command was installed before or not applicable.
*/
protected Command installCommands(Command clear, Command t9) {
Form f = getComponentForm();
Command original = f.getClearCommand();
if(replaceMenu && originalCommands == null) {
originalCommands = new Command[f.getCommandCount()];
for(int iter = 0 ; iter < originalCommands.length ; iter++) {
originalCommands[iter] = f.getCommand(iter);
}
f.removeAllCommands();
}
f.addCommand(clear, 0);
f.addCommand(t9, 0);
f.setClearCommand(clear);
return original;
}
/**
* Removes the clear and t9 commands from the parent form, this method can
* be overriden to provide device specific placement for these commands
*
* @param clear the clear command
* @param t9 the t9 command
* @param originalClear the command originally assigned as the clear command (or null if no command was assigned before)
*/
protected void removeCommands(Command clear, Command t9, Command originalClear) {
Form f = getComponentForm();
f.removeCommand(clear);
f.removeCommand(t9);
f.setClearCommand(originalClear);
if(replaceMenu && originalCommands != null) {
for(int iter = originalCommands.length - 1 ; iter >= 0 ; iter--) {
f.addCommand(originalCommands[iter]);
}
originalCommands = null;
}
}
void focusLostInternal() {
if(useSoftkeys) {
Form f = getComponentForm();
if(f != null) {
removeCommands(DELETE_COMMAND, T9_COMMAND, originalClearCommand);
}
}
}
/**
* Indicates whether the given key code should be ignored or should trigger
* editing, by default fire or any numeric key should trigger editing implicitly.
* This method is only called when handles input is false.
*
* @param keyCode the keycode passed to the keyPressed method
* @return true if this key code should cause a switch to editing mode.
*/
protected boolean isEditingTrigger(int keyCode) {
if(isQwertyInput()) {
return keyCode > 0 || (Display.getInstance().getGameAction(keyCode) == Display.GAME_FIRE);
}
return (keyCode >= '0' && keyCode <= '9') ||
(Display.getInstance().getGameAction(keyCode) == Display.GAME_FIRE);
}
/**
* Indicates whether the given key code should be ignored or should trigger
* cause editing to end. By default the fire key, up or down will trigger
* the end of editing.
*
* @param keyCode the keycode passed to the keyPressed method
* @return true if this key code should cause a switch to editing mode.
*/
protected boolean isEditingEndTrigger(int keyCode) {
int k =Display.getInstance().getGameAction(keyCode);
if(isQwertyInput()) {
return keyCode < 0 && (k == Display.GAME_FIRE || k == Display.GAME_UP || k == Display.GAME_DOWN);
}
return (k == Display.GAME_FIRE || k == Display.GAME_UP || k == Display.GAME_DOWN);
}
/**
* @inheritDoc
*/
public void paint(Graphics g) {
UIManager.getInstance().getLookAndFeel().drawTextField(g, this);
if (drawCursor) {
UIManager.getInstance().getLookAndFeel().drawTextFieldCursor(g, this);
}
}
/**
* @inheritDoc
*/
protected Dimension calcPreferredSize() {
return UIManager.getInstance().getLookAndFeel().getTextFieldPreferredSize(this);
}
/**
* @inheritDoc
*/
protected void initComponent() {
getComponentForm().registerAnimated(this);
}
/**
* The amount of time in milliseconds in which the cursor is visible
*/
public void setCursorBlinkTimeOn(int time) {
blinkOnTime = time;
}
/**
* The amount of time in milliseconds in which the cursor is invisible
*/
public void setCursorBlinkTimeOff(int time) {
blinkOffTime = time;
}
/**
* The amount of time in milliseconds in which the cursor is visible
*/
public int getCursorBlinkTimeOn() {
return blinkOnTime;
}
/**
* The amount of time in milliseconds in which the cursor is invisible
*/
public int getCursorBlinkTimeOff() {
return blinkOffTime;
}
/**
* @inheritDoc
*/
public boolean animate() {
boolean ani = super.animate();
if(hasFocus()) {
long currentTime = System.currentTimeMillis();
if (drawCursor) {
if ((currentTime - cursorBlinkTime) > blinkOnTime) {
cursorBlinkTime = currentTime;
drawCursor = false;
return true;
}
} else {
if ((currentTime - cursorBlinkTime) > blinkOffTime) {
cursorBlinkTime = currentTime;
drawCursor = true;
return true;
}
}
if(pressedAndNotReleased) {
if(currentTime - pressTime >= getLongClickDuration()) {
longClick(pressedKeyCode);
}
} else {
if(pendingCommit && currentTime - releaseTime > commitTimeout) {
commitChange();
}
}
} else {
drawCursor = false;
}
return ani;
}
/**
* @inheritDoc
*/
public void pointerReleased(int x, int y) {
// unlike text area the text field supports shifting the cursor with the touch screen
String text = getText();
int textLength = text.length();
int position = 0;
Font f = getStyle().getFont();
x -= getAbsoluteX();
for(int iter = 0 ; iter < textLength ; iter++) {
int width = f.substringWidth(text, 0, iter);
if(x > width) {
position = iter;
} else {
break;
}
}
if(position == textLength - 1) {
if(f.stringWidth(text) < x) {
position = textLength;
}
}
setCursorPosition(position);
repaint();
}
/**
* When set to true softkeys are used to enable delete functionality
*/
public boolean isUseSoftkeys() {
return useSoftkeys;
}
/**
* When set to true softkeys are used to enable delete functionality
*/
public void setUseSoftkeys(boolean useSoftkeys) {
this.useSoftkeys = useSoftkeys;
}
/**
* Adds a listener for data change events it will be invoked for every change
* made to the text field
*/
public void addDataChangeListener(DataChangedListener d) {
if(listeners == null) {
listeners = new Vector();
}
if(!listeners.contains(d)) {
listeners.addElement(d);
}
}
/**
* Removes the listener for data change events
*/
public void removeDataChangeListener(DataChangedListener d) {
if(listeners == null) {
listeners = new Vector();
}
listeners.removeElement(d);
}
private void fireDataChanged(int type, int index) {
if(listeners != null) {
for(int iter = 0 ; iter < listeners.size() ; iter++) {
DataChangedListener d = (DataChangedListener)listeners.elementAt(iter);
d.dataChanged(type, index);
}
}
}
/**
* @inheritDoc
*/
void onEditComplete(String text) {
super.onEditComplete(text);
setCursorPosition(text.length());
}
/**
* Indicates whether the menu of the form should be replaced with the T9/Clear
* commands for the duration of interactivity with the text field
*/
public boolean isReplaceMenu() {
return replaceMenu;
}
/**
* Indicates whether the menu of the form should be replaced with the T9/Clear
* commands for the duration of interactivity with the text field
*/
public void setReplaceMenu(boolean replaceMenu) {
this.replaceMenu = replaceMenu;
}
/**
* Indicates whether the menu of the form should be replaced with the T9/Clear
* commands for the duration of interactivity with the text field
*/
public static boolean isReplaceMenuDefault() {
return replaceMenuDefault;
}
/**
* Indicates whether the menu of the form should be replaced with the T9/Clear
* commands for the duration of interactivity with the text field
*/
public static void setReplaceMenuDefault(boolean replaceMenu) {
replaceMenuDefault = replaceMenu;
}
}