Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Made the filter gui more accessible to downstream code #102

Merged
merged 1 commit into from
Sep 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions assert/assert-filter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ Calling [`blockForUpdates()`][Filter!.blockForUpdates()] on a `Filter` instance

<!-- code_link_start -->

[Filter!.blockForUpdates()]: src/main/java/com/mastercard/test/flow/assrt/filter/Filter.java#L138-L151,138-151
[Filter!.blockForUpdates()]: src/main/java/com/mastercard/test/flow/assrt/filter/Filter.java#L158-L171,158-171

<!-- code_link_end -->

Expand All @@ -59,7 +59,7 @@ Calling [`load()`][Filter!.load()] on a filter (when system property `mctf.filte

<!-- code_link_start -->

[Filter!.save()]: src/main/java/com/mastercard/test/flow/assrt/filter/Filter.java#L162-L168,162-168
[Filter!.load()]: src/main/java/com/mastercard/test/flow/assrt/filter/Filter.java#L108-L122,108-122
[Filter!.save()]: src/main/java/com/mastercard/test/flow/assrt/filter/Filter.java#L182-L188,182-188
[Filter!.load()]: src/main/java/com/mastercard/test/flow/assrt/filter/Filter.java#L128-L142,128-142

<!-- code_link_end -->
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@

package com.mastercard.test.flow.assrt.filter;

import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toCollection;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Deque;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -55,6 +60,10 @@ public class Filter {
private static final Pattern RANGE_PTRN = Pattern.compile( "(\\d+)-(\\d+)" );
private final Set<Integer> indices = parseIndices( FilterOptions.INDICES.value() );

private Consumer<Filter> listener = f -> {
// default to nothing
};

/**
* Extracts numeric indices from a string
*
Expand Down Expand Up @@ -105,6 +114,17 @@ public Filter( Model model ) {
this.model = model;
}

/**
* Sets the listener on this {@link Filter}
*
* @param l The object that will be notified when this filter is updated
* @return <code>this</code>
*/
public Filter listener( Consumer<Filter> l ) {
listener = l;
return this;
}

/**
* Attempts to configure the filter from historic executions:
* <ul>
Expand Down Expand Up @@ -196,6 +216,7 @@ public Filter includedTags( Set<String> tags ) {
includeTags.clear();
includeTags.addAll( tags );
matchIndexSelection( current );
listener.accept( this );
}
return this;
}
Expand Down Expand Up @@ -252,6 +273,7 @@ public Filter excludedTags( Set<String> tags ) {
excludeTags.clear();
excludeTags.addAll( tags );
matchIndexSelection( current );
listener.accept( this );
}
return this;
}
Expand Down Expand Up @@ -284,6 +306,7 @@ public Filter indices( Set<Integer> idx ) {

indices.clear();
indices.addAll( valid );
listener.accept( this );
return this;
}

Expand Down Expand Up @@ -387,12 +410,14 @@ private boolean matches( Flow flow ) {
if( !includeTags.isEmpty() ) {
Set<String> includeIntersection = new HashSet<>( flow.meta().tags() );
includeIntersection.retainAll( includeTags );
included &= !includeIntersection.isEmpty();
// the flow bears *all* of the included tags
included &= includeIntersection.size() == includeTags.size();
}

if( !excludeTags.isEmpty() ) {
Set<String> excludeIntersection = new HashSet<>( flow.meta().tags() );
excludeIntersection.retainAll( excludeTags );
// the flow bears *none* of the excluded tags
included &= excludeIntersection.isEmpty();
}

Expand Down Expand Up @@ -421,6 +446,63 @@ public Stream<Flow> flows() {
return filtered.stream();
}

/**
* Computes the property values that recreate the settings of this
* {@link Filter}
*
* @param option The option
* @return The value for that option that would recreate the current filter
* configuration, or <code>null</code> if the supplied option is not
* relevant for filter configuration
*/
public String property( FilterOptions option ) {
if( option == FilterOptions.INCLUDE_TAGS && !includedTags().isEmpty() ) {
return includedTags().stream().collect( Collectors.joining( "," ) );
}
if( option == FilterOptions.EXCLUDE_TAGS && !excludedTags().isEmpty() ) {
return excludedTags().stream().collect( Collectors.joining( "," ) );
}
if( option == FilterOptions.INDICES ) {
return ranges( indices() );
}
return null;
}

/**
* Compresses integer values into ranges
*
* @param values The values, e.g.: [1,2,3,5]
* @return A string representing those values, e.g.: 1-3,5
*/
private static String ranges( Set<Integer> values ) {
Deque<Integer> dq = values.stream()
.filter( Objects::nonNull )
.sorted()
.collect( toCollection( ArrayDeque::new ) );

List<String> ranges = new ArrayList<>();

while( !dq.isEmpty() ) {
int low = dq.removeFirst().intValue();
int high = low;
while( !dq.isEmpty() && dq.peek().intValue() == high + 1 ) {
high = dq.removeFirst().intValue();
}
if( low == high ) {
ranges.add( String.valueOf( low ) );
}
else if( high - low == 1 ) {
ranges.add( String.valueOf( low ) );
ranges.add( String.valueOf( high ) );
}
else {
ranges.add( low + "-" + high );
}
}

return ranges.stream().collect( joining( "," ) );
}

private static class Persistence {

private static final Path persistencePath = Paths.get(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

package com.mastercard.test.flow.assrt.filter.gui;

import static java.awt.GridBagConstraints.BOTH;
import static java.awt.event.WindowEvent.WINDOW_CLOSING;

import java.awt.BorderLayout;
import java.awt.GraphicsEnvironment;
Expand Down Expand Up @@ -33,7 +33,7 @@
* - this can improve performance by avoiding building flows that will not be
* exercised.
*/
public class FilterGui extends JFrame {
public class FilterGui {

private static final long serialVersionUID = 1L;

Expand All @@ -54,7 +54,6 @@ public static boolean requested() {
* @param filter The filter to control
*/
public FilterGui( Filter filter ) {
super( "Flow filters" );
this.filter = filter;
}

Expand All @@ -67,8 +66,11 @@ public void blockForInput() {
final Object monitor = new Object();

SwingUtilities.invokeLater( () -> {
setDefaultCloseOperation( WindowConstants.DISPOSE_ON_CLOSE );
addWindowListener( new WindowAdapter() {
JFrame frame = new JFrame( "Flow filters" );
frame.setName( "flow_filter_frame" );
frame.setDefaultCloseOperation( WindowConstants.DISPOSE_ON_CLOSE );
frame.addWindowListener( new WindowAdapter() {

@Override
public void windowClosed( WindowEvent e ) {
updatesCompleted.set( true );
Expand All @@ -77,16 +79,11 @@ public void windowClosed( WindowEvent e ) {
}
}
} );
JButton build = new JButton( "Build" );
build.setName( "build_button" );
JButton run = new JButton( "Run" );
run.setName( "run_button" );
run.addActionListener( ac -> dispatchEvent( new WindowEvent( this, WINDOW_CLOSING ) ) );
getContentPane().add( buildGUI( build, run ) );
pack();
setLocationRelativeTo( null );
getRootPane().setDefaultButton( build );
setVisible( true );
frame.getContentPane().add( buildGUI( frame ) );
frame.setAlwaysOnTop( true );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible( true );
} );

synchronized( monitor ) {
Expand All @@ -102,8 +99,29 @@ public void windowClosed( WindowEvent e ) {
}
}

private JPanel buildGUI( JButton build, JButton run ) {
/**
* Builds the filter controls. The supplied frame will be updated to:
* <ul>
* <li>Control the default button - starting out as "build", but moving to "run"
* after that</li>
* <li>Provoke frame closure when "run" is clicked</li>
* </ul>
*
* @param frame The frame that will hold the controls
* @return The controls component
*/
public JPanel buildGUI( JFrame frame ) {

JButton build = new JButton( "Build" );
build.setName( "build_button" );
frame.getRootPane().setDefaultButton( build );

JButton run = new JButton( "Run" );
run.setName( "run_button" );
run.setEnabled( false );
run.addActionListener( ac -> frame.dispatchEvent(
new WindowEvent( frame, WindowEvent.WINDOW_CLOSING ) ) );

JTextField filterField = new JTextField();
filterField.setName( "filter_textfield" );
filterField.setHorizontalAlignment( SwingConstants.CENTER );
Expand Down Expand Up @@ -151,7 +169,7 @@ private JPanel buildGUI( JButton build, JButton run ) {
flowBuilding.set( true );
flowPanel.withListener( tagPanel::refreshAndLimitTags );
run.setEnabled( true );
SwingUtilities.getRootPane( run ).setDefaultButton( run );
frame.getRootPane().setDefaultButton( run );

panel.remove( buildPanel );
panel.add( flowPanel,
Expand Down
Loading