Skip to content

Commit

Permalink
Added double-click support (#842)
Browse files Browse the repository at this point in the history
* Added double-click support

* warning fixen
  • Loading branch information
therealryan authored Jun 10, 2024
1 parent 0052acd commit 6380532
Show file tree
Hide file tree
Showing 6 changed files with 230 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,18 @@
import java.awt.Font;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.Vector;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.BiConsumer;
import java.util.regex.Pattern;
import java.util.stream.IntStream;
import java.util.stream.Stream;
Expand All @@ -43,7 +47,10 @@ class FlowPanel extends JPanel {

private static final long serialVersionUID = 1L;

private final transient Filter filter;
/**
* The {@link Filter} that is maniupated by this widget
*/
final transient Filter filter;

/**
* Map from list content to flow
Expand Down Expand Up @@ -81,6 +88,10 @@ class FlowPanel extends JPanel {
}
return d;
};

/**
* Invoked when the {@link Filter} changes
*/
private transient Runnable updateListener = () -> {
// no-op
};
Expand Down Expand Up @@ -125,6 +136,13 @@ class FlowPanel extends JPanel {
include.setEnabled( !enabledFlows.isSelectionEmpty() || !disabledFlows.isSelectionEmpty() );
exclude.setEnabled( !enabledFlows.isSelectionEmpty() );
} );
setDoubleClickAction( enabledFlows, ( set, index ) -> {
if( set.isEmpty() ) {
listedFlows.values().forEach( f -> set.add( f.index ) );
}
set.remove( index );
} );

disabledFlows.addListSelectionListener( lse -> {
if( !clearing.get() ) {
clearing.set( true );
Expand All @@ -134,6 +152,7 @@ class FlowPanel extends JPanel {
include.setEnabled( !enabledFlows.isSelectionEmpty() || !disabledFlows.isSelectionEmpty() );
exclude.setEnabled( !enabledFlows.isSelectionEmpty() );
} );
setDoubleClickAction( disabledFlows, Set::add );

include.setToolTipText( "Enable selected flows" );
include.addActionListener( ac -> {
Expand Down Expand Up @@ -226,6 +245,29 @@ class FlowPanel extends JPanel {

}

private void setDoubleClickAction( JList<String> list,
BiConsumer<Set<Integer>, Integer> action ) {
list.addMouseListener( new MouseAdapter() {
@Override
public void mouseClicked( MouseEvent e ) {
if( e.getClickCount() == 2 ) {
Optional.of( e.getPoint() )
.map( list::locationToIndex )
.map( list.getModel()::getElementAt )
.map( listedFlows::get )
.map( ifl -> ifl.index )
.ifPresent( idx -> {
Set<Integer> indices = filter.indices();
action.accept( indices, idx );
filter.indices( indices );
updateListener.run();
refresh();
} );
}
}
} );
}

/**
* @param l Called whenever the flow selection is changed
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Set;
import java.util.Vector;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.BiConsumer;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Stream;
Expand All @@ -39,7 +42,10 @@ class TagPanel extends JPanel {

private static final long serialVersionUID = 1L;

private final transient Filter filter;
/**
* The {@link Filter} being manipulated by this widget
*/
final transient Filter filter;

private final JList<String> availableTags = new JList<>();
private final JList<String> includedTags = new JList<>();
Expand All @@ -60,7 +66,10 @@ class TagPanel extends JPanel {
*/
transient Predicate<String> tagLimit = t -> true;

private transient Runnable updateListener = () -> {
/**
* Invoked when the {@link Filter} changes
*/
transient Runnable updateListener = () -> {
// no-op
};

Expand Down Expand Up @@ -119,6 +128,8 @@ class TagPanel extends JPanel {
avin.setEnabled( !availableTags.isSelectionEmpty() || !includedTags.isSelectionEmpty() );
avex.setEnabled( !availableTags.isSelectionEmpty() || !excludedTags.isSelectionEmpty() );
} );
setDoubleClickAction( availableTags, Set::add, null );

includedTags.addListSelectionListener( lse -> {
if( !clearing.get() ) {
clearing.set( true );
Expand All @@ -129,6 +140,8 @@ class TagPanel extends JPanel {
avin.setEnabled( !availableTags.isSelectionEmpty() || !includedTags.isSelectionEmpty() );
inex.setEnabled( !includedTags.isSelectionEmpty() || !excludedTags.isSelectionEmpty() );
} );
setDoubleClickAction( includedTags, Set::remove, null );

excludedTags.addListSelectionListener( lse -> {
if( !clearing.get() ) {
clearing.set( true );
Expand All @@ -139,6 +152,7 @@ class TagPanel extends JPanel {
avex.setEnabled( !availableTags.isSelectionEmpty() || !excludedTags.isSelectionEmpty() );
inex.setEnabled( !includedTags.isSelectionEmpty() || !excludedTags.isSelectionEmpty() );
} );
setDoubleClickAction( excludedTags, null, Set::remove );

avin.setToolTipText( SWAP_SELECTED_TAGS );
avin.addActionListener( ac -> {
Expand Down Expand Up @@ -246,6 +260,35 @@ class TagPanel extends JPanel {
refresh();
}

private void setDoubleClickAction( JList<String> list,
BiConsumer<Set<String>, String> includeAction,
BiConsumer<Set<String>, String> excludeAction ) {
list.addMouseListener( new MouseAdapter() {
@Override
public void mouseClicked( MouseEvent e ) {
if( e.getClickCount() == 2 ) {
String item = list.getModel().getElementAt(
list.locationToIndex( e.getPoint() ) );

if( includeAction != null ) {
Set<String> s = filter.includedTags();
includeAction.accept( s, item );
filter.includedTags( s );
}

if( excludeAction != null ) {
Set<String> s = filter.excludedTags();
excludeAction.accept( s, item );
filter.excludedTags( s );
}

updateListener.run();
refresh();
}
}
} );
}

/**
* @param l executed whenever the filter is updated
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,20 @@ public FilterGuiHarness selectTags( TagList in, String... tags ) {
return this;
}

/**
* Double-clicks on a list item
*
* @param in The list that the item resides in
* @param tag The item to double-click
* @return <code>this</code>
*/
public FilterGuiHarness doubleClick( TagList in, String tag ) {
interactions.add( ( f, m ) -> {
f.list( in.widgetName ).item( tag ).doubleClick();
} );
return this;
}

/**
* Clicks one of the tags swap buttons
*
Expand Down Expand Up @@ -188,6 +202,20 @@ public FilterGuiHarness selectFlows( FlowList list, String... flows ) {
return this;
}

/**
* Double-clicks on a list item
*
* @param in The list that the item resides in
* @param flow The item to double-click
* @return <code>this</code>
*/
public FilterGuiHarness doubleClick( FlowList in, String flow ) {
interactions.add( ( f, m ) -> {
f.list( in.widgetName ).item( FilterGuiHarness.toRendered( flow ) ).doubleClick();
} );
return this;
}

private static final Pattern TO_RENDERED = Pattern.compile(
"(.*) \\| (.*)" );

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledIf;
import org.junit.jupiter.api.condition.EnabledIfSystemProperty;

import com.mastercard.test.flow.assrt.filter.Filter;
import com.mastercard.test.flow.assrt.filter.gui.FilterGuiHarness.FlowList;
import com.mastercard.test.flow.assrt.filter.gui.FilterGuiHarness.TagList;
import com.mastercard.test.flow.assrt.filter.mock.Mdl;
Expand Down Expand Up @@ -234,4 +236,20 @@ void combined() {
.expectFilterResults(
"fourth [bar, foo]" );
}

/**
* Throws up a gui instance for you to fiddle with for manual testing
*/
@Test()
@EnabledIfSystemProperty(named = "manual", matches = "true")
void manual() {
Mdl mdl = new Mdl().withFlows(
"first [foo, bar]",
"second [bar, baz]",
"third [baz, oof]",
"fourth [foo, bar]" );
Filter filter = new Filter( mdl );
FilterGui gui = new FilterGui( filter );
gui.blockForInput();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,54 @@ void rebuild() {
.on( mdl );
}

/**
* Shows how flows can be moved between the enabled and disabled set by
* double-clicking
*/
@Test
void doubleClick() {

Mdl mdl = new Mdl().withFlows(
"bcd []",
"fga []",
"jkl []",
"mne []" );

new FilterGuiHarness()
.buildFlows()
.doubleClick( FlowList.ENABLED, "jkl | " )
.expect( "before",
"┌─ avail… ─┐┌┈┈┈┐┌─ inclu… ─┐┌─ disable… ─┐┌┈┈┈┐┌─ enabled_flo… ─┐╔═════╗",
"│ │┊ _ ┊│ ││ jkl | │┊ _ ┊│ bcd | │║ ║",
"│ │└┈┈┈┘└──────────┘│ │┊ ┊│ fga | │║ ║",
"│ │ ┌┈┈┈┈┈┈┈┈┈┈┐│ │└┈┈┈┘│ mne | │║ ║",
"│ │ ┊ _ ┊│ │┌┈┈┈┐│ │║ ║",
"│ │ └┈┈┈┈┈┈┈┈┈┈┘│ │┊ ┊│ │║ Run ║",
"│ │┌┈┈┈┐┌─ exclu… ─┐│ │┊ _ ┊│ │║ ║",
"│ │┊ _ ┊│ ││ │┊ ┊│ │║ ║",
"└──────────┘└┈┈┈┘└──────────┘└────────────┘└┈┈┈┘└────────────────┘║ ║",
"┌┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┐╔═══════════════════════════════════╗║ ║",
"┊ Reset ┊║ Reset ║║ ║",
"└┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┘╚═══════════════════════════════════╝╚═════╝" )
.doubleClick( FlowList.DISABLED, "jkl | " )
.doubleClick( FlowList.ENABLED, "bcd | " )
.expect( "after",
"┌─ avail… ─┐┌┈┈┈┐┌─ inclu… ─┐┌─ disable… ─┐┌┈┈┈┐┌─ enabled_flo… ─┐╔═════╗",
"│ │┊ _ ┊│ ││ bcd | │┊ _ ┊│ fga | │║ ║",
"│ │└┈┈┈┘└──────────┘│ │┊ ┊│ jkl | │║ ║",
"│ │ ┌┈┈┈┈┈┈┈┈┈┈┐│ │└┈┈┈┘│ mne | │║ ║",
"│ │ ┊ _ ┊│ │┌┈┈┈┐│ │║ ║",
"│ │ └┈┈┈┈┈┈┈┈┈┈┘│ │┊ ┊│ │║ Run ║",
"│ │┌┈┈┈┐┌─ exclu… ─┐│ │┊ _ ┊│ │║ ║",
"│ │┊ _ ┊│ ││ │┊ ┊│ │║ ║",
"└──────────┘└┈┈┈┘└──────────┘└────────────┘└┈┈┈┘└────────────────┘║ ║",
"┌┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┐╔═══════════════════════════════════╗║ ║",
"┊ Reset ┊║ Reset ║║ ║",
"└┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┘╚═══════════════════════════════════╝╚═════╝" )
.close()
.on( mdl );
}

/**
* Shows how the filter input shuffles the tag and flow lists
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,54 @@ void selection() {
.on( mdl );
}

/**
* Shows that tags can be moved between sets by double-clicking
*/
@Test
void doubleClick() {
Mdl mdl = new Mdl().withFlows(
"first [foo, bar]",
"second [bar, baz]",
"third [baz, oof]" );

new FilterGuiHarness()
.selectTags( TagList.AVAILABLE, "bar" )
.moveTo( TagList.INCLUDED )
.selectTags( TagList.AVAILABLE, "oof" )
.moveTo( TagList.EXCLUDED )
.expect( "before",
"┌─ avail… ─┐┌┈┈┈┐┌─ inclu… ─┐╔═══════╗┌┈┈┈┈┈┐",
"│ baz │┊ _ ┊│ bar │║ ║┊ ┊",
"│ foo │└┈┈┈┘└──────────┘║ ║┊ ┊",
"│ │ ┌┈┈┈┈┈┈┈┈┈┈┐║ ║┊ ┊",
"│ │ ┊ _ ┊║ ║┊ ┊",
"│ │ └┈┈┈┈┈┈┈┈┈┈┘║ Build ║┊ Run ┊",
"│ │┌┈┈┈┐┌─ exclu… ─┐║ ║┊ ┊",
"│ │┊ _ ┊│ oof │║ ║┊ ┊",
"└──────────┘└┈┈┈┘└──────────┘║ ║┊ ┊",
"╔═══════════════════════════╗║ ║┊ ┊",
"║ Reset ║║ ║┊ ┊",
"╚═══════════════════════════╝╚═══════╝└┈┈┈┈┈┘" )
.doubleClick( TagList.AVAILABLE, "baz" )
.doubleClick( TagList.INCLUDED, "bar" )
.doubleClick( TagList.EXCLUDED, "oof" )
.expect( "after",
"┌─ avail… ─┐┌┈┈┈┐┌─ inclu… ─┐╔═══════╗┌┈┈┈┈┈┐",
"│ bar │┊ _ ┊│ baz │║ ║┊ ┊",
"│ foo │└┈┈┈┘└──────────┘║ ║┊ ┊",
"│ oof │ ┌┈┈┈┈┈┈┈┈┈┈┐║ ║┊ ┊",
"│ │ ┊ _ ┊║ ║┊ ┊",
"│ │ └┈┈┈┈┈┈┈┈┈┈┘║ Build ║┊ Run ┊",
"│ │┌┈┈┈┐┌─ exclu… ─┐║ ║┊ ┊",
"│ │┊ _ ┊│ │║ ║┊ ┊",
"└──────────┘└┈┈┈┘└──────────┘║ ║┊ ┊",
"╔═══════════════════════════╗║ ║┊ ┊",
"║ Reset ║║ ║┊ ┊",
"╚═══════════════════════════╝╚═══════╝└┈┈┈┈┈┘" )
.close()
.on( mdl );
}

/**
* Exercises the tag reset button
*/
Expand Down

0 comments on commit 6380532

Please sign in to comment.