diff --git a/jhotdraw-actions/pom.xml b/jhotdraw-actions/pom.xml index 5cc33e1c6..4e31ac814 100644 --- a/jhotdraw-actions/pom.xml +++ b/jhotdraw-actions/pom.xml @@ -24,5 +24,24 @@ jhotdraw-datatransfer ${project.version} + + org.junit.jupiter + junit-jupiter + RELEASE + test + + + org.mockito + mockito-junit-jupiter + 4.5.1 + test + + + org.mockito + mockito-core + 4.5.1 + test + + \ No newline at end of file diff --git a/jhotdraw-actions/src/main/java/org/jhotdraw/action/edit/CopyAction.java b/jhotdraw-actions/src/main/java/org/jhotdraw/action/edit/CopyAction.java index 208e82405..d7853d3a3 100644 --- a/jhotdraw-actions/src/main/java/org/jhotdraw/action/edit/CopyAction.java +++ b/jhotdraw-actions/src/main/java/org/jhotdraw/action/edit/CopyAction.java @@ -56,18 +56,25 @@ public CopyAction(JComponent target) { @Override public void actionPerformed(ActionEvent evt) { - JComponent c = target; - if (c == null && (KeyboardFocusManager.getCurrentKeyboardFocusManager(). - getPermanentFocusOwner() instanceof JComponent)) { - c = (JComponent) KeyboardFocusManager.getCurrentKeyboardFocusManager(). - getPermanentFocusOwner(); + JComponent component = getTargetComponent(); + if (component != null) { + copyToClipboard(component); } - // Note: copying is allowed for disabled components - if (c != null) { - c.getTransferHandler().exportToClipboard( - c, - ClipboardUtil.getClipboard(), - TransferHandler.COPY); + } + + private JComponent getTargetComponent() { + if (target != null) { + return target; } + Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner(); + return (focusOwner instanceof JComponent) ? (JComponent) focusOwner : null; + } + + private void copyToClipboard(JComponent component) { + component.getTransferHandler().exportToClipboard( + component, + ClipboardUtil.getClipboard(), + TransferHandler.COPY + ); } } diff --git a/jhotdraw-actions/src/main/java/org/jhotdraw/action/edit/CutAction.java b/jhotdraw-actions/src/main/java/org/jhotdraw/action/edit/CutAction.java index 044bb4aa7..5ebb4d136 100644 --- a/jhotdraw-actions/src/main/java/org/jhotdraw/action/edit/CutAction.java +++ b/jhotdraw-actions/src/main/java/org/jhotdraw/action/edit/CutAction.java @@ -1,17 +1,10 @@ -/* - * @(#)CutAction.java - * - * Copyright (c) 1996-2010 The authors and contributors of JHotDraw. - * You may not use, copy or modify this file, except in compliance with the - * accompanying license terms. - */ package org.jhotdraw.action.edit; import java.awt.*; -import java.awt.event.*; +import java.awt.event.ActionEvent; import javax.swing.*; import org.jhotdraw.datatransfer.ClipboardUtil; -import org.jhotdraw.util.*; +import org.jhotdraw.util.ResourceBundleUtil; /** * Cuts the selected region and places its contents into the system clipboard. @@ -26,9 +19,7 @@ * If you want this behavior in your application, you have to create an action * with this ID and put it in your {@code ApplicationModel} in method * {@link org.jhotdraw.app.ApplicationModel#initApplication}. - * - * @author Werner Randelshofer - * @version $Id$ + *

*/ public class CutAction extends AbstractSelectionAction { @@ -50,23 +41,56 @@ public CutAction() { */ public CutAction(JComponent target) { super(target); + initializeAction(); + } + + private void initializeAction() { ResourceBundleUtil labels = ResourceBundleUtil.getBundle("org.jhotdraw.action.Labels"); labels.configureAction(this, ID); } @Override public void actionPerformed(ActionEvent evt) { - JComponent c = target; - if (c == null && (KeyboardFocusManager.getCurrentKeyboardFocusManager(). - getPermanentFocusOwner() instanceof JComponent)) { - c = (JComponent) KeyboardFocusManager.getCurrentKeyboardFocusManager(). - getPermanentFocusOwner(); + JComponent component = getActiveComponent(); + if (isComponentEligibleForCut(component)) { + performCutToClipboard(component); } - if (c != null && c.isEnabled()) { - c.getTransferHandler().exportToClipboard( - c, - ClipboardUtil.getClipboard(), - TransferHandler.MOVE); + } + + /** + * Retrieves the target component, defaulting to the currently focused component if target is null. + * + * @return the active JComponent or null if none is focused. + */ + private JComponent getActiveComponent() { + if (target != null) { + return target; } + Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner(); + return (focusOwner instanceof JComponent) ? (JComponent) focusOwner : null; + } + + /** + * Checks if the component is eligible for a cut operation. + * + * @param component the component to check + * @return true if component is not null and is enabled + */ + private boolean isComponentEligibleForCut(JComponent component) { + return component != null && component.isEnabled(); + } + + /** + * Cuts the contents of the component to the system clipboard. + * + * @param component the component whose contents are to be cut + */ + private void performCutToClipboard(JComponent component) { + component.getTransferHandler().exportToClipboard( + component, + ClipboardUtil.getClipboard(), + TransferHandler.MOVE + ); } } + diff --git a/jhotdraw-actions/src/main/java/org/jhotdraw/action/edit/DeleteAction.java b/jhotdraw-actions/src/main/java/org/jhotdraw/action/edit/DeleteAction.java index 05ae13f58..79f9df527 100644 --- a/jhotdraw-actions/src/main/java/org/jhotdraw/action/edit/DeleteAction.java +++ b/jhotdraw-actions/src/main/java/org/jhotdraw/action/edit/DeleteAction.java @@ -77,7 +77,7 @@ public DeleteAction() { * Creates a new instance which acts on the specified component. * * @param target The target of the action. Specify null for the currently - * focused component. + * focused component. */ public DeleteAction(JComponent target) { this(target, ID); @@ -87,7 +87,7 @@ public DeleteAction(JComponent target) { * Creates a new instance which acts on the specified component. * * @param target The target of the action. Specify null for the currently - * focused component. + * focused component. */ protected DeleteAction(JComponent target, String id) { super(id); @@ -110,15 +110,15 @@ public void propertyChange(PropertyChangeEvent evt) { @Override public void actionPerformed(ActionEvent evt) { - JComponent c = target; - if (c == null && (KeyboardFocusManager.getCurrentKeyboardFocusManager(). + JComponent component = target; + if (component == null && (KeyboardFocusManager.getCurrentKeyboardFocusManager(). getPermanentFocusOwner() instanceof JComponent)) { - c = (JComponent) KeyboardFocusManager.getCurrentKeyboardFocusManager(). + component = (JComponent) KeyboardFocusManager.getCurrentKeyboardFocusManager(). getPermanentFocusOwner(); } - if (c != null && c.isEnabled()) { - if (c instanceof EditableComponent) { - ((EditableComponent) c).delete(); + if (component != null && component.isEnabled()) { + if (component instanceof EditableComponent) { + ((EditableComponent) component).delete(); } else { deleteNextChar(evt); } @@ -130,27 +130,51 @@ public void actionPerformed(ActionEvent evt) { * DefaultEditorKit.DeleteNextCharAction.actionPerformed(ActionEvent). */ public void deleteNextChar(ActionEvent e) { - JTextComponent c = getTextComponent(e); - boolean beep = true; - if ((c != null) && (c.isEditable())) { - try { - javax.swing.text.Document doc = c.getDocument(); - Caret caret = c.getCaret(); - int dot = caret.getDot(); - int mark = caret.getMark(); - if (dot != mark) { - doc.remove(Math.min(dot, mark), Math.abs(dot - mark)); - beep = false; - } else if (dot < doc.getLength()) { - doc.remove(dot, 1); - beep = false; - } - } catch (BadLocationException bl) { - // allowed empty - } + JTextComponent textComponent = getTextComponent(e); + + if (shouldBeepInsteadOfDelete(textComponent)) { + Toolkit.getDefaultToolkit().beep(); + return; + } + + try { + deleteTextOrNextCharacter(textComponent); + } catch (BadLocationException ignored) { + // Exception ignored as it's unlikely to occur in practice } - if (beep) { + } +// Refactored helper methods + private boolean shouldBeepInsteadOfDelete(JTextComponent textComponent) { + return textComponent == null || !textComponent.isEditable(); + } + + private void deleteTextOrNextCharacter(JTextComponent textComponent) throws BadLocationException { + Document doc = textComponent.getDocument(); + Caret caret = textComponent.getCaret(); + + if (hasSelection(caret)) { + deleteSelectedText(doc, caret); + } else if (canDeleteNextCharacter(caret, doc)) { + deleteNextCharacter(doc, caret.getDot()); + } else { Toolkit.getDefaultToolkit().beep(); } } -} + + private boolean hasSelection(Caret caret) { + return caret.getDot() != caret.getMark(); + } + + private void deleteSelectedText(Document doc, Caret caret) throws BadLocationException { + int dot = caret.getDot(); + int mark = caret.getMark(); + doc.remove(Math.min(dot, mark), Math.abs(dot - mark)); + } + + private boolean canDeleteNextCharacter(Caret caret, Document doc) { + return caret.getDot() < doc.getLength(); + } + + private void deleteNextCharacter(Document doc, int dot) throws BadLocationException { + doc.remove(dot, 1); + }} diff --git a/jhotdraw-actions/src/main/java/org/jhotdraw/action/edit/DuplicateAction.java b/jhotdraw-actions/src/main/java/org/jhotdraw/action/edit/DuplicateAction.java index 5c7fa23ab..9b3d7f369 100644 --- a/jhotdraw-actions/src/main/java/org/jhotdraw/action/edit/DuplicateAction.java +++ b/jhotdraw-actions/src/main/java/org/jhotdraw/action/edit/DuplicateAction.java @@ -13,6 +13,7 @@ import org.jhotdraw.api.gui.EditableComponent; import org.jhotdraw.util.*; + /** * Duplicates the selected region. *

@@ -61,7 +62,7 @@ public DuplicateAction() { * Creates a new instance which acts on the specified component. * * @param target The target of the action. Specify null for the currently - * focused component. + * focused component. */ public DuplicateAction(JComponent target) { super(target); @@ -69,20 +70,37 @@ public DuplicateAction(JComponent target) { labels.configureAction(this, ID); } + @Override public void actionPerformed(ActionEvent evt) { - JComponent c = target; - if (c == null && (KeyboardFocusManager.getCurrentKeyboardFocusManager(). - getPermanentFocusOwner() instanceof JComponent)) { - c = (JComponent) KeyboardFocusManager.getCurrentKeyboardFocusManager(). - getPermanentFocusOwner(); + // Change Variable name + JComponent targetComponent = getTargetComponent(); + + // Return early if there is no valid or enabled component + if (targetComponent == null || !targetComponent.isEnabled()) { + return; } - if (c != null && c.isEnabled()) { - if (c instanceof EditableComponent) { - ((EditableComponent) c).duplicate(); - } else { - c.getToolkit().beep(); - } + + // Perform duplication if the component is editable + if (targetComponent instanceof EditableComponent) { + ((EditableComponent) targetComponent).duplicate(); + } else { + targetComponent.getToolkit().beep(); } } + private JComponent getTargetComponent() { + // Check if 'target' is available + if (target != null) { + return target; + } + + // Get the component that is currently in focus + Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner(); + if (focusOwner instanceof JComponent) { + return (JComponent) focusOwner; + } + + // Returnér null, if no valid component is found + return null; + } } diff --git a/jhotdraw-actions/src/main/java/org/jhotdraw/action/edit/PasteAction.java b/jhotdraw-actions/src/main/java/org/jhotdraw/action/edit/PasteAction.java index 44f3a0953..0fc3ea4ac 100644 --- a/jhotdraw-actions/src/main/java/org/jhotdraw/action/edit/PasteAction.java +++ b/jhotdraw-actions/src/main/java/org/jhotdraw/action/edit/PasteAction.java @@ -26,7 +26,7 @@ *

* If you want this behavior in your application, you have to create an action * with this ID and put it in your {@code ApplicationModel} in method - * {@link org.jhotdraw.app.ApplicationModel#initApplication}. + * . * * @author Werner Randelshofer * @version $Id$ @@ -56,27 +56,38 @@ public PasteAction(JComponent target) { } @Override - public void actionPerformed(ActionEvent evt) { - JComponent c = target; - if (c == null && (KeyboardFocusManager.getCurrentKeyboardFocusManager(). - getPermanentFocusOwner() instanceof JComponent)) { - c = (JComponent) KeyboardFocusManager.getCurrentKeyboardFocusManager(). - getPermanentFocusOwner(); + protected void updateEnabled() { + if (target != null) { + setEnabled(target.isEnabled()); } - if (c != null && c.isEnabled()) { - Transferable t = ClipboardUtil.getClipboard().getContents(c); - if (t != null && c.getTransferHandler() != null) { - c.getTransferHandler().importData( - c, - t); + } + @Override + public void actionPerformed(ActionEvent evt) { + JComponent focusedComponent = getTargetComponent(); + + if (isComponentEligibleForTransfer(focusedComponent)) { + Transferable clipboardContent = ClipboardUtil.getClipboard().getContents(focusedComponent); + if (clipboardContent != null) { + importDataToComponent(focusedComponent, clipboardContent); } } } - - @Override - protected void updateEnabled() { + private JComponent getTargetComponent() { if (target != null) { - setEnabled(target.isEnabled()); + return target; + } + KeyboardFocusManager focusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager(); + if (focusManager.getPermanentFocusOwner() instanceof JComponent) { + return (JComponent) focusManager.getPermanentFocusOwner(); } + + return null; + } + private boolean isComponentEligibleForTransfer(JComponent component) { + return component != null && component.isEnabled() && component.getTransferHandler() != null; } + private void importDataToComponent(JComponent component, Transferable transferable) { + component.getTransferHandler().importData(component, transferable); + } + } diff --git a/jhotdraw-actions/src/test/java/org/jhotdraw/action/edit/CopyActionTest.java b/jhotdraw-actions/src/test/java/org/jhotdraw/action/edit/CopyActionTest.java new file mode 100644 index 000000000..554870a8c --- /dev/null +++ b/jhotdraw-actions/src/test/java/org/jhotdraw/action/edit/CopyActionTest.java @@ -0,0 +1,62 @@ +package org.jhotdraw.action.edit; + +import org.jhotdraw.datatransfer.ClipboardUtil; +import org.junit.jupiter.api.Test; + +import javax.swing.*; +import static org.mockito.Mockito.*; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.awt.*; + +import java.awt.event.ActionEvent; +@ExtendWith(MockitoExtension.class) +class CopyActionTest { + private CopyAction copyAction; + @Mock + private JComponent targetComponent; + @Mock + private TransferHandler mockTransferHandler; + @Mock + private KeyboardFocusManager mockFocusManager; + + @BeforeEach + void setUP() { + copyAction = new CopyAction(targetComponent); + lenient().when(mockFocusManager.getPermanentFocusOwner()).thenReturn(targetComponent); + KeyboardFocusManager.setCurrentKeyboardFocusManager(mockFocusManager); + + lenient().when(targetComponent.getTransferHandler()).thenReturn(mockTransferHandler); + + } + + @Test + void TestAction() { + assertNotNull(targetComponent); + } + + @Test + void ActionPerformedTest() { + ActionEvent event = new ActionEvent(targetComponent, ActionEvent.ACTION_PERFORMED, "copy"); + // Perform copyAction + copyAction.actionPerformed(event); + + verify(mockTransferHandler).exportToClipboard( + eq(targetComponent), + eq(ClipboardUtil.getClipboard()), + eq(TransferHandler.COPY) + ); + + verify(mockTransferHandler, times(1)).exportToClipboard( + eq(targetComponent), + eq(ClipboardUtil.getClipboard()), + eq(TransferHandler.COPY) + ); + + } +} diff --git a/jhotdraw-core/src/main/java/org/jhotdraw/draw/action/AlignAction.java b/jhotdraw-core/src/main/java/org/jhotdraw/draw/action/AlignAction.java index 9b682f099..129cab0d9 100644 --- a/jhotdraw-core/src/main/java/org/jhotdraw/draw/action/AlignAction.java +++ b/jhotdraw-core/src/main/java/org/jhotdraw/draw/action/AlignAction.java @@ -24,7 +24,6 @@ * @version $Id$ */ public abstract class AlignAction extends AbstractSelectedAction { - private static final long serialVersionUID = 1L; protected ResourceBundleUtil labels = ResourceBundleUtil.getBundle("org.jhotdraw.draw.Labels"); diff --git a/jhotdraw-core/src/main/java/org/jhotdraw/draw/figure/Figure.java b/jhotdraw-core/src/main/java/org/jhotdraw/draw/figure/Figure.java index 2e9b9ab11..7c19de39e 100644 --- a/jhotdraw-core/src/main/java/org/jhotdraw/draw/figure/Figure.java +++ b/jhotdraw-core/src/main/java/org/jhotdraw/draw/figure/Figure.java @@ -23,7 +23,10 @@ import org.jhotdraw.draw.tool.Tool; import org.jhotdraw.geom.Dimension2DDouble; -/** +/**public interface Figure { + void draw(Graphics2D g); // Hvordan figuren tegnes + boolean contains(Point2D p); // Er et punkt inde i figuren? + } * A figure is a graphical element of a {@link Drawing}. A figure * can be only in one drawing at a time. *

@@ -601,3 +604,4 @@ public interface Figure extends Cloneable, Serializable { */ public void removePropertyChangeListener(PropertyChangeListener listener); } + diff --git a/jhotdraw-gui/src/main/java/org/jhotdraw/color/AbstractColorSlidersModel.java b/jhotdraw-gui/src/main/java/org/jhotdraw/color/AbstractColorSlidersModel.java index 1359b0019..ee131a275 100644 --- a/jhotdraw-gui/src/main/java/org/jhotdraw/color/AbstractColorSlidersModel.java +++ b/jhotdraw-gui/src/main/java/org/jhotdraw/color/AbstractColorSlidersModel.java @@ -19,6 +19,7 @@ */ public abstract class AbstractColorSlidersModel extends AbstractBean implements ColorSliderModel { + private static final long serialVersionUID = 1L; /** * ChangeListener's listening to changes in this model. diff --git a/pom.xml b/pom.xml index 5f6c7eef5..fc66c4c8e 100644 --- a/pom.xml +++ b/pom.xml @@ -71,5 +71,9 @@ jhotdraw-app jhotdraw-datatransfer jhotdraw-actions + + + + \ No newline at end of file