content: package tim.prune.function.edit;
  
  import java.awt.Component;
  import java.awt.BorderLayout;
  import java.awt.FlowLayout;
  import java.awt.event.KeyAdapter;
  import java.awt.event.KeyEvent;
  
  import javax.swing.BorderFactory;
  import javax.swing.BoxLayout;
  import javax.swing.JButton;
  import javax.swing.JDialog;
  import javax.swing.JLabel;
  import javax.swing.JPanel;
  import javax.swing.JTextField;
  
  import tim.prune.App;
  import tim.prune.GenericFunction;
  import tim.prune.I18nManager;
  import tim.prune.cmd.EditPointCmd;
  import tim.prune.data.DataPoint;
  import tim.prune.data.Field;
  
  /**
   * Function to manage the display and editing of waypoint names
   */
  public class PointNameEditor extends GenericFunction
  {
  	private JDialog _dialog = null;
  	private DataPoint _point = null;
  	private JTextField _nameField = null;
  	private JButton _okButton = null;
  
  	private enum CaseOperation {LOWER_CASE, UPPER_CASE, TITLE_CASE}
  
  
  	/**
  	 * Constructor
  	 * @param inApp application object to inform of success
  	 */
  	public PointNameEditor(App inApp) {
  		super(inApp);
  	}
  
  	/** Get the name key */
  	public String getNameKey() {
  		return "function.editwaypointname";
  	}
  
  	/**
  	 * Begin the function by showing the edit point name dialog
  	 */
  	public void begin()
  	{
  		_point = _app.getTrackInfo().getCurrentPoint();
  		if (_dialog == null)
  		{
  			_dialog = new JDialog(_parentFrame, getName(), true);
  			_dialog.setLocationRelativeTo(_parentFrame);
  			// Create Gui and show it
  			_dialog.getContentPane().add(makeDialogComponents());
  			_dialog.pack();
  		}
  		// Check current waypoint name, if any
  		String name = _point.getWaypointName();
  		resetDialog(name);
  		_dialog.setVisible(true);
  	}
  
  
  	/**
  	 * Make the dialog components
  	 * @return the GUI components for the dialog
  	 */
  	private Component makeDialogComponents()
  	{
  		JPanel panel = new JPanel();
  		panel.setLayout(new BorderLayout());
  		// Create GUI layout for point name editor
  		JPanel centrePanel = new JPanel();
  		centrePanel.setLayout(new BorderLayout(8, 8));
  		centrePanel.add(new JLabel(I18nManager.getText("dialog.pointnameedit.name") + ": "), BorderLayout.WEST);
  		// Make listener to react to ok being pressed
  		_nameField = new JTextField("", 12);
  		_nameField.addKeyListener(new KeyAdapter() {
  			public void keyReleased(KeyEvent e)
  			{
  				// close dialog if escape pressed
  				if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
  					_dialog.dispose();
  				}
  				// Enable ok button if name changed
  				_okButton.setEnabled(hasNameChanged());
  			}
  		});
  		_nameField.addActionListener(e -> confirmEdit());
  		centrePanel.add(_nameField, BorderLayout.CENTER);
  		// holder panel to stop the text box from being stretched
  		JPanel holderPanel = new JPanel();
  		holderPanel.setLayout(new BorderLayout());
  		holderPanel.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
  		holderPanel.add(centrePanel, BorderLayout.NORTH);
  		panel.add(holderPanel, BorderLayout.CENTER);
  		JPanel rightPanel = new JPanel();
  		rightPanel.setLayout(new BoxLayout(rightPanel, BoxLayout.Y_AXIS));
  		JButton upperButton = new JButton(I18nManager.getText("dialog.pointnameedit.uppercase"));
  		upperButton.addActionListener(e -> changeCase(CaseOperation.UPPER_CASE));
  		rightPanel.add(upperButton);
  		JButton lowerButton = new JButton(I18nManager.getText("dialog.pointnameedit.lowercase"));
  		lowerButton.addActionListener(e -> changeCase(CaseOperation.LOWER_CASE));
  		rightPanel.add(lowerButton);
  		JButton titleButton = new JButton(I18nManager.getText("dialog.pointnameedit.titlecase"));
  		titleButton.addActionListener(e -> changeCase(CaseOperation.TITLE_CASE));
  		rightPanel.add(titleButton);
  		panel.add(rightPanel, BorderLayout.EAST);
  		// Bottom panel for OK, cancel buttons
  		JPanel lowerPanel = new JPanel();
  		lowerPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
  		JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
  		cancelButton.addActionListener((e) -> _dialog.dispose());
  		lowerPanel.add(cancelButton);
  		_okButton = new JButton(I18nManager.getText("button.ok"));
  		_okButton.setEnabled(false);
  		_okButton.addActionListener(e -> confirmEdit());
  		lowerPanel.add(_okButton);
  		panel.add(lowerPanel, BorderLayout.SOUTH);
  		return panel;
  	}
  
  
  	/**
  	 * Change the case of the name
  	 * @param caseOp operation to perform, upper/lower/title
  	 */
  	private void changeCase(CaseOperation caseOp)
  	{
  		String name = _nameField.getText();
  		switch (caseOp) {
  			case UPPER_CASE:
  				name = name.toUpperCase();
  				break;
  			case LOWER_CASE:
  				name = name.toLowerCase();
  				break;
  			case TITLE_CASE:
  				name = titleCase(name);
  				break;
  		}
  		_nameField.setText(name);
  		_okButton.setEnabled(true);
  		_nameField.requestFocus();
  	}
  
  	/**
  	 * Reset the dialog with the given name
  	 * @param inName waypoint name
  	 */
  	private void resetDialog(String inName)
  	{
  		_nameField.setText(inName);
  		_okButton.setEnabled(false);
  	}
  
  	/**
  	 * Turn a String into title case by capitalizing each word
  	 * @param inString String to convert
  	 * @return capitalized String
  	 */
  	static String titleCase(String inString)
  	{
  		// Check first for empty strings
  		if (inString == null || inString.equals("")) {
  			return "";
  		}
  		StringBuilder buffer = new StringBuilder();
  		// loop through characters
  		char lastChar = ' ';
  		for (int i=0; i<inString.length(); i++)
  		{
  			char currChar = inString.charAt(i);
  			buffer.append(lastChar == ' ' ? Character.toUpperCase(currChar) : Character.toLowerCase(currChar));
  			lastChar = currChar;
  		}
  		return buffer.toString();
  	}
  
  
  	/**
  	 * Confirm the edit and execute the command
  	 */
  	private void confirmEdit()
  	{
  		// Check whether name has really changed
  		if (!hasNameChanged()) {
  			return;
  		}
  		String newName = _nameField.getText().trim();
  		String displayName = (newName.isEmpty() ? _point.getWaypointName() : newName);
  		int pointIndex = _app.getTrackInfo().getSelection().getCurrentPointIndex();
  		EditPointCmd command = new EditPointCmd(pointIndex, new FieldEdit(Field.WAYPT_NAME, newName));
  		command.setDescription(I18nManager.getText("undo.editpoint.withname", displayName));
  		command.setConfirmText(I18nManager.getText("confirm.point.edit"));
  		_app.execute(command);
  
  		_dialog.dispose();
  	}
  
  	/**
  	 * Check whether the name has been changed or not
  	 * @return true if the new name is different
  	 */
  	private boolean hasNameChanged()
  	{
  		String prevName = _point.getWaypointName();
  		String newName = _nameField.getText().trim();
  		boolean prevNull = (prevName == null || prevName.equals(""));
  		boolean newNull = (newName == null || newName.equals(""));
  		return (prevNull && !newNull)
  			|| (!prevNull && newNull)
  			|| (!prevNull && !newNull && !prevName.equals(newName));
  	}
  }
  