/** * 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.configuration; import static com.comcast.cats.vision.panel.configuration.ConfigConstants.LAUNCH_VIDEO; import static com.comcast.cats.vision.panel.configuration.ConfigConstants.REFRESH_SETTOP_LIST; import static com.comcast.cats.vision.panel.configuration.ConfigConstants.SEARCH_SETTOP; import static com.comcast.cats.vision.panel.configuration.ConfigConstants.SEARCH_TEXT_FIELD; import static com.comcast.cats.vision.panel.configuration.TableType.ALLOCATED_SETTOPS_TABLE; import static com.comcast.cats.vision.panel.configuration.TableType.AVAILABLE_SETTOPS_TABLE; import static com.comcast.cats.vision.panel.configuration.TableType.SETTOP_PROERTIES_TABLE; import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.MalformedURLException; import java.net.URISyntaxException; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Vector; import javax.inject.Inject; import javax.inject.Named; import javax.swing.JButton; import javax.swing.JTabbedPane; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.ListSelectionModel; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import org.apache.log4j.Logger; import com.comcast.cats.domain.SettopDesc; import com.comcast.cats.domain.SettopReservationDesc; import com.comcast.cats.domain.configuration.CatsProperties; import com.comcast.cats.event.impl.ManagedThreadPool; import com.comcast.cats.vision.panel.videogrid.VideoGridController; import com.comcast.cats.vision.task.MySettopsTask; import com.comcast.cats.vision.util.CatsVisionConstants; import com.comcast.cats.vision.util.CatsVisionUtils; /** * This class acts as the Controller for the Configuration module. * * @author ajith * */ @Named public class ConfigPanelController implements ListSelectionListener, ActionListener, MouseListener, ChangeListener { private ConfigPanel panel; private VideoGridController videoGridController; private ConfigPanelUtil configPanelUtil; private String authToken; private static final Logger logger = Logger.getLogger( ConfigPanelController.class ); private int selectedRow; private int[] indexRowsSelected = { -1 }; private ConfigPanelTableModel availableTableModel; private ConfigPanelTableModel allocatedTableModel; private JTable availableSettopsTable; private JTable allocatedSettopsTable; private ConfigModel configModel; private ManagedThreadPool managedThreadPool; private int hostMacIndex = 2; private int reservationIndex = 4; /** * Constructor for ConfigPanelController * * @param configPanel * instance of ConfigPanel * @param configModel * instance of ConfigModel * @param videoGridController * instance of VideoGridController * @param configPanelUtil * instance of ConfigPanelUtil * @param managedThreadPool * instance of ManagedThreadPool * @param catsProperties * instance of CatsProperties */ @Inject public ConfigPanelController( ConfigPanel configPanel, ConfigModel configModel, VideoGridController videoGridController, ConfigPanelUtil configPanelUtil, ManagedThreadPool managedThreadPool, CatsProperties catsProperties ) { this.panel = configPanel; this.videoGridController = videoGridController; this.authToken = catsProperties.getAuthToken(); this.configModel = configModel; this.configPanelUtil = configPanelUtil; this.managedThreadPool = managedThreadPool; initListeners(); } private void initListeners() { panel.addMouseListener( this ); panel.addActionListener( this ); panel.addChangeListener( this ); panel.addListSelectionListener( this ); } @Override public void valueChanged( ListSelectionEvent listSelectionEvent ) { if ( listSelectionEvent.getValueIsAdjusting() ) { return; } /* * To make the selection is empty */ selectedRow = -1; if ( indexRowsSelected.length > 0 ) { for ( int i = 0; i < indexRowsSelected.length; i++ ) { indexRowsSelected[ i ] = -1; } } final ListSelectionModel listSelectionModel = ( ListSelectionModel ) listSelectionEvent.getSource(); if ( !( listSelectionModel.isSelectionEmpty() ) ) { final Component selectedComponent = panel.getTabbedPane().getSelectedComponent(); if ( panel.getAvailableSettopsScrollPane().equals( selectedComponent ) ) { availableSettopsTable = panel.getAvailableSettopsTable(); indexRowsSelected = availableSettopsTable.getSelectedRows(); if ( indexRowsSelected.length == 1 ) { selectedRow = indexRowsSelected[ 0 ]; String key = availableSettopsTable.getValueAt( selectedRow, hostMacIndex ).toString(); // + availableSettopsTable.getValueAt( selectedRow, reservationIndex ).toString(); // Fill settop property table System.out.println("key "+key); fillPropertyValueTable( configModel.getAvailableSettops().get( key ) ); } else if ( indexRowsSelected.length > 1 ) { /* * Clear settop property table */ clearPropertyValueTable(); } /* * Find the selected Mac Ids and also remove the previously * selected mac Ids from the macIDMap. */ findSelectedMacIDs( getSearchKeyword() ); } else if ( panel.getAllocatedSettopsScrollPane().equals( selectedComponent ) ) { allocatedSettopsTable = panel.getAllocatedSettopsTable(); selectedRow = listSelectionModel.getMinSelectionIndex(); String key = allocatedSettopsTable.getValueAt( selectedRow, hostMacIndex ).toString() + allocatedSettopsTable.getValueAt( selectedRow, reservationIndex ).toString(); fillPropertyValueTable( configModel.getAllocatedSettops().get( key ) ); } panel.autoResizeTable( SETTOP_PROERTIES_TABLE ); } } /** * Method to fill the data in Available and Allocated JTables. This method * will be called during the start up of CATS Vision. */ public void fillConfigDataTables() { enableLaunchVideoButton(); fillAvailableSettopTab( authToken ); fillAllocatedSettopTab( authToken ); } private void updateTable() { // To clear the selected row in each of the tabs panel.getAvailableSettopsTable().clearSelection(); panel.getAllocatedSettopsTable().clearSelection(); configModel.getHighlightedRowMap().clear(); // Clearing the Property value table ConfigPanelTableModel tableModel = panel.getPropertyValueModel(); tableModel.getDataVector().removeAllElements(); panel.updateTableData( SETTOP_PROERTIES_TABLE, tableModel ); panel.autoResizeTable( SETTOP_PROERTIES_TABLE ); fillDataInSelectedTab( authToken ); } /** * Method to call appropriate method to fill data in JTable. */ private void fillDataInSelectedTab( String authToken ) { JTabbedPane resultsTabbedPane = panel.getTabbedPane(); final Component selectedComponent = resultsTabbedPane.getSelectedComponent(); if ( panel.getAvailableSettopsScrollPane().equals( selectedComponent ) ) { fillAvailableSettopTab( authToken ); } else if ( panel.getAllocatedSettopsScrollPane().equals( selectedComponent ) ) { fillAllocatedSettopTab( authToken ); } } private void enableLaunchVideoButton() { JTabbedPane resultsTabbedPane = panel.getTabbedPane(); final Component selectedComponent = resultsTabbedPane.getSelectedComponent(); if ( panel.getAvailableSettopsScrollPane().equals( selectedComponent ) ) { panel.getLaunchVideoButton().setEnabled( true ); panel.getLaunchVideoCheckBox().setEnabled( true ); } else if ( panel.getAllocatedSettopsScrollPane().equals( selectedComponent ) ) { panel.getLaunchVideoButton().setEnabled( false ); panel.getLaunchVideoCheckBox().setEnabled( false ); } } /** * Fill the data to the Available STB table. This gets the data from the * allocation service. The previous data is flushed and new data will be * populated. */ private void fillAvailableSettopTab( String authToken ) { clearAvailableSettopTable(); if ( authToken != null && !authToken.isEmpty() ) { MySettopsTask mySettopsTask = new MySettopsTask( configPanelUtil, configModel, availableTableModel, panel, AVAILABLE_SETTOPS_TABLE ); managedThreadPool.addTask( mySettopsTask ); } } /** * Fills the data to the allocated Settops Tab. The previous data is flushed * and new data will be populated. */ private void fillAllocatedSettopTab( String authToken ) { clearAllocatedSettopTable(); if ( authToken != null && !authToken.isEmpty() ) { MySettopsTask mySettopsTask = new MySettopsTask( configPanelUtil, configModel, allocatedTableModel, panel, ALLOCATED_SETTOPS_TABLE ); managedThreadPool.addTask( mySettopsTask ); } } private void clearAllocatedSettopTable() { allocatedTableModel = panel.getAllocatedSettopModel(); allocatedTableModel.getDataVector().removeAllElements(); allocatedTableModel.setNumRows( 0 ); allocatedTableModel.fireTableDataChanged(); panel.updateTableData( ALLOCATED_SETTOPS_TABLE, allocatedTableModel ); } private void clearAvailableSettopTable() { availableTableModel = panel.getAvailableSettopModel(); availableTableModel.getDataVector().removeAllElements(); availableTableModel.setNumRows( 0 ); availableTableModel.fireTableDataChanged(); panel.updateTableData( AVAILABLE_SETTOPS_TABLE, availableTableModel ); } /** * Method to fill the Property value table. * * @param settopReservationDesc * instance of SettopReservationDesc */ private void fillPropertyValueTable( final SettopReservationDesc settopReservationDesc ) { // Remove any existing properties. ConfigPanelTableModel tableModel = panel.getPropertyValueModel(); tableModel.getDataVector().removeAllElements(); // Settop Properties can be identified as getXXX methods in SettopDesc // class. // To identify the different properties, we need to identify all the // getXXX methods in SettopDesc. tableModel = populateSettopDescData( tableModel, settopReservationDesc ); panel.updateTableData( SETTOP_PROERTIES_TABLE, tableModel ); panel.autoResizeTable( SETTOP_PROERTIES_TABLE ); } private ConfigPanelTableModel populateSettopDescData( ConfigPanelTableModel tableModel, SettopDesc settDesc ) { Method[] methods = new SettopDesc().getClass().getDeclaredMethods(); for ( Method method : methods ) { // Get all "getXXX" methods that has no arguments. if ( method.getName().startsWith( "get" ) && method.getModifiers() == Modifier.PUBLIC && method.getParameterTypes().length == 0 ) { // We need to show only properties that have a non-null vale and // is not a list. Object object = null; try { object = method.invoke( settDesc ); if ( object != null && !( object instanceof List< ? > ) ) { // Check for hashmap to deal with extraproperties. // FIXME: Is this right??? final Vector< Object > propertyValueData = new Vector< Object >(); if ( object instanceof HashMap< ?, ? > ) { Set< ? > keySet = ( ( HashMap< ?, ? > ) object ).keySet(); for ( Object key : keySet ) { propertyValueData.add( key.toString() ); propertyValueData.add( ( ( HashMap< ?, ? > ) object ).get( key ) ); } } else { propertyValueData.add( method.getName().substring( 3 ) ); propertyValueData.add( object ); } tableModel.addRow( propertyValueData ); } } catch ( IllegalArgumentException e ) { e.printStackTrace(); } catch ( IllegalAccessException e ) { e.printStackTrace(); } catch ( InvocationTargetException e ) { e.printStackTrace(); } catch(Exception e) { e.printStackTrace(); } } } return tableModel; } /** * Method to clear the Property value table. */ private void clearPropertyValueTable() { ConfigPanelTableModel tableModel = panel.getPropertyValueModel(); tableModel.getDataVector().removeAllElements(); panel.updateTableData( SETTOP_PROERTIES_TABLE, tableModel ); } /** * Filter Settops based on the focused table */ private void filterSettops() { String keyword = getSearchKeyword(); if ( logger.isDebugEnabled() ) { logger.debug( "Search keyword = " + keyword ); } if ( ( panel != null ) && ( panel.getFocusedTable() != null ) ) { TableType focusedTableType = panel.getFocusedTable(); if ( focusedTableType.equals( AVAILABLE_SETTOPS_TABLE ) ) { filterAvailableSettops( keyword ); } else if ( focusedTableType.equals( ALLOCATED_SETTOPS_TABLE ) ) { filterAllocatedSettops( keyword ); } } } /** * Filter Settops in AvailableSettops table * * @param keyword * Search keyword */ private void filterAvailableSettops( final String keyword ) { if ( logger.isDebugEnabled() ) { logger.debug( "Filter AvailableSettops " ); } /* * Clear the contents in table */ ConfigPanelTableModel tableFilterModel = panel.getAvailableSettopModel(); tableFilterModel.getDataVector().removeAllElements(); tableFilterModel.setNumRows( 0 ); tableFilterModel.fireTableDataChanged(); if ( availableSettopsTable != null ) { availableSettopsTable.clearSelection(); clearPropertyValueTable(); } if ( !keyword.isEmpty() ) { /* * Filter settops based on the keyword */ for ( SettopReservationDesc settopDesc : configModel.getAvailableSettops().values() ) { if ( ( settopDesc.toString().toLowerCase() ).contains( keyword.toLowerCase() ) ) { tableFilterModel.addRow( settopDesc, AVAILABLE_SETTOPS_TABLE ); } } } else { /* * Unfilter settops */ for ( SettopReservationDesc settopDesc : configModel.getAvailableSettops().values() ) { tableFilterModel.addRow( settopDesc, AVAILABLE_SETTOPS_TABLE ); } } panel.updateTableData( AVAILABLE_SETTOPS_TABLE, tableFilterModel ); highlightSettops( keyword ); } /** * Filter Settops in AllocatedSettops table * * @param keyword * Search keyword */ private void filterAllocatedSettops( final String keyword ) { ConfigPanelTableModel tableModel = panel.getAllocatedSettopModel(); tableModel.getDataVector().removeAllElements(); tableModel.setNumRows( 0 ); tableModel.fireTableDataChanged(); if ( allocatedSettopsTable != null ) { allocatedSettopsTable.clearSelection(); clearPropertyValueTable(); } if ( !keyword.isEmpty() ) { for ( SettopReservationDesc settopDesc : configModel.getAllocatedSettops().values() ) { if ( ( settopDesc.toString().toLowerCase() ).contains( keyword.toLowerCase() ) ) { tableModel.addRow( settopDesc, ALLOCATED_SETTOPS_TABLE ); } } } else { for ( SettopReservationDesc settopDesc : configModel.getAllocatedSettops().values() ) { tableModel.addRow( settopDesc, ALLOCATED_SETTOPS_TABLE ); } } panel.updateTableData( ALLOCATED_SETTOPS_TABLE, allocatedTableModel ); } /** * Highlight the settops which are already selected by user(This neccessary * because after each search the highlighted settops get cleared) * * @param keyword * Search keyword (Acts as a key) */ private void highlightSettops( final String keyword ) { /* * Get all the selected settops' macID */ Set< String > highlightedRows = configModel.getHighlightedRowIds(); if ( panel.getFocusedTable().equals( AVAILABLE_SETTOPS_TABLE ) && !highlightedRows.isEmpty() ) { List< String > highLightedRowIds = new LinkedList< String >( highlightedRows ); JTable table = panel.getAvailableSettopsTable(); /* * Check if the table contains any selected macIDs, if so highlight * those table rows. */ if ( table != null ) { for ( int i = 0; i < table.getRowCount(); i++ ) { for ( String highLightedRowId : highLightedRowIds ) { if ( ( table.getValueAt( i, 2 ) != null ) && ( table.getValueAt( i, 4 ) != null ) ) { String identifier = ( String ) ( table.getValueAt( i, 2 ) ) + ( String ) ( table.getValueAt( i, 4 ) ); if ( identifier.equals( highLightedRowId ) ) { // Highlighting the table row table.addRowSelectionInterval( i, i ); } } } } } } } /** * * Get search keyword from the config panel * * @return search keyword */ private String getSearchKeyword() { String searchKeyword = panel.getSearchTextField().getText(); return searchKeyword.trim(); } /* * Find the newly highlighted Mac Ids and also remove the previously * highlighted mac Ids from the macIDMap. */ private void findSelectedMacIDs( final String keyword ) { Set< String > oldHighlightedRowIds = new LinkedHashSet< String >(); if ( keyword.isEmpty() ) { /* * If search keyword is empty, then need to get all highlighted * settops.(When no keyword is given unfiltering happens) */ oldHighlightedRowIds = configModel.getHighlightedRowIds(); } else { oldHighlightedRowIds = configModel.getHighlightedRowMap().get( keyword ); } Set< String > newHighlightedRowIds = getNewHighlightedRowIds( indexRowsSelected ); Set< String > unselectedRowIDs = findUnselectedRowIDs( oldHighlightedRowIds, newHighlightedRowIds ); if ( logger.isTraceEnabled() ) { logger.trace( "Old Highlighted Row Identifiers = = " + oldHighlightedRowIds + "\n" + "New Highlighted Row Identifiers = " + newHighlightedRowIds + "\n" + "unselectedRowIDs =" + unselectedRowIDs ); } /* * Remove the unselected row ID from the map */ if ( unselectedRowIDs != null ) { removeUnselectedRowIDs( unselectedRowIDs ); } if ( newHighlightedRowIds != null ) { configModel.getHighlightedRowMap().put( keyword, newHighlightedRowIds ); } } /* * Remove the unselected row IDs from the map */ private void removeUnselectedRowIDs( final Set< String > deselectedMacIds ) { Map< String, Set< String >> macIDMap = configModel.getHighlightedRowMap(); for ( String key : macIDMap.keySet() ) { Set< String > macIDs = macIDMap.get( key ); for ( String deselectedMacId : deselectedMacIds ) { if ( macIDs.contains( deselectedMacId ) ) { macIDs.remove( deselectedMacId ); } } } } /* * Find unselected Settops */ private Set< String > findUnselectedRowIDs( final Set< String > oldHighlightedRowIDs, final Set< String > newHighlightedRowIDs ) { Set< String > deselectedRowIDs = new LinkedHashSet< String >(); if ( ( oldHighlightedRowIDs != null ) && ( newHighlightedRowIDs != null ) ) { for ( String oldHighlightedRowID : oldHighlightedRowIDs ) { /* * Checks if the newly highlighted row ids contains previously * highlighted row id, If not the previously highlighted row id * will be marked as deselected. */ if ( !newHighlightedRowIDs.contains( oldHighlightedRowID ) ) { deselectedRowIDs.add( oldHighlightedRowID ); } } } return deselectedRowIDs; } /* * Get highlighted rows mac id */ private Set< String > getNewHighlightedRowIds( final int[] rowsSelected ) { Set< String > highlightedRows = new LinkedHashSet< String >(); JTable table = panel.getAvailableSettopsTable(); if ( rowsSelected.length != 0 ) { for ( int i = 0; i < rowsSelected.length; i++ ) { if ( rowsSelected[ i ] != -1 ) { // Settop macId + Reservation name is used as unique // identifier String identifier = ( String ) table.getValueAt( rowsSelected[ i ], 2 ) + ( String ) table.getValueAt( rowsSelected[ i ], 4 ); highlightedRows.add( identifier ); } } } return highlightedRows; } @Override public void actionPerformed( ActionEvent actionEvent ) { if ( actionEvent.getSource() instanceof JButton ) { JButton button = ( JButton ) actionEvent.getSource(); String buttonText = button.getText(); if ( buttonText.equals( LAUNCH_VIDEO ) ) { /* * Get the selected settops */ Set< String > macIdSet = configModel.getHighlightedMacIds(); if ( !macIdSet.isEmpty() ) { try { videoGridController.launchCatsVision( macIdSet ); } catch ( MalformedURLException e ) { logger.debug( "MalformedURLException : " + e ); } catch ( URISyntaxException e ) { logger.debug( "URISyntaxException : " + e ); } } else { CatsVisionUtils.showWarning( "No Settops Selected", "Please select Settops before launching "+CatsVisionConstants.APPLICATION_TITLE ); } } else if ( buttonText.equals( SEARCH_SETTOP ) ) { filterSettops(); } else if ( buttonText.equals( REFRESH_SETTOP_LIST ) ) { updateTable(); } } else if ( actionEvent.getSource() instanceof JTextField ) { JTextField textField = ( JTextField ) actionEvent.getSource(); if ( textField.getName().equals( SEARCH_TEXT_FIELD ) ) { filterSettops(); } } } @Override public void mouseClicked( MouseEvent evt ) { if ( evt.getSource() instanceof JTable ) { JTable selectedtable = ( JTable ) evt.getSource(); if ( evt.getClickCount() == 2 ) { if ( null != selectedtable.getValueAt( selectedRow, 2 ) ) { String macAddress = selectedtable.getValueAt( selectedRow, 2 ).toString(); /* * If the user has double clicked a row in the given table, * the activate settop in that row. */ if ( null != macAddress && !macAddress.isEmpty() && evt.getClickCount() == 2 ) { logger.debug( "Double clicked the row containing mac address -" + macAddress ); try { videoGridController.launchCatsVision( macAddress ); } catch ( MalformedURLException e ) { logger.error( "MalformedURLException : " + e ); } catch ( URISyntaxException e ) { logger.error( "URISyntaxException : " + e ); } } } else if ( null == selectedtable.getValueAt( selectedRow, 2 ) ) { CatsVisionUtils.showNoMacFoundError(); } } } } @Override public void mousePressed( MouseEvent evt ) { /* * This is to handle table row deselection. */ if ( evt.isControlDown() && ( panel.getFocusedTable() == TableType.AVAILABLE_SETTOPS_TABLE ) ) { indexRowsSelected = panel.getAvailableSettopsTable().getSelectedRows(); findSelectedMacIDs( getSearchKeyword() ); } } @Override public void mouseEntered( MouseEvent e ) { // TODO Auto-generated method stub } @Override public void mouseExited( MouseEvent e ) { // TODO Auto-generated method stub } @Override public void mouseReleased( MouseEvent e ) { // TODO Auto-generated method stub } /** * This will be called on the allocated and available settop tab change. */ @Override public void stateChanged( ChangeEvent evt ) { JTabbedPane resultsTabbedPane = panel.getTabbedPane(); final Component selectedComponent = resultsTabbedPane.getSelectedComponent(); if ( panel.getAvailableSettopsScrollPane().equals( selectedComponent ) ) { panel.setFocusedTable( AVAILABLE_SETTOPS_TABLE ); panel.getLaunchVideoButton().setEnabled( true ); panel.getLaunchVideoCheckBox().setEnabled( true ); } else if ( panel.getAllocatedSettopsScrollPane().equals( selectedComponent ) ) { panel.setFocusedTable( ALLOCATED_SETTOPS_TABLE ); panel.getLaunchVideoButton().setEnabled( false ); panel.getLaunchVideoCheckBox().setEnabled( false ); } } }