Package org.openquark.gems.client

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

/*
* 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.
*/


/*
* IntellicutListRenderer.java
* Creation date: Jun 16, 2003
* By: Frank Worsley
*/
package org.openquark.gems.client;

import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.util.HashMap;
import java.util.Map;

import javax.swing.DefaultListCellRenderer;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JList;
import javax.swing.SwingUtilities;

import org.openquark.cal.services.GemEntity;
import org.openquark.gems.client.AutoburnLogic.AutoburnUnifyStatus;
import org.openquark.gems.client.IntellicutListModelAdapter.IntellicutListEntry;
import org.openquark.gems.client.IntellicutManager.IntellicutInfo;
import org.openquark.gems.client.IntellicutManager.IntellicutMode;
import org.openquark.util.ui.UIUtilities;


/**
* The cell renderer for the intellicut list.
*
@author Frank Worsley
*/
public class IntellicutListRenderer extends DefaultListCellRenderer {

    private static final long serialVersionUID = -9074143759683342266L;

    /** The background color of list items that are not selected. */
    static final Color NORMAL_BACKGROUND_COLOR = Color.WHITE;
   
    /** The background color of list items that are selected. */
    static final Color SELECTED_BACKGROUND_COLOR = Color.BLUE.darker().darker();
   
    /** The background color if the list item is transparent and not selected. */
    static final Color TRANSPARENT_BACKGROUND_COLOR = new Color(0, 0, 0, 0);

    /** The background color if the list item is transparent and selected. */
    static final Color SELECTED_TRANSPARENT_BACKGROUND_COLOR = new Color(100, 150, 255, 100);
   
    /** The text highlight colour for non selected items. */
    static final Color HIGHLIGHT_COLOR = Color.MAGENTA.darker();
   
    /** The text highlight colour for selected items. */
    static final Color SELECTED_HIGHTLIGHT_COLOR = Color.ORANGE;
   
    /** The text color for normal items. */
    static final Color TEXT_COLOR = Color.BLACK;
   
    /** The text color for selected items. */
    static final Color SELECTED_TEXT_COLOR = Color.WHITE;
   
    /** The text color for transparent items. */
    static final Color TRANSPARENT_TEXT_COLOR = Color.BLACK;
   
    /** The text color for selected transparent items. */
    static final Color SELECTED_TRANSPARENT_TEXT_COLOR = Color.WHITE;
   
    /** The outline color for transparent non selected items. */
    static final Color OUTLINE_COLOR = new Color(250, 250, 250, 100);

    /** The outline color for transparent selected items. */
    static final Color SELECTED_OUTLINE_COLOR = new Color(80, 130, 255, 100);
   
    /** The size of the glowing outline drawn around text if the list is transparent. */
    private static final int OUTLINE_SIZE = 2;
       
    /** The list entry this renderer is rendering. */
    private IntellicutListEntry listEntry;
      
    /**
     * The list this renderer is used for. This may not be an IntellicutList since
     * this renderer is also used for the normal JList of the IntellicutComboBox.
     */
    private JList intellicutList;

    /** Whether or not this item is selected. */
    private boolean selected;
       
    /** Whether or not this item is transparent. */
    private boolean transparent;

    /** Scope decal */
    private static final ImageIcon SCOPE_PRIVATE_ICON = new ImageIcon(TableTop.class.getResource("/Resources/intellicut_private.gif"));
    private static final ImageIcon SCOPE_PROTECTED_ICON = new ImageIcon(TableTop.class.getResource("/Resources/intellicut_protected.gif"));
    private static final ImageIcon SCOPE_PUBLIC_ICON = new ImageIcon(TableTop.class.getResource("/Resources/intellicut_public.gif"));
   
    // Icons for when only displaying scope icons
    private ImageIcon emitterIcon = null;
    private ImageIcon reflectorIcon = null;
   
    private ImageIcon scopePrivateIcon = null;
    private ImageIcon scopeProtectedIcon = null;
    private ImageIcon scopePublicIcon = null;
  
    // Icons for when displaying both burning status and scope
    private ImageIcon burnImageIcon = null;
    private ImageIcon burnQuestionIcon = null;
    private ImageIcon blankImageIcon = null;
   
    private ImageIcon emitterIcon_shifted = null;
    private ImageIcon reflectorIcon_shifted = null;
  
    private ImageIcon scopePrivateIcon_shifted = null;
    private ImageIcon scopeProtectedIcon_shifted = null;
    private ImageIcon scopePublicIcon_shifted = null;
   
    /** Cache for the scope decorated icons */
    private final Map<Icon, Icon> imageCache_public = new HashMap<Icon, Icon>();
    private final Map<Icon, Icon> imageCache_protected = new HashMap<Icon, Icon>();
    private final Map<Icon, Icon> imageCache_private = new HashMap<Icon, Icon>();

    /** Where the intellicut is activated */
    private final IntellicutMode intellicutMode;
 

    /**
     * @param list the IntellicutList the renderer will be used for
     * @param value the list entry item that should be rendered
     * @param index the index of the item in the model
     * @param isSelected true if the item is selected
     * @param cellHasFocus true if the item has focus
     * @return Component the component to use for rendering the list cell with the given values.
     */
    @Override
    public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
        
        this.listEntry = (IntellicutListEntry) value;
        this.intellicutList = list;
        this.selected = isSelected;
       
        if (list instanceof IntellicutList) {
            transparent = ((IntellicutList) list).isTransparent();
        } else {
            // If the list is actually the JList in the IntellicutComboBox
            transparent = false;
        }

        setText(listEntry.getDisplayString());
       
        // Choose the correct background color
        if (transparent) {
            setBackground(selected ? SELECTED_TRANSPARENT_BACKGROUND_COLOR : TRANSPARENT_BACKGROUND_COLOR);
        } else {
            setBackground(selected ? SELECTED_BACKGROUND_COLOR : NORMAL_BACKGROUND_COLOR);
        }
       
        // Looks better with a narrower gap (default is 4)
        setIconTextGap(2);
        setIcon(getIconForEntry(listEntry));
       
        return this;
    }
   
    /** Constructor */
    public IntellicutListRenderer(IntellicutMode mode) {
        createIcons();
        intellicutMode = mode;
    }
   
    /**
     * Creates images for the icons used by this list
     */
    private void createIcons() {
        // Icons for when only displaying scope icons
        emitterIcon = createCenteredIcon(TableTopPanel.emitterImageIconSmall);
        reflectorIcon = createCenteredIcon(TableTopPanel.reflectorImageIconSmall);
       
        scopePrivateIcon = createCenteredIcon (SCOPE_PRIVATE_ICON);
        scopeProtectedIcon = createCenteredIcon (SCOPE_PROTECTED_ICON);
        scopePublicIcon = createCenteredIcon (SCOPE_PUBLIC_ICON);
       
        // Icons for when displaying both burning status and scope
        blankImageIcon = createCroppedAndCenteredIcon(TableTopPanel.blankImageIconSmall);       
        burnImageIcon = createCroppedAndCenteredIcon(TableTopPanel.burnImageIconSmall);
        burnQuestionIcon = createCroppedAndCenteredIcon(TableTopPanel.burnQuestionImageIconSmall);
       
        emitterIcon_shifted = createShiftedIcon(TableTopPanel.emitterImageIconSmall);
        reflectorIcon_shifted = createShiftedIcon(TableTopPanel.reflectorImageIconSmall);
       
        scopePrivateIcon_shifted = createShiftedIcon (SCOPE_PRIVATE_ICON);
        scopeProtectedIcon_shifted = createShiftedIcon (SCOPE_PROTECTED_ICON);
        scopePublicIcon_shifted = createShiftedIcon (SCOPE_PUBLIC_ICON);

    }
   
    /**
     * Takes a small icon image, and vertically centers it so that the new icon fits within the dimensions of a row label.
     * @param icon
     * @return new icon
     */
    private ImageIcon createCenteredIcon(ImageIcon icon) {
        int height = this.getFontMetrics(this.getFont()).getHeight();
        // The image will be shifted down so that it is vertically centered, then padded at the bottom to match the required height
        Image newImage = UIUtilities.cropImage(UIUtilities.shiftImage(icon.getImage(), 0, ((height - icon.getIconHeight())/2 - 1)), 0, 0, 0, -1 * ((height - icon.getIconHeight())/2 + 1));
        return new ImageIcon(newImage);
    }
   
    /**
     * Takes a small icon image, vertically centers it so that the new icon fits within the dimensions of a row label.
     * Then crop 2 pixels on the left side of the image for better appearance
     * @param icon
     * @return new icon
     */
    private ImageIcon createCroppedAndCenteredIcon(ImageIcon icon) {
        int height = this.getFontMetrics(this.getFont()).getHeight();
        // The image will be shifted down so that it is vertically centered, then padded at the bottom to match the required height
        Image newImage = UIUtilities.cropImage(UIUtilities.shiftImage(icon.getImage(), 0, ((height - icon.getIconHeight())/2 - 1)), 2, 0, 0, -1 * ((height - icon.getIconHeight())/2 + 1));
        return new ImageIcon(newImage);
    }
   
   
    /**
     * Takes a small icon image and make room on the left for combining with the burning status icons.
     * @param icon
     * @return new icon the icon that has enough padding on the left to fit another icon
     */
    private ImageIcon createShiftedIcon(ImageIcon icon) {
        Image newImage = UIUtilities.cropImage(icon.getImage(), -10, 0, 0, 0 );
        return new ImageIcon(newImage);
    }

    /**
     * Determines the burning icon that should be used for a list entry.
     * @param listEntry the intellicut entry to get the icon for
     * @return the burning icon to use or a blank image for no burning icon
     */
    private Icon getBurnImageForEntry(IntellicutListEntry listEntry) {

        IntellicutInfo intellicutInfo = listEntry.getIntellicutInfo();
        AutoburnUnifyStatus burnStatus = intellicutInfo.getAutoburnUnifyStatus();

        if (burnStatus == AutoburnUnifyStatus.UNAMBIGUOUS) {
            return burnImageIcon;

        } else if (burnStatus == AutoburnUnifyStatus.NOT_NECESSARY) {
            return blankImageIcon;

        } else if (burnStatus == AutoburnUnifyStatus.AMBIGUOUS) {
            return burnQuestionIcon;

        } else if (burnStatus == AutoburnUnifyStatus.UNAMBIGUOUS_NOT_NECESSARY) {
            if (intellicutInfo.getBurnTypeCloseness() > intellicutInfo.getNoBurnTypeCloseness()) {
                return burnImageIcon;
            }

        } else if (burnStatus == AutoburnUnifyStatus.AMBIGUOUS_NOT_NECESSARY) {
            if (intellicutInfo.getBurnTypeCloseness() > intellicutInfo.getNoBurnTypeCloseness()) {
                return burnQuestionIcon;
            }
        }
        return blankImageIcon;
    }       

    /**
     * Determines the icon for the entry. The scoped entry icon could be a scope icon only or scope icon plus burn status icon,
     * depending on which part the intellicut was activated on.
     * @param listEntry the intellicut entry to get the icon for
     * @return icon with scope (and burn status) or the appropriate icon for non-scoped entry
     */
    public Icon getIconForEntry(IntellicutListEntry listEntry) {
       
        // Overlays the burn status image and scope icon only if intellicut is activated on an input part
        if (intellicutMode == IntellicutMode.PART_INPUT) {
            return getIconWithBurnStatus(listEntry);

        } else {// (intellicutMode == IntellicutMode.PART_OUTPUT || intellicutMode == IntellicutMode.NOTHING
            return getIconWithoutBurnStatus(listEntry);

        }
    }
   
    /**
     * Determines the icon for the entry where the left column is the burn status icon and the right column is the scope icon.
     * Non-scoped entry returns the appropriate gem type icon.
     * @param listEntry
     * @return Icon an combined icon with burn status and scope
     */
    private Icon getIconWithBurnStatus(IntellicutListEntry listEntry) {

        Object listData = listEntry.getData();

        // Retrieve the top layer of the icon
        Icon overlayImage = getBurnImageForEntry(listEntry);

        // Add scope decal (public, protected, private) underneath if entry is scoped
        if (listData instanceof GemEntity) {
            // Uses cache to store icons already combined
            GemEntity entity = (GemEntity) listData;
            Icon baseGemIcon = null;
            Icon overlayIcon = overlayImage;
            Map<Icon, Icon> cache = null;

            if (entity.getScope().isPublic()) {
                cache = imageCache_public;
                baseGemIcon = scopePublicIcon_shifted;

            } else if (entity.getScope().isProtected()) {
                cache = imageCache_protected;
                baseGemIcon = scopeProtectedIcon_shifted;

            } else { // entity.getScope().isPrivate()
                cache = imageCache_private;
                baseGemIcon = scopePrivateIcon_shifted;
            }

            Icon cachedImage = cache.get(overlayIcon);
            if (cachedImage != null) {
                return cachedImage;

            } else {
                Icon newIcon = UIUtilities.combineIcons(baseGemIcon, overlayIcon);
                cache.put(overlayIcon, newIcon);
                return newIcon;
            }

        } else if (listData instanceof CollectorGem) {
            return ((CollectorGem) listData).getReflectedInputs().isEmpty() ? emitterIcon_shifted : reflectorIcon_shifted;
        }

        return blankImageIcon;
    }
   
    /**
     * Determines the icon for the list entry without any burn status icons. Non-scoped entry returns the appropriate gem type icon.
     * @param listEntry
     * @return Icon Either a scope icon or the appropriate gem type icon
     */
    private Icon getIconWithoutBurnStatus(IntellicutListEntry listEntry) {

        Object listData = listEntry.getData();

        if (listData instanceof GemEntity) {
            GemEntity entity = (GemEntity) listData;
            if (entity.getScope().isPublic()) {
                return scopePublicIcon;
            } else if (entity.getScope().isProtected()) {
                return scopeProtectedIcon;
            } else {
                return scopePrivateIcon;
            }
        } else if (listData instanceof CollectorGem) {
            return ((CollectorGem) listData).getReflectedInputs().isEmpty() ? emitterIcon : reflectorIcon;
        }

        return blankImageIcon;
    }
   
   
    /**
     * This is needed so that drawing the label works correctly. We have to always
     * fill in our background so that the list updates correctly if we scroll.
     * @param g the graphics object to draw with
     */
    @Override
    public void paintComponent(Graphics g) {
       
        g.setColor(getBackground());
        g.fillRect(0, 0, getWidth(), getHeight());
       
        super.paintComponent(g);
    }
   
    /**
     * Overloaded paint function to draw our custom highlighted text.
     * @param g the graphics object to draw with
     */
    @Override
    public void paint(Graphics g) {
       
        Insets insets = getInsets();
        Icon icon = getIcon();
        int iconWidth = icon != null ? icon.getIconWidth() : 0;
       
        String text1 = listEntry.getDisplayString();
        String text2 = " (" + listEntry.getSecondaryDisplayString() + ")";
        if (text2.length() == 3) {
            text2 = "";
        }
        Graphics2D g2 = (Graphics2D) g;
       
        /////////////////////
        // TODO: Module name should be de-emphasized from regular name,
        //       but still attract attention. The following variables are
        //       here to assist in selection of this font.

        Font textFont = getFont().deriveFont(Font.PLAIN ).deriveFont(getFont().getSize2D()-0.0f);
        Font text2Font = (getFont().deriveFont( Font.PLAIN ).deriveFont(getFont().getSize2D()-0.0f));
        //LinkedHashMap attributes = new LinkedHashMap();
        //attributes.put(TextAttribute.WIDTH, TextAttribute.WIDTH_CONDENSED);
        //attributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_ULTRABOLD );
        //text2Font = text2Font.deriveFont(attributes);
        //text2Font = text2Font.deriveFont(new AffineTransform(0.9,0.0,0.0,1.0,0.0,0.0));
        Object textRenderHint = (RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
        Object text2RenderHint = (RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
        Color text2Color = selected ? SELECTED_TEXT_COLOR : new Color(10, 10, 10, 190);
        Color outline2Color = selected ? SELECTED_OUTLINE_COLOR : OUTLINE_COLOR;//new Color(240, 240, 240, 100); // 100
           
        ////////////////////

        // draw in the background
        g2.setColor(getBackground());
        g2.fillRect(0, 0, getWidth(), getHeight());

        // draw in the icon
        if (icon != null) {
            icon.paintIcon(this, g2, insets.left, insets.top);
        }

        // figure out the text color
        Color textColor = selected ? SELECTED_TEXT_COLOR : TEXT_COLOR;
        if (transparent) {
            textColor = selected ? SELECTED_TRANSPARENT_TEXT_COLOR : TRANSPARENT_TEXT_COLOR;
        }

        // get ready to draw the text           
        g2.setFont(textFont);
        g2.setColor(textColor);
       
        final int xOffset = insets.left + iconWidth + getIconTextGap();
        final int yOffset = getHeight() - getFontMetrics(textFont).getDescent() - insets.bottom + OUTLINE_SIZE;
        final int xOffset2 = xOffset + SwingUtilities.computeStringWidth(getFontMetrics(textFont), text1+" ");
       
        // draw an outline for non-selected text if the item is transparent.
        if (transparent) {

            Color outlineColor = selected ? SELECTED_OUTLINE_COLOR : OUTLINE_COLOR;
            g2.setColor(outlineColor);
            g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
           
            for (int x = 0, xmax = 2 * OUTLINE_SIZE; x <= xmax; x++) {
                for (int y = 0, ymax = 2 * OUTLINE_SIZE; y <= ymax; y++) {
                    g2.drawString(text1, xOffset + x, yOffset - y);                           
                }
            }
           
            g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
            g2.setColor(outline2Color);
            g2.setFont(text2Font);
            for (int x = 0, xmax = 0+2*OUTLINE_SIZE; x <= xmax; x++) {
                for (int y = 0, ymax = 0+2*OUTLINE_SIZE; y <= ymax; y++) {
                    g2.drawString(text2, xOffset2 + x, yOffset - y);
                }
            }
           
            g2.setFont(textFont);
            g2.setColor(textColor);
            g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, textRenderHint);
        }

        // draw the main string
        g2.drawString(text1, xOffset + OUTLINE_SIZE, yOffset - OUTLINE_SIZE);
       
        g2.setColor(text2Color);
        g2.setFont(text2Font);
        g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, text2RenderHint);
        g2.drawString(text2, xOffset2 + OUTLINE_SIZE, yOffset - OUTLINE_SIZE);
        g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
        g2.setFont(textFont);
        g2.setColor(textColor);
       
        // draw the letters the user has entered in a different color
        String userInput = ((IntellicutListModel) intellicutList.getModel()).getUserInput();
        String textToMatch = listEntry.getDisplayString();
       
        if (userInput.length() > 0 && userInput.length() <= textToMatch.length() &&
            textToMatch.substring(0, userInput.length()).equalsIgnoreCase(userInput)) {
           
            Color typedCharactersColor = selected ? SELECTED_HIGHTLIGHT_COLOR : HIGHLIGHT_COLOR;
            g2.setColor(typedCharactersColor);
           
            int index = text1.length() - textToMatch.length();
            int prefixWidth = 0;
           
            if (index > 0) {
                String prefix = getText().substring(0, index);
                prefixWidth = SwingUtilities.computeStringWidth(getFontMetrics(getFont()), prefix);
            }
           
            String highlight = text1.substring(index, index + userInput.length());
            g2.drawString(highlight, xOffset + OUTLINE_SIZE + prefixWidth, yOffset - OUTLINE_SIZE);
           
        }           
    }
}
TOP

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

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.