Package org.openquark.gems.client

Source Code of org.openquark.gems.client.RecordFieldRenameEditor

/*
* Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
*     * Redistributions of source code must retain the above copyright notice,
*       this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in the
*       documentation and/or other materials provided with the distribution.
*     * Neither the name of Business Objects nor the names of its contributors
*       may be used to endorse or promote products derived from this software
*       without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

/*
* RecordFieldRenameEditor.java
* Creation date: Oct 4, 2007
* By: Jennifer Chen
*/

package org.openquark.gems.client;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.List;
import java.util.Map;

import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;

import org.openquark.cal.compiler.FieldName;
import org.openquark.cal.compiler.LanguageInfo;
import org.openquark.gems.client.Gem.PartInput;
import org.openquark.gems.client.utilities.ExtendedUndoManager;

/**
* This class is responsible for displaying the correct field name editor for a given Record Creation Gem.
* The editor is specific to the field which it is activated on
*
* @author Jennifer Chen
*/

public class RecordFieldRenameEditor extends EditableIdentifierNameField {

    private static final long serialVersionUID = -5205246630972127102L;

    /** The RecordCreationGem Gem for this editor  */
    private RecordCreationGem rcGem;

    /** The original field name before edit */
    private final String oldFieldName;

    /** The list of existing names which the new name cannot overlap with*/
    private final List<String> restrictedFieldNames;

    /** Saves the previous state of field name and inputs before the edit */
    private final Map<String, PartInput> fieldToInputMap;

    /** TableTop reference */
    private final TableTop tableTop;

    /** The undo manager for this text field */
    private ExtendedUndoManager undoManager;

    /** Keeps track of whether this component has been removed from the tableTop */
    private boolean removed = false;

    /** Index of the field which we are modifying */
    private final int fieldIndex;

    public RecordFieldRenameEditor(RecordCreationGem rcGem, FieldName fieldToRename, TableTop tabletop) {
        super();

        this.rcGem = rcGem;
        this.tableTop = tabletop;
        this.fieldToInputMap = rcGem.getFieldNameToInputMap();
        this.oldFieldName = fieldToRename.getCalSourceForm();
        this.restrictedFieldNames = rcGem.getCopyOfFieldsList();
        this.fieldIndex = restrictedFieldNames.indexOf(oldFieldName);

        // set the initial text
        setInitialText(oldFieldName);
        setText(oldFieldName);

        // set the font of the text
        setFont(GemCutterPaintHelper.getTitleFont());

        // update the size of the text area to reflect the size of the text
        updateSize();

        // starts out with all text selected
        selectAll();

        // set up the undo manager
        undoManager = new ExtendedUndoManager();
        getDocument().addUndoableEditListener(undoManager);

        // moving focus away commits the text entered and closes this component
        addFocusListener(new FocusAdapter() {
            @Override
            public void focusLost(FocusEvent e) {
                // Note: when user presses Enter, an actionPerformed() in EditableIdentifierNameField will cause a
                // commitText(), then the focusLost event will also commitText(). The extra commit is ok given that
                // the extra UndoEdit posted is removed. Therefore in the UndoableModifyRecordFieldEdit, we need to
                // implement the replaceEdit() method so there is only 1 edit for the rename action.

                commitText();
            }
        });

        // intercept some key events           
        addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                int keyCode = e.getKeyCode();

                // pressing "ESC" cancels text entry and closes this component
                if (keyCode == KeyEvent.VK_ESCAPE) {
                    cancelEntry();
                }

                KeyStroke keyStroke = KeyStroke.getKeyStrokeForEvent(e);

                // handle undo and redo
                if (keyStroke.equals(GemCutterActionKeys.ACCELERATOR_UNDO)) {
                    if (undoManager.canUndo()) {
                        undoManager.undo();
                        textChanged();
                    }
                    e.consume();

                } else if (keyStroke.equals(GemCutterActionKeys.ACCELERATOR_REDO)) {
                    if (undoManager.canRedo()) {
                        undoManager.redo();
                        textChanged();
                    }
                    e.consume();

                } else if (keyStroke.equals(GemCutterActionKeys.ACCELERATOR_ARRANGE_GRAPH) || keyStroke.equals(GemCutterActionKeys.ACCELERATOR_FIT_TABLETOP)
                        || keyStroke.equals(GemCutterActionKeys.ACCELERATOR_NEW)) {

                    // We have to intercept accelerators for these so that the GemCutter
                    // doesn't get screwed up when the text field doesn't match the action result.
                    e.consume();
                }
            }
        });

        // ensure the cursor is visible when it moves
        addCaretListener(new CaretListener() {
            public void caretUpdate(CaretEvent e) {
                // just ensure the caret is visible
                scrollCaretToVisible();
            }
        });
    }

    @Override
    protected boolean isValidName(String name) {

        // String is not a valid field name
        if (!LanguageInfo.isValidFieldName(name)) {
            return false;
        }

        // Determine if the current input is duplicate to an existing name
        for (String tabooName : restrictedFieldNames) {
            if (tabooName.equals(name) && !name.equals(oldFieldName)) {
                return false;
            }
        }
        return true;
    }

    /**
     * Notify that the text of this text field has changed.  Called upon insertUpdate() and remove() completion.
     */
    @Override
    protected void textChanged() {
        super.textChanged();

        tableTop.resizeForGems();

        // ensure the caret is visible
        scrollCaretToVisible();

    }

    @Override
    protected void textChangeInvalid() {
        // Signal the user.
        setForeground(Color.lightGray);

        // Update the gem field name to display the new text (despite being invalid)
        updateFieldName(getText());

        // set a tooltip saying that the text is invalid
        String text = GemCutter.getResourceString("ToolTip_InvalidFieldName");
        String[] lines = ToolTipHelpers.splitTextIntoLines(text, 300, getFont(), ((Graphics2D)tableTop.getTableTopPanel().getGraphics()).getFontRenderContext());
        text = "<html>" + lines[0];
        for (int i = 1; i < lines.length; i++) {
            text += "<br>" + lines[i];
        }
        setToolTipText(text + "</html>");

        // update the text field to reflect the new size of the text
        updateSize();
    }

    @Override
    protected void textChangeValid() {
        setForeground(Color.black);

        // update the gem name to display the new text
        updateFieldName(getText());

        // clear any tooltip saying that the text is invalid
        setToolTipText(null);

        // update the text field to reflect the new size of the text
        updateSize();
    }

    @Override
    protected void textCommittedInvalid() {
        // revert changes
        rcGem.renameRecordField(fieldIndex, oldFieldName);

        // close this component
        closeField();
    }

    @Override
    protected void textCommittedValid() {
        // Update the gem name.
        String committedText = getText();
        updateFieldName(committedText);

        // close this component
        closeField();

        // Notify the undo manager of the name change, if any
        tableTop.updateForGemGraph();
        tableTop.getUndoableEditSupport().postEdit(new UndoableModifyRecordFieldEdit(rcGem, fieldToInputMap));

    }

    /**
     * @param newFieldName the new name for the field
     */
    private void updateFieldName(String newFieldName) {
        rcGem.renameRecordField(fieldIndex, newFieldName);
    }

    /**
     * Update the size of this field.
     */
    private void updateSize() {
        Insets insets = getInsets();

        // The X dimension is based on the size of the text for the name (plus some margins)
        FontMetrics fm = getFontMetrics(getFont());

        // Calculate width and height
        int newWidth = fm.stringWidth(getText()) + insets.right + insets.left + 1;
        int newHeight = fm.getHeight();

        setSize(new Dimension(newWidth, newHeight));

    }

    /**
     * Creates the default implementation of the model to be used at construction if one isn't explicitly given.
     * Overridden to return a LetterNumberUnderscorePoundDocument.
     * @return Document the default model implementation.
     */
    @Override
    protected Document createDefaultModel() {
        //Underscores are allowed for field names
        return new LetterNumberUnderscorePoundDocument();
    }

    /**
     * Cancel text entry (press "ESC" ..)
     */
    @Override
    protected void cancelEntry() {
        // Revert to the last valid name
        setText(getInitialText());

        textCommittedInvalid();
    }

    /**
     * If this has been placed in the tabletop, make sure the caret is visible
     */
    void scrollCaretToVisible() {
        if (tableTop.getTableTopPanel().isAncestorOf(this)) {
            int dotPos = getCaret().getDot();
            try {
                Rectangle caretRect = modelToView(dotPos);

                if (caretRect != null) {
                    caretRect.width += 1;
                    Rectangle convertedRect = SwingUtilities.convertRectangle(this, caretRect, tableTop.getTableTopPanel());
                    tableTop.getTableTopPanel().scrollRectToVisible(convertedRect);
                }
            } catch (BadLocationException e) {
                // Nowhere to scroll.  Oh well.
            }
        }
    }

    /**
     * Close this window (if not already gone..)
     */
    synchronized void closeField() {
        if (!removed) {
            removed = true;
            tableTop.getTableTopPanel().remove(this);
            tableTop.getTableTopPanel().repaint(RecordFieldRenameEditor.this.getBounds());

            // we have to do this or else you can just keep typing (..!)
            setEnabled(false);

            // Update the tabletop for the new gem graph state.
            //  Among other things, this will ensure arg name disambiguation with respect to the new collector name.
            tableTop.updateForGemGraph();
        }
        // trigger a focusLost() on this component if it had focus
        tableTop.getTableTopPanel().requestFocus();
    }
}
TOP

Related Classes of org.openquark.gems.client.RecordFieldRenameEditor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.