All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.cayenne.modeler.editor.AbstractCallbackMethodsTab Maven / Gradle / Ivy

There is a newer version: 5.0-M1
Show newest version
/*****************************************************************
 *   Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF licenses this file
 *  to you 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
 *
 *    https://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.apache.cayenne.modeler.editor;

import com.jgoodies.forms.builder.DefaultFormBuilder;
import com.jgoodies.forms.builder.PanelBuilder;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;
import org.apache.cayenne.map.CallbackDescriptor;
import org.apache.cayenne.map.CallbackMap;
import org.apache.cayenne.map.LifecycleEvent;
import org.apache.cayenne.modeler.Application;
import org.apache.cayenne.modeler.ProjectController;
import org.apache.cayenne.modeler.action.CopyCallbackMethodAction;
import org.apache.cayenne.modeler.action.CreateCallbackMethodAction;
import org.apache.cayenne.modeler.action.CutCallbackMethodAction;
import org.apache.cayenne.modeler.action.PasteAction;
import org.apache.cayenne.modeler.action.RemoveCallbackMethodAction;
import org.apache.cayenne.modeler.event.CallbackMethodEvent;
import org.apache.cayenne.modeler.event.CallbackMethodListener;
import org.apache.cayenne.modeler.event.TablePopupHandler;
import org.apache.cayenne.modeler.pref.TableColumnPreferences;
import org.apache.cayenne.modeler.util.CayenneAction;
import org.apache.cayenne.modeler.util.CayenneTable;
import org.apache.cayenne.modeler.util.ModelerUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JToolBar;
import javax.swing.ListSelectionModel;
import javax.swing.TransferHandler;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableColumnModelEvent;
import javax.swing.event.TableColumnModelListener;
import javax.swing.table.JTableHeader;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import java.util.List;

/**
 * Base abstract class for all callback methods editing tabs Contains logic for callback
 * methods displaying, creating, removing, editing, reordering
 * 
 */
public abstract class AbstractCallbackMethodsTab extends JPanel {

    private static Logger logger = LoggerFactory.getLogger(AbstractCallbackMethodsTab.class);

    /**
     * mediator instance
     */
    ProjectController mediator;

    /**
     * toolbar for actions
     */
    protected JToolBar toolBar;
    
    /**
     * panel for displaying callback method tables
     */
    protected JPanel auxPanel;
    
    /**
     * preferences for the callback methods table
     */
    protected TableColumnPreferences tablePreferences;

    /**
     * list of callback method types
     */
    protected CallbackType[] callbackTypes = {
                            new CallbackType(LifecycleEvent.POST_ADD),
                            new CallbackType(LifecycleEvent.PRE_PERSIST),
                            new CallbackType(LifecycleEvent.POST_PERSIST),
                            new CallbackType(LifecycleEvent.PRE_UPDATE),
                            new CallbackType(LifecycleEvent.POST_UPDATE),
                            new CallbackType(LifecycleEvent.PRE_REMOVE),
                            new CallbackType(LifecycleEvent.POST_REMOVE),
                            new CallbackType(LifecycleEvent.POST_LOAD),
                    };
    
    /**
     * list of tables
     */
    protected CayenneTable[] tables = new CayenneTable[callbackTypes.length];
    
    protected JPopupMenu popupMenu;
    
    /**
     * constructor
     * 
     * @param mediator mediator instance
     */
    public AbstractCallbackMethodsTab(ProjectController mediator) {
        this.mediator = mediator;
        init();
        initController();
    }

    /**
     * @return CallbackMap with callback methods
     */
    protected abstract CallbackMap getCallbackMap();

    /**
     * @return create callback method action
     */
    protected CayenneAction getCreateCallbackMethodAction() {
        Application app = Application.getInstance();
        return app.getActionManager().getAction(CreateCallbackMethodAction.class);
    }

    /**
     * @return remove callback method action
     */
    protected RemoveCallbackMethodAction getRemoveCallbackMethodAction() {
        Application app = Application.getInstance();
        return app.getActionManager().getAction(RemoveCallbackMethodAction.class);
    }

    /**
     * @return copy callback method action
     */
    protected CopyCallbackMethodAction getCopyCallbackMethodAction() {
        Application app = Application.getInstance();
        return app.getActionManager().getAction(CopyCallbackMethodAction.class);
    }

    /**
     * @return cut callback method action
     */
    protected CutCallbackMethodAction getCutCallbackMethodAction() {
        Application app = Application.getInstance();
        return app.getActionManager().getAction(CutCallbackMethodAction.class);
    }

    /**
     * @return paste callback method action
     */
    protected PasteAction getPasteCallbackMethodAction() {
        Application app = Application.getInstance();
        return app.getActionManager().getAction(PasteAction.class);
    }

    /**
     * GUI components initialization
     */
    protected void init() {
        this.setLayout(new BorderLayout());

        toolBar = new JToolBar();
        toolBar.setFloatable(false);
        toolBar.add(getRemoveCallbackMethodAction().buildButton());
        toolBar.addSeparator(new Dimension(10, 0));
	    toolBar.add(getCopyCallbackMethodAction().buildButton(1));
	    toolBar.add(getCutCallbackMethodAction().buildButton(2));
        toolBar.add(getPasteCallbackMethodAction().buildButton(3));

        add(toolBar, BorderLayout.NORTH);

        auxPanel = new JPanel();
        auxPanel.setOpaque(false);
        auxPanel.setLayout(new BorderLayout());
        
        popupMenu = createPopup(); 
        
        createTables();

        add(new JScrollPane(auxPanel), BorderLayout.CENTER);
    }

    /**
     * Inits the {@link TableColumnPreferences} object according to callback table name.
     */
    protected abstract void initTablePreferences();

    /**
     * listeners initialization
     */
    protected void initController() {
        mediator.addCallbackMethodListener(new CallbackMethodListener() {

            public void callbackMethodChanged(CallbackMethodEvent e) {
                rebuildTables();
            }

            public void callbackMethodAdded(CallbackMethodEvent e) {
                rebuildTables();
            	selectAdded();
            }

            public void callbackMethodRemoved(CallbackMethodEvent e) {
            	int row = -1, i;
            	
            	for(i = 0; i < callbackTypes.length; i++) {
            		if(callbackTypes[i] == getSelectedCallbackType()) {
                        row = tables[i].getSelectedRow();
                        break;
            		}
            	}
                
            	rebuildTables();
                
            	if(row == tables[i].getRowCount()) {
                	row--;
                }
                
            	if (row < 0) {
                    return;
                }

            	tables[i].changeSelection(row, 0, false, false);
            }
        });

        for (CayenneTable table : tables) {
            mediator.getApplication().getActionManager().setupCutCopyPaste(
                    table,
                    CutCallbackMethodAction.class,
                    CopyCallbackMethodAction.class);
        }
    }

    /**
     * rebuilds table content
     */
    protected void rebuildTables() {
                
        CallbackMap callbackMap = getCallbackMap();

       	for(int i = 0; i < callbackTypes.length; i++) {
       		
       		CallbackType callbackType = callbackTypes[i];
  
       		List methods = new ArrayList<>();
       		CallbackDescriptor descriptor = null;
       		
       		if (callbackMap != null && callbackType != null) {
       			descriptor = callbackMap.getCallbackDescriptor(callbackType.getType());
                methods.addAll(descriptor.getCallbackMethods());
       	    }
        		
            CallbackDescriptorTableModel model = new CallbackDescriptorTableModel(
                    mediator,
                    this,
                    methods,
                    descriptor,
                    callbackType);
            
            tables[i].setModel(model);
        }

        for (CayenneTable table : tables) {
            tablePreferences.bind(table, null, null, null);
        }
    }
    
    private void createTables() {
    	FormLayout formLayout = new FormLayout("left:pref");
        DefaultFormBuilder builder = new DefaultFormBuilder(formLayout);
    	
    	int index = 0;
      	for(CallbackType callbackType : callbackTypes) {
       		tables[index] = createTable(callbackType);
       		builder.append(createTablePanel(tables[index++]));
    	}
      	
      	initTablePreferences();

        auxPanel.add(builder.getPanel(), BorderLayout.CENTER);
        validate();
    }

    private CayenneTable createTable(CallbackType callbackType) {
    	final CayenneTable cayenneTable = new CayenneTable();

        // drag-and-drop initialization
    	cayenneTable.setDragEnabled(true);

    	cayenneTable.setSortable(false);
	    cayenneTable.setRowHeight(25);
	    cayenneTable.setRowMargin(3);
	    cayenneTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
	    cayenneTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
	    
	    cayenneTable.setTransferHandler(new CallbackImportableHandler(cayenneTable));
	    cayenneTable.getSelectionModel().addListSelectionListener(new CallbackListSelectionListener(cayenneTable));
	    cayenneTable.getColumnModel().addColumnModelListener(new CallbackTableColumnModelListener(cayenneTable));
	    cayenneTable.getTableHeader().addMouseListener(new CallbackMouseAdapter(cayenneTable));
	    cayenneTable.getTableHeader().addMouseMotionListener(new CallbackMouseMotionListener(cayenneTable));
	      
	    TablePopupHandler.install(cayenneTable, popupMenu);

        addButtonAtHeader(
        		cayenneTable, 
        		getCreateCallbackMethodAction().buildButton(),
        		new ButtonListener(callbackType), 
        		ModelerUtil.buildIcon("icon-create-method.png"));
	    
	    return cayenneTable;
    }
    
    private JPopupMenu createPopup() {
	    JPopupMenu popup = new JPopupMenu();

	    popup.add(getRemoveCallbackMethodAction().buildMenu());
	    popup.addSeparator();
	    popup.add(getCopyCallbackMethodAction().buildMenu());
	    popup.add(getCutCallbackMethodAction().buildMenu());
	    popup.add(getPasteCallbackMethodAction().buildMenu());
	    
		return popup;
	}
    
    private JPanel createTablePanel(final CayenneTable cayenneTable) {
        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());
        
        panel.add(cayenneTable.getTableHeader(), BorderLayout.NORTH);
        panel.add(cayenneTable, BorderLayout.CENTER);
        
        return panel;
    }
    
    private void addButtonAtHeader(JTable table, JButton button, ActionListener buttonListener, ImageIcon buttonIcon){
        PanelBuilder builder = new PanelBuilder(new FormLayout("left:10dlu, 2dlu", "center:14dlu"));
        CellConstraints cc = new CellConstraints();
        
        button.setIcon(buttonIcon);
        button.setOpaque(false);
        button.setBorderPainted(false);
        button.setContentAreaFilled(false);
        button.addActionListener(buttonListener);
        
        builder.add(button, cc.xy(1, 1));
        
        JPanel buttonPanel = builder.getPanel();
        buttonPanel.setOpaque(false);
       
        JTableHeader header = table.getTableHeader();
        header.setLayout(new BorderLayout());
        header.setReorderingAllowed(false);
        header.setPreferredSize(new Dimension(150, 22));
        header.add(buttonPanel, BorderLayout.EAST);
    }

    class ButtonListener implements ActionListener {
    	private CallbackType callbackType;
    	
    	public ButtonListener(CallbackType callbackType) {
    		this.callbackType = callbackType;
    	}
    	
        public void actionPerformed(ActionEvent e) {
        	mediator.setCurrentCallbackType(callbackType);
        }
    } 

    protected final CallbackType getSelectedCallbackType() {
    	return mediator.getCurrentCallbackType();
    }
    
    private void selectAdded() {
    	for(int i = 0; i < callbackTypes.length; i++) {
    		if(callbackTypes[i] == getSelectedCallbackType()) {
                if (tables[i].editCellAt(
                		tables[i].getRowCount() - 1,
                        CallbackDescriptorTableModel.METHOD_NAME)
                        && tables[i].getEditorComponent() != null) {
                	tables[i].changeSelection(tables[i].getRowCount() - 1, 0, false, false);
                	tables[i].editCellAt(tables[i].getRowCount() - 1, 0);
                	tables[i].getCellEditor().stopCellEditing();
                	return;
                }
    		}
    	}
    }
    

	private void unselectAll() {
		for(int i = 0; i < callbackTypes.length; i++) {
          	if(tables[i].getCellEditor() != null) {
    			tables[i].getCellEditor().stopCellEditing();
    		}
          	tables[i].clearSelection();
    	}
	}
    
    private class CallbackImportableHandler extends TransferHandler {
    	
    	private CayenneTable table;
    	
    	public CallbackImportableHandler(CayenneTable table) {
    		this.table = table;
    	}
    	
        protected Transferable createTransferable(JComponent c) {
            int rowIndex = table.getSelectedRow();

            String result = null;
            if (rowIndex >= 0 && rowIndex < table.getModel().getRowCount()) {
                result = String.valueOf(table.getModel().getValueAt(
                        rowIndex,
                        CallbackDescriptorTableModel.METHOD_NAME));
            }

            return new StringSelection(result);
        }

        public int getSourceActions(JComponent c) {
            return COPY_OR_MOVE;
        }

        public boolean importData(JComponent comp, Transferable t) {
            if (canImport(comp, t.getTransferDataFlavors())) {
                String callbackMethod;
                try {
                    callbackMethod = (String) t.getTransferData(DataFlavor.stringFlavor);
                } catch (Exception e) {
                    logger.warn("Error transferring", e);
                    return false;
                }

                int rowIndex = table.getSelectedRow();

                CallbackDescriptor callbackDescriptor =
                        ((CallbackDescriptorTableModel)table.getCayenneModel()).getCallbackDescriptor();
                mediator.setDirty(callbackDescriptor.moveMethod(callbackMethod, rowIndex));
                rebuildTables();
                return true;
            }

            return false;
        }

        public boolean canImport(JComponent comp, DataFlavor[] transferFlavors) {
            for (DataFlavor flavor : transferFlavors) {
                if (DataFlavor.stringFlavor.equals(flavor)) {
                    return true;
                }
            }
            return false;
        }
    }

    private class CallbackListSelectionListener implements ListSelectionListener {    	
        
    	private CayenneTable table;
    	
    	public CallbackListSelectionListener(CayenneTable table){
    		this.table = table;
    	}
    	
    	public void valueChanged(ListSelectionEvent e) {
            if (!e.getValueIsAdjusting()) {
            	ObjCallbackMethod[] methods = new ObjCallbackMethod[0];

                if(!((ListSelectionModel)e.getSource()).isSelectionEmpty()) {
                    for (CayenneTable nextTable : tables) {
                        if (!nextTable.equals(table)) {
                            nextTable.clearSelection();
                            if (nextTable.getCellEditor() != null) {
                                nextTable.getCellEditor().stopCellEditing();
                            }
                        }
                    }

	                mediator.setCurrentCallbackType(((CallbackDescriptorTableModel)table.getCayenneModel()).getCallbackType());
                }

                if (table.getSelectedRow() != -1) {
                    int[] sel = table.getSelectedRows();
                    CallbackType callbackType = mediator.getCurrentCallbackType();
                    
                    methods = new ObjCallbackMethod[sel.length];
                                        
                    for (int i = 0; i < sel.length; i++) {
                    	String methodName = (String) table.getValueAt(
                    	        sel[i],
                                table.convertColumnIndexToView(CallbackDescriptorTableModel.METHOD_NAME));
                    	methods[i] = new ObjCallbackMethod(methodName, callbackType);
                    }
                }

                mediator.setCurrentCallbackMethods(methods);
                boolean enabled = methods.length > 0;
                boolean multiple = methods.length > 1;

                getRemoveCallbackMethodAction().setEnabled(enabled);
                getRemoveCallbackMethodAction().setName(getRemoveCallbackMethodAction().getActionName(multiple));
                getCopyCallbackMethodAction().setEnabled(enabled);
                getCopyCallbackMethodAction().setName(getCopyCallbackMethodAction().getActionName(multiple));
                getCutCallbackMethodAction().setEnabled(enabled);
                getCutCallbackMethodAction().setName(getCutCallbackMethodAction().getActionName(multiple));
            }
        }
    }

    private class CallbackTableColumnModelListener implements TableColumnModelListener {
        
    	private CayenneTable table;
    	
    	public CallbackTableColumnModelListener(CayenneTable table){
    		this.table = table;
    	}
    	
	    public void columnMarginChanged(ChangeEvent e) {
	        if(!table.getColumnWidthChanged() && table.getTableHeader().getResizingColumn() != null) {
                table.setColumnWidthChanged(true);
	        }
	    }
	
	    public void columnMoved(TableColumnModelEvent e) { 
	    	
	    }
	
	    public void columnAdded(TableColumnModelEvent e) { 
	    	
	    }
	
	    public void columnRemoved(TableColumnModelEvent e) { 
	    	
	    }
	
	    public void columnSelectionChanged(ListSelectionEvent e) { 
	    	
	    }
	}

    private class CallbackMouseAdapter extends MouseAdapter {
    	
    	CayenneTable table;
    	
    	public CallbackMouseAdapter(CayenneTable table) {
    		this.table = table;
    	}
    	
    	@Override
	    public void mouseReleased(MouseEvent e) {
	    	if(table.getColumnWidthChanged()) {
                for (CayenneTable nextTable : tables) {
                    nextTable.getColumnModel().getColumn(0).setPreferredWidth(table.getWidth());
                }
		    	
		    	initTablePreferences();
	        	table.setColumnWidthChanged(false);
	        }
	    }
	    
    	@Override
	    public void mousePressed(MouseEvent e) {
    		if (e.isPopupTrigger() && e.getComponent() instanceof JTableHeader ) {

    			unselectAll();
            	
    			mediator.setCurrentCallbackType(((CallbackDescriptorTableModel)table.getCayenneModel()).getCallbackType());
            	popupMenu.show(e.getComponent(), e.getX(), e.getY());
            }
	    }
	}
    
    private class CallbackMouseMotionListener implements MouseMotionListener {
    	
    	CayenneTable table;
    	
    	public CallbackMouseMotionListener(CayenneTable table) {
    		this.table = table;
    	}
    	
		public void mouseMoved(MouseEvent e) {
		}
		
		public void mouseDragged(MouseEvent e) {
	    	if(table.getColumnWidthChanged()) {
	    		tablePreferences.bind(table, null, null, null);
                for (CayenneTable nextTable : tables) {
                    if (!table.equals(nextTable)) {
                        nextTable.getColumnModel().getColumn(0).setPreferredWidth(table.getWidth());
                    }
                }
	        }
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy