# SPIPane.java

    /*
     * Copyright (c) 2009, Tony Kohar. All Rights Reserved.
     *
     * Licensed  under the  Apache License,  Version 2.0  (the "License");
     * you may not use  this file  except in  compliance with the License.
     * You may obtain a copy of the License at
     *
     *   http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed  under the  License is distributed on an "AS IS" BASIS,
     * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
     * implied.
     *
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    package org.qi4j.envisage.detail;

    import java.awt.BorderLayout;
    import java.awt.Component;
    import java.awt.Cursor;
    import java.awt.event.MouseEvent;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.ResourceBundle;
    import javax.swing.JComponent;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTable;
    import javax.swing.ListSelectionModel;
    import javax.swing.event.MouseInputAdapter;
    import javax.swing.table.AbstractTableModel;
    import javax.swing.table.DefaultTableCellRenderer;
    import javax.swing.table.TableColumnModel;
    import org.qi4j.envisage.event.LinkEvent;
    import org.qi4j.envisage.util.TableRow;
    import org.qi4j.tools.model.descriptor.LayerDetailDescriptor;
    import org.qi4j.tools.model.descriptor.ModuleDetailDescriptor;
    import org.qi4j.tools.model.descriptor.ServiceDetailDescriptor;
    import org.qi4j.tools.model.util.DescriptorUtilities;

    /**
     * API would be defined as "All service interfaces which are visible for layer
     * or application" and SPI would be defined as "All service dependencies which
     * are not satisfied from within the module". And then similar for Layer. This
     * way you can select a Module/Layer and immediately see what it produces as
     * output and requires as input. This is also very very nice for documentation
     * purposes.
     */
    /* package */ final class SPIPane
        extends DetailPane
    {
        private static final ResourceBundle BUNDLE = ResourceBundle.getBundle( SPIPane.class.getName() );

        private JPanel contentPane;
        private JTable spiTable;
        private SPITableModel spiTableModel;

        private Object linkObject;
        private Cursor defaultCursor;
        private Cursor linkCursor;

        /* package */ SPIPane( DetailModelPane detailModelPane )
        {
            super( detailModelPane );
            this.setLayout( new BorderLayout() );
            this.add( contentPane, BorderLayout.CENTER );

            spiTableModel = new SPITableModel();
            spiTable.setModel( spiTableModel );
            spiTable.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );

            TableColumnModel columnModel = spiTable.getColumnModel();
            columnModel.getColumn( 0 ).setCellRenderer( new DependencyCellRenderer() );

            defaultCursor = getCursor();
            linkCursor = LinkEvent.LINK_CURSOR;

            MouseInputAdapter mouseInputListener = new MouseInputAdapter()
            {
                @Override
                public void mouseMoved( MouseEvent evt )
                {
                    // Column 1 is the Service Column
                    int col = spiTable.columnAtPoint( evt.getPoint() );
                    if( col == 0 )
                    {
                        setCursor( linkCursor );
                    }
                    else
                    {
                        if( !getCursor().equals( defaultCursor ) )
                        {
                            setCursor( defaultCursor );
                        }
                    }
                }

                @Override
                public void mouseClicked( MouseEvent evt )
                {
                    int col = spiTable.columnAtPoint( evt.getPoint() );
                    if( col != 0 )
                    {
                        return;
                    }

                    int row = spiTable.rowAtPoint( evt.getPoint() );
                    if( row < 0 )
                    {
                        return;
                    }

                    linkObject = spiTable.getValueAt( row, col );
                    linkActivated();
                    linkObject = null;
                }
            };

            spiTable.addMouseMotionListener( mouseInputListener );
            spiTable.addMouseListener( mouseInputListener );
        }

        @Override
        protected void setDescriptor( Object objectDesciptor )
        {
            clear();

            List<ServiceDetailDescriptor> list = null;
            if( objectDesciptor instanceof LayerDetailDescriptor )
            {
                list = DescriptorUtilities.findLayerSPI( (LayerDetailDescriptor) objectDesciptor );
            }
            else if( objectDesciptor instanceof ModuleDetailDescriptor )
            {
                list = DescriptorUtilities.findModule( (ModuleDetailDescriptor) objectDesciptor );
            }

            if( list != null )
            {
                spiTableModel.addRow( list );
            }
        }

        private void clear()
        {
            linkObject = null;
            spiTableModel.clear();
        }

        private void linkActivated()
        {
            if( linkObject == null )
            {
                return;
            }
            LinkEvent linkEvt = new LinkEvent( this, linkObject );
            detailModelPane.fireLinkActivated( linkEvt );
        }

        {
    // GUI initializer generated by IntelliJ IDEA GUI Designer
    // >>> IMPORTANT!! <<<
    // DO NOT EDIT OR ADD ANY CODE HERE!
            $$$setupUI$$$();
        }

        /**
         * Method generated by IntelliJ IDEA GUI Designer
         * >>> IMPORTANT!! <<<
         * DO NOT edit this method OR call it in your code!
         *
         */
        private void $$$setupUI$$$()
        {
            contentPane = new JPanel();
            contentPane.setLayout( new BorderLayout( 0, 0 ) );
            final JScrollPane scrollPane1 = new JScrollPane();
            contentPane.add( scrollPane1, BorderLayout.CENTER );
            spiTable = new JTable();
            scrollPane1.setViewportView( spiTable );
        }

        public JComponent $$$getRootComponent$$$()
        {
            return contentPane;
        }

        private static class SPITableModel
            extends AbstractTableModel
        {
            /**
             * the column names for this model
             */
            private static final String[] COLUMN_NAMES =
            {
                BUNDLE.getString( "Dependency.Column" ),
                BUNDLE.getString( "Module.Column" ),
                BUNDLE.getString( "Layer.Column" )
            };
            private final ArrayList<TableRow> rows;

            private SPITableModel()
            {
                rows = new ArrayList<>();
            }

            private void addRow( List<ServiceDetailDescriptor> list )
            {
                if( list.isEmpty() )
                {
                    return;
                }

                int i1 = rows.size();
                if( i1 > 0 )
                {
                    i1--;
                }

                int i2 = 0;

                for( ServiceDetailDescriptor descriptor : list )
                {
                    TableRow row = new TableRow( COLUMN_NAMES.length );
                    row.set( 0, descriptor );
                    row.set( 1, descriptor.module() );
                    row.set( 2, descriptor.module().layer() );
                    this.rows.add( row );
                    i2++;
                }

                fireTableRowsInserted( i1, i1 + i2 );
            }

            @Override
            public Object getValueAt( int rowIndex, int columnIndex )
            {
                TableRow row = rows.get( rowIndex );
                return row.get( columnIndex );
            }

            private void clear()
            {
                rows.clear();
                fireTableDataChanged();
            }

            @Override
            public int getColumnCount()
            {
                return COLUMN_NAMES.length;
            }

            @Override
            public String getColumnName( int col )
            {
                return COLUMN_NAMES[ col];
            }

            @Override
            public int getRowCount()
            {
                return rows.size();
            }
        }

        private static class DependencyCellRenderer
            extends DefaultTableCellRenderer
        {
            @Override
            public final Component getTableCellRendererComponent( JTable table,
                                                                  Object value,
                                                                  boolean isSelected,
                                                                  boolean hasFocus,
                                                                  int row,
                                                                  int column
            )
            {
                if( value != null )
                {
                    value = "<html><a href=\"" + value.toString() + "\">" + value.toString() + "</a></html>";
                }

                super.getTableCellRendererComponent( table, value, isSelected, hasFocus, row, column );

                return this;
            }
        }

    }