/*
* TransferHandlerTest.java 11 sept 06
*
* Copyright (c) 2006 Emmanuel PUYBARET / eTeks <info@eteks.com>. All Rights
* Reserved.
*
* This program 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 2 of the License, or (at your option) any later
* version.
*
* This program 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
* program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.eteks.sweethome3d.junit;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.JFrame;
import junit.extensions.abbot.ComponentTestFixture;
import abbot.finder.ComponentSearchException;
import abbot.tester.ComponentLocation;
import abbot.tester.JComponentTester;
import com.eteks.sweethome3d.io.DefaultUserPreferences;
import com.eteks.sweethome3d.model.Home;
import com.eteks.sweethome3d.model.HomePieceOfFurniture;
import com.eteks.sweethome3d.model.UserPreferences;
import com.eteks.sweethome3d.swing.FurnitureCatalogTree;
import com.eteks.sweethome3d.swing.FurnitureTable;
import com.eteks.sweethome3d.swing.HomePane;
import com.eteks.sweethome3d.swing.HomeTransferableList;
import com.eteks.sweethome3d.swing.PlanComponent;
import com.eteks.sweethome3d.swing.SwingViewFactory;
import com.eteks.sweethome3d.viewcontroller.HomeController;
import com.eteks.sweethome3d.viewcontroller.PlanController;
import com.eteks.sweethome3d.viewcontroller.ViewFactory;
/**
* Tests drag and drop, and cut / copy / paste.
* @author Emmanuel Puybaret
*/
public class TransferHandlerTest extends ComponentTestFixture {
public void testTransferHandler() throws ComponentSearchException, UnsupportedFlavorException,
IOException, InterruptedException, InvocationTargetException {
UserPreferences preferences = new DefaultUserPreferences();
preferences.setFurnitureCatalogViewedInTree(true);
ViewFactory viewFactory = new SwingViewFactory();
Home home = new Home();
home.getCompass().setVisible(false);
final HomeController controller = new HomeController(home, preferences, viewFactory);
JComponent homeView = (JComponent)controller.getView();
final FurnitureCatalogTree catalogTree = (FurnitureCatalogTree)TestUtilities.findComponent(
homeView, FurnitureCatalogTree.class);
FurnitureTable furnitureTable = (FurnitureTable)TestUtilities.findComponent(
homeView, FurnitureTable.class);
final PlanComponent planComponent = (PlanComponent)TestUtilities.findComponent(
homeView, PlanComponent.class);
// 1. Create a frame that displays a home view
JFrame frame = new JFrame("Home TransferHandler Test");
frame.add(homeView);
frame.pack();
// Ensure clipboard is empty
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(""), null);
// Show home plan frame
showWindow(frame);
final JComponentTester tester = new JComponentTester();
tester.waitForIdle();
// Check catalog tree has default focus
assertTrue("Tree doesn't have the focus", catalogTree.isFocusOwner());
// Check Cut, Copy, Paste and Delete actions are disable
assertActionsEnabled(controller, false, false, false, false);
// 2. Select the first piece of furniture in catalog
tester.invokeAndWait(new Runnable() {
public void run() {
catalogTree.expandRow(0);
catalogTree.addSelectionInterval(1, 1);
}
});
// Check only Copy action is enabled
assertActionsEnabled(controller, false, true, false, false);
// 3. Drag and drop selected piece in tree to point (120, 120) in plan component
Rectangle selectedRowBounds = catalogTree.getRowBounds(1);
tester.actionDrag(catalogTree, new ComponentLocation(
new Point(selectedRowBounds.x, selectedRowBounds.y)));
tester.actionDrop(planComponent, new ComponentLocation(
new Point(120, 120)));
tester.waitForIdle();
// Check a piece was added to home
assertEquals("Wrong piece count in home", 1, home.getFurniture().size());
// Check top left corner of the piece is at (200, 200)
HomePieceOfFurniture piece = home.getFurniture().get(0);
assertTrue("Incorrect X " + piece.getX(),
Math.abs(200 - piece.getX() + piece.getWidth() / 2) < 1E-5);
assertTrue("Incorrect Y " + piece.getY(),
Math.abs(200 - piece.getY() + piece.getDepth() / 2) < 1E-5);
// 4. Transfer focus to plan view with TAB keys
tester.actionKeyStroke(KeyEvent.VK_TAB);
tester.actionKeyStroke(KeyEvent.VK_TAB);
// Check plan component has focus
assertTrue("Plan doesn't have the focus", planComponent.isFocusOwner());
// Check Cut, Copy and Delete actions are enabled in plan view
assertActionsEnabled(controller, true, true, false, true);
// 5. Use Wall creation mode
tester.invokeAndWait(new Runnable() {
public void run() {
controller.getPlanController().setMode(PlanController.Mode.WALL_CREATION);
}
});
// Check Cut, Copy, Paste actions are enabled
assertActionsEnabled(controller, true, true, false, true);
// Create a wall between points (25, 25) and (100, 25)
tester.actionClick(planComponent, 25, 25);
// Check Cut, Copy, Paste actions are disabled during wall drawing
assertActionsEnabled(controller, false, false, false, false);
tester.actionClick(planComponent, 100, 25, InputEvent.BUTTON1_MASK, 2);
// 6. Use Dimension creation mode
tester.invokeAndWait(new Runnable() {
public void run() {
controller.getPlanController().setMode(PlanController.Mode.DIMENSION_LINE_CREATION);
}
});
// Check Cut, Copy, Paste actions are enabled
assertActionsEnabled(controller, true, true, false, true);
// 7. Create a dimension line between points (25, 35) and (100, 35)
tester.actionClick(planComponent, 25, 35);
// Check Cut, Copy, Paste actions are disabled during dimension line drawing
assertActionsEnabled(controller, false, false, false, false);
tester.actionClick(planComponent, 100, 35, InputEvent.BUTTON1_MASK, 2);
// Use Selection mode
tester.invokeAndWait(new Runnable() {
public void run() {
controller.getPlanController().setMode(PlanController.Mode.SELECTION);
}
});
// Check Cut, Copy and Delete actions are enabled
assertActionsEnabled(controller, true, true, false, true);
// 7. Select the dimension, the wall and the piece
tester.actionKeyPress(KeyEvent.VK_SHIFT);
tester.actionClick(planComponent, 30, 25);
tester.actionClick(planComponent, 120, 120);
tester.actionKeyRelease(KeyEvent.VK_SHIFT);
// Check home selection contains 3 items
assertEquals("Selected items wrong count", 3, home.getSelectedItems().size());
// Cut selected items in plan component
runAction(tester, controller, HomePane.ActionType.CUT);
// Check home is empty
assertEquals("Wrong piece count in home", 0, home.getFurniture().size());
assertEquals("Wrong wall count in home", 0, home.getWalls().size());
assertEquals("Wrong dimension count in home", 0, home.getDimensionLines().size());
// Check only Paste action is enabled
assertActionsEnabled(controller, false, false, true, false);
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
// Check clipboard contains two different data flavors (HomeTransferableList and Image)
assertTrue("Missing home data flavor", clipboard.isDataFlavorAvailable(HomeTransferableList.HOME_FLAVOR));
assertTrue("Missing String flavor", clipboard.isDataFlavorAvailable(DataFlavor.imageFlavor));
// 8. Paste selected items in plan component
runAction(tester, controller, HomePane.ActionType.PASTE);
tester.waitForIdle();
// Check home contains one piece, one wall and one dimension
assertEquals("Wrong piece count in home", 1, home.getFurniture().size());
assertEquals("Wrong wall count in home", 1, home.getWalls().size());
assertEquals("Wrong dimension count in home", 1, home.getDimensionLines().size());
// 9. Transfer focus to furniture table
tester.actionKeyStroke(KeyEvent.VK_TAB, InputEvent.SHIFT_MASK);
// Check furniture table has focus
assertTrue("Table doesn't have the focus", furnitureTable.isFocusOwner());
// Delete selection
runAction(tester, controller, HomePane.ActionType.DELETE);
// Check home contains no piece, one wall and one dimension
assertEquals("Wrong piece count in home", 0, home.getFurniture().size());
assertEquals("Wrong wall count in home", 1, home.getWalls().size());
assertEquals("Wrong dimension count in home", 1, home.getDimensionLines().size());
// Check only Paste action is enabled
assertActionsEnabled(controller, false, false, true, false);
// 10. Paste selected items in furniture table
runAction(tester, controller, HomePane.ActionType.PASTE);
// Check home contains one piece, one wall and one dimension
assertEquals("Wrong piece count in home", 1, home.getFurniture().size());
assertEquals("Wrong wall count in home", 1, home.getWalls().size());
assertEquals("Wrong dimension count in home", 1, home.getDimensionLines().size());
// Check Cut, Copy and Paste actions are enabled
assertActionsEnabled(controller, true, true, true, true);
// 11. Copy selected furniture in clipboard while furniture table has focus
runAction(tester, controller, HomePane.ActionType.COPY);
// Check clipboard contains two different data flavors (HomeTransferableList and String)
assertTrue("Missing home data flavor", clipboard.isDataFlavorAvailable(HomeTransferableList.HOME_FLAVOR));
assertTrue("Missing String flavor", clipboard.isDataFlavorAvailable(DataFlavor.stringFlavor));
}
/**
* Runs <code>actionPerformed</code> method matching <code>actionType</code>
* in <code>HomePane</code>.
*/
private void runAction(JComponentTester tester, final HomeController controller,
final HomePane.ActionType actionType) {
tester.invokeAndWait(new Runnable() {
public void run() {
getAction(controller, actionType).actionPerformed(null);
}
});
}
/**
* Returns the action matching <code>actionType</code> in <code>HomePane</code>.
*/
private Action getAction(HomeController controller,
HomePane.ActionType actionType) {
return ((JComponent)controller.getView()).getActionMap().get(actionType);
}
/**
* Asserts CUT, COPY, PASTE and DELETE actions in <code>HomePane</code>
* are enabled or disabled.
*/
private void assertActionsEnabled(HomeController controller,
boolean cutActionEnabled,
boolean copyActionEnabled,
boolean pasteActionEnabled,
boolean deleteActionEnabled) {
assertTrue("Cut action invalid state",
cutActionEnabled == getAction(controller, HomePane.ActionType.CUT).isEnabled());
assertTrue("Copy action invalid state",
copyActionEnabled == getAction(controller, HomePane.ActionType.COPY).isEnabled());
assertTrue("Paste action invalid state",
pasteActionEnabled == getAction(controller, HomePane.ActionType.PASTE).isEnabled());
assertTrue("Delete action invalid state",
deleteActionEnabled == getAction(controller, HomePane.ActionType.DELETE).isEnabled());
}
}