/** * Copyright 2014 Comcast Cable Communications Management, LLC * * This file is part of CATS. * * CATS is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * CATS 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 for more details. * * You should have received a copy of the GNU General Public License * along with CATS. If not, see <http://www.gnu.org/licenses/>. */ package com.comcast.cats.vision.panel.remote; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.Point; import java.awt.event.MouseListener; import java.util.ArrayList; import java.util.List; import javax.swing.Action; import javax.swing.ActionMap; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.InputMap; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.KeyStroke; import org.apache.log4j.Logger; import com.comcast.cats.RemoteCommand; import com.comcast.cats.RemoteLayout; /** * | The view logic of the remote control in CATS Vision * * @author bemman01c * */ public class RemoteControlView extends JPanel { private static final long serialVersionUID = -758016305574347046L; private static final Integer REMOTE_PANEL_WIDTH = 275; private static final Integer REMOTE_PANEL_HEIGHT = 400; public static final Font DEFAULT_FONT = new Font( "Serif", Font.ITALIC, 24 ); private static final Dimension REMOTE_PANEL_DIMENSION = new Dimension( REMOTE_PANEL_WIDTH, REMOTE_PANEL_HEIGHT ); private CounterPanel pressAndHoldPanel; private static final String ACTION_KEY = "actioned"; /** * Logger instance for RemotePanel. */ private static final Logger logger = Logger.getLogger( RemoteControlView.class ); /** * The the handler to take care of key events. */ private Object handler; /** * Name of this view panel */ String name; /** * All the remote button grouping panels. */ private List< ButtonPanel > panels; /** * Direct Tune Panel */ protected DirectTunePanel directTunePanel; List< RemoteLayout > keys = null; /** Creates a Remote panel with the help of a handler */ public RemoteControlView( Object handler, String panelName, List< RemoteLayout > keys ) { this.handler = handler; this.name = panelName; this.keys = keys; initComponents(); clearPanels(); this.setVisible( true ); } /** * Place holder for chaning remote layout */ public void setRemoteLayout( List< RemoteLayout > keys ) { /** * TODO: In future this can be used to change the remote based on the * remote type. * * We have to clear the current remote pannel, add the new buttons and * repaint() */ this.keys = keys; } /** * initialize the view */ private void initComponents() { setName( name ); setRemoteControlLook(); pressAndHoldPanel = new CounterPanel(); add( pressAndHoldPanel ); } /** * Method sets the size color and shape of the remote control */ public void setRemoteControlLook() { setMinimumSize( REMOTE_PANEL_DIMENSION ); setPreferredSize( REMOTE_PANEL_DIMENSION ); setSize( REMOTE_PANEL_DIMENSION ); setLayout( new BoxLayout( this, BoxLayout.Y_AXIS ) ); setBorder( BorderFactory.createLineBorder( Color.BLACK, 1 ) ); setBackground( Color.LIGHT_GRAY ); } /** * Adds a Direct tune panel to this view * * @param directTunePanel */ public void addDirectTunePanel( DirectTunePanel directTunePanel ) { this.directTunePanel = directTunePanel; } private void addDirectTunePanelToRemoteView() { this.add( directTunePanel ); } /** * instatiates the button layout on the view with the key list and the * dierct tune panel */ public void performRemoteButtonLayout() { Integer panelCount = getPanelCount( keys ); /** * Set the array size to be the panel count. */ panels = new ArrayList< ButtonPanel >( panelCount ); GridBagConstraints gbc = new GridBagConstraints(); gbc.fill = GridBagConstraints.NONE; gbc.anchor = GridBagConstraints.NORTH; // For Direct Tune addDirectTunePanelToRemoteView(); /** * Create new JPanels to hold buttons and add all the panels to the main * panel. */ for ( int p = 0; p < panelCount; p++ ) { ButtonPanel panel = new ButtonPanel(); panel.setVisible( true ); panels.add( p, panel ); // gbc.gridy = p; // // this.add(panel, margin); // this.add(panel, gbc); this.add( panel ); } logger.debug( "panelCount = " + panelCount ); logger.debug( "Panels = " + panels.size() ); // Put this around row to give bottom padding. for ( RemoteLayout key : keys ) { ButtonPanel p = panels.get( key.getPanel() ); addRemoteButtonToPanel( p, key ); } } private void clearPanels() { if ( null != panels ) { this.panels.clear(); } } private void addRemoteButtonToPanel( ButtonPanel panel, RemoteLayout key ) { RemoteButton rb = new RemoteButton( key ); // This panel should be the action listener for button presses. // rb.addActionListener(this); rb.addMouseListener( ( MouseListener ) handler ); rb.setFocusable( false ); setKeyBoardShortCut( rb ); panel.addButtonToPanel( rb ); } private void setKeyBoardShortCut( RemoteButton remoteButton ) { String buttonText = remoteButton.getText(); if ( ( buttonText == RemoteCommand.ZERO.toString() ) || ( buttonText == RemoteCommand.ONE.toString() ) || ( buttonText == RemoteCommand.TWO.toString() ) || ( buttonText == RemoteCommand.THREE.toString() ) || ( buttonText == RemoteCommand.FOUR.toString() ) || ( buttonText == RemoteCommand.FIVE.toString() ) || ( buttonText == RemoteCommand.SIX.toString() ) || ( buttonText == RemoteCommand.SEVEN.toString() ) || ( buttonText == RemoteCommand.EIGHT.toString() ) || ( buttonText == RemoteCommand.NINE.toString() ) ) { setInputAndActionMap( remoteButton, buttonText ); } if ( ( buttonText == RemoteCommand.VOLUP.toString() ) ) { setInputAndActionMap( remoteButton, "PERIOD" ); // corresponds to > setInputAndActionMap( remoteButton, "GREATER" ); } else if ( ( buttonText == RemoteCommand.VOLDN.toString() ) ) { setInputAndActionMap( remoteButton, "COMMA" ); // corresponds to < setInputAndActionMap( remoteButton, "LESS" ); } else if ( ( buttonText == RemoteCommand.CHUP.toString() ) ) { setInputAndActionMap( remoteButton, "EQUALS" ); // corresponds to + } else if ( ( buttonText == RemoteCommand.CHDN.toString() ) ) { setInputAndActionMap( remoteButton, "MINUS" ); } else if ( ( buttonText == RemoteCommand.MENU.toString() ) ) { setInputAndActionMap( remoteButton, "M" ); setInputAndActionMap( remoteButton, "m" ); } else if ( ( buttonText == RemoteCommand.INFO.toString() ) ) { setInputAndActionMap( remoteButton, "I" ); setInputAndActionMap( remoteButton, "i" ); } else if ( ( buttonText == RemoteCommand.GUIDE.toString() ) ) { setInputAndActionMap( remoteButton, "G" ); setInputAndActionMap( remoteButton, "g" ); } else if ( ( buttonText == RemoteCommand.SELECT.toString() ) ) { setInputAndActionMap( remoteButton, "ENTER" ); } else if ( ( buttonText == RemoteCommand.EXIT.toString() ) ) { setInputAndActionMap( remoteButton, "ESCAPE" ); } else if ( ( buttonText == RemoteCommand.LAST.toString() ) ) { setInputAndActionMap( remoteButton, "BACK_SPACE" ); } else if ( ( buttonText == RemoteCommand.UP.toString() ) ) { setInputAndActionMap( remoteButton, "W" ); } else if ( ( buttonText == RemoteCommand.DOWN.toString() ) ) { setInputAndActionMap( remoteButton, "S" ); } else if ( ( buttonText == RemoteCommand.LEFT.toString() ) ) { setInputAndActionMap( remoteButton, "A" ); } else if ( ( buttonText == RemoteCommand.RIGHT.toString() ) ) { setInputAndActionMap( remoteButton, "D" ); } } private void setInputAndActionMap( RemoteButton remoteButton, String keyStroke ) { InputMap inputMap = remoteButton.getInputMap(); inputMap = remoteButton.getInputMap( JComponent.WHEN_IN_FOCUSED_WINDOW ); inputMap.put( KeyStroke.getKeyStroke( keyStroke ), ACTION_KEY ); inputMap.put( KeyStroke.getKeyStroke( "shift " + keyStroke ), ACTION_KEY ); ActionMap actionMap = remoteButton.getActionMap(); actionMap.put( ACTION_KEY, ( Action ) handler ); } private Integer getPanelCount( List< RemoteLayout > keys ) { Integer panelCount = -1; for ( RemoteLayout key : keys ) { if ( key.getPanel() > panelCount ) { panelCount = key.getPanel(); } } // Adjust the panel by one to account for the zero start. return panelCount + 1; } /** * Get the location to show the press and hold visualization. Adds any * offset, corrections to make sure that the panel is visible, provided it * has the space to be shown fully. * * @param point * - the point where mouse clicked. * @param xOffset * - any x offset * @param yOffset * - any y offset * @return - the point where to position the press and hold panel. */ protected Point getPressAndHoldPanelLocation( Point point, int xOffset, int yOffset ) { int x = point.x; int y = point.y; // if the panel width will fall out of bounds of the remote panel, // negate the width to make the panel fall within bounds. if ( ( x + pressAndHoldPanel.getPreferredSize().width ) > getWidth() ) { x = x - pressAndHoldPanel.getPreferredSize().width - xOffset; } else { x += xOffset; } if ( ( y + pressAndHoldPanel.getHeight() ) > getHeight() ) { y = y - pressAndHoldPanel.getHeight() - yOffset; } else { y += yOffset; } // finally adjust x and y to zero if they are negative and hence out of // bounds. x = ( x < 0 ) ? 0 : x; y = ( x < 0 ) ? 0 : y; return new Point( x, y ); } /** * notify the view to show the pressAndHoldPanel */ public void showPressAndHoldPanel( Point mousePosition, JButton button ) { Point panelPosition = getPressAndHoldPanelLocation( mousePosition, 0, button.getHeight() ); // provide pressAndHoldPanel.setLocation( panelPosition.x, panelPosition.y ); pressAndHoldPanel.showCounterPanel( CounterPanel.COUNT_MODE ); } /** * Hide the press and Hold panel. */ protected void hidePressAndHoldPanel() { pressAndHoldPanel.hideCounterPanel(); this.repaint(); } }