Centralize query searching.
This commit is contained in:
		@@ -3,7 +3,7 @@ package com.lyndir.masterpassword.gui.view;
 | 
			
		||||
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
 | 
			
		||||
 | 
			
		||||
import com.google.common.base.*;
 | 
			
		||||
import com.google.common.collect.ImmutableList;
 | 
			
		||||
import com.google.common.collect.*;
 | 
			
		||||
import com.google.common.primitives.UnsignedInteger;
 | 
			
		||||
import com.google.common.util.concurrent.ListenableFuture;
 | 
			
		||||
import com.lyndir.lhunath.opal.system.logging.Logger;
 | 
			
		||||
@@ -650,8 +650,10 @@ public class UserContentPanel extends JPanel implements MasterPassword.Listener,
 | 
			
		||||
            JList<MPQuery.Result<? extends MPQuestion>> questionsList =
 | 
			
		||||
                    Components.list( questionsModel, this::getQuestionDescription );
 | 
			
		||||
            JTextField queryField = Components.textField( null, queryText -> Res.job( () -> {
 | 
			
		||||
                MPQuery                                          query         = new MPQuery( queryText );
 | 
			
		||||
                Collection<MPQuery.Result<? extends MPQuestion>> questionItems = new LinkedList<>( site.findQuestions( query ) );
 | 
			
		||||
                MPQuery query = new MPQuery( queryText );
 | 
			
		||||
                Collection<MPQuery.Result<? extends MPQuestion>> questionItems = new LinkedList<MPQuery.Result<? extends MPQuestion>>(
 | 
			
		||||
                        query.find( site.getQuestions(), MPQuestion::getKeyword ) );
 | 
			
		||||
 | 
			
		||||
                if (questionItems.stream().noneMatch( MPQuery.Result::isExact ))
 | 
			
		||||
                    questionItems.add( MPQuery.Result.allOf( new MPNewQuestion( site, query.getQuery() ), query.getQuery() ) );
 | 
			
		||||
 | 
			
		||||
@@ -814,7 +816,7 @@ public class UserContentPanel extends JPanel implements MasterPassword.Listener,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private String getSiteDescription(@Nullable final MPQuery.Result<? extends MPSite<?>> item) {
 | 
			
		||||
            MPSite<?> site = (item != null)? item.getOption(): null;
 | 
			
		||||
            MPSite<?> site = (item != null)? item.getValue(): null;
 | 
			
		||||
            if (site == null)
 | 
			
		||||
                return " ";
 | 
			
		||||
            if (site instanceof MPNewSite)
 | 
			
		||||
@@ -834,7 +836,7 @@ public class UserContentPanel extends JPanel implements MasterPassword.Listener,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private String getQuestionDescription(@Nullable final MPQuery.Result<? extends MPQuestion> item) {
 | 
			
		||||
            MPQuestion question = (item != null)? item.getOption(): null;
 | 
			
		||||
            MPQuestion question = (item != null)? item.getValue(): null;
 | 
			
		||||
            if (question == null)
 | 
			
		||||
                return "<site>";
 | 
			
		||||
            if (question instanceof MPNewQuestion)
 | 
			
		||||
@@ -876,7 +878,7 @@ public class UserContentPanel extends JPanel implements MasterPassword.Listener,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void showSiteItem(@Nullable final MPQuery.Result<? extends MPSite<?>> item) {
 | 
			
		||||
            MPSite<?> site = (item != null)? item.getOption(): null;
 | 
			
		||||
            MPSite<?> site = (item != null)? item.getValue(): null;
 | 
			
		||||
            Res.ui( getSiteResult( site, showLogin ), result -> {
 | 
			
		||||
                if (!showLogin && (site != null))
 | 
			
		||||
                    resultLabel.setText( (result != null)? strf( "Your password for %s:", site.getSiteName() ): " " );
 | 
			
		||||
@@ -937,7 +939,7 @@ public class UserContentPanel extends JPanel implements MasterPassword.Listener,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void showQuestionItem(@Nullable final MPQuery.Result<? extends MPQuestion> item) {
 | 
			
		||||
            MPQuestion question = (item != null)? item.getOption(): null;
 | 
			
		||||
            MPQuestion question = (item != null)? item.getValue(): null;
 | 
			
		||||
            Res.ui( getQuestionResult( question ), answer -> {
 | 
			
		||||
                if ((answer == null) || (question == null))
 | 
			
		||||
                    answerLabel.setText( " " );
 | 
			
		||||
@@ -988,7 +990,7 @@ public class UserContentPanel extends JPanel implements MasterPassword.Listener,
 | 
			
		||||
            if (selectedSite == null)
 | 
			
		||||
                return null;
 | 
			
		||||
 | 
			
		||||
            return selectedSite.getOption();
 | 
			
		||||
            return selectedSite.getValue();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Nullable
 | 
			
		||||
@@ -997,7 +999,7 @@ public class UserContentPanel extends JPanel implements MasterPassword.Listener,
 | 
			
		||||
            if (selectedQuestion == null)
 | 
			
		||||
                return null;
 | 
			
		||||
 | 
			
		||||
            return selectedQuestion.getOption();
 | 
			
		||||
            return selectedQuestion.getValue();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
@@ -1022,8 +1024,8 @@ public class UserContentPanel extends JPanel implements MasterPassword.Listener,
 | 
			
		||||
 | 
			
		||||
            updateSitesJob = Res.job( () -> {
 | 
			
		||||
                MPQuery query = new MPQuery( queryText );
 | 
			
		||||
                Collection<MPQuery.Result<? extends MPSite<?>>> siteItems =
 | 
			
		||||
                        new LinkedList<>( user.findSites( query ) );
 | 
			
		||||
                Collection<MPQuery.Result<? extends MPSite<?>>> siteItems = new LinkedList<MPQuery.Result<? extends MPSite<?>>>(
 | 
			
		||||
                        query.find( user.getSites(), MPSite::getSiteName ) );
 | 
			
		||||
 | 
			
		||||
                if (!Strings.isNullOrEmpty( queryText ))
 | 
			
		||||
                    if (siteItems.stream().noneMatch( MPQuery.Result::isExact )) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,13 @@
 | 
			
		||||
package com.lyndir.masterpassword.model;
 | 
			
		||||
 | 
			
		||||
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
 | 
			
		||||
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
 | 
			
		||||
 | 
			
		||||
import com.google.common.collect.ImmutableCollection;
 | 
			
		||||
import com.google.common.collect.ImmutableList;
 | 
			
		||||
import java.util.*;
 | 
			
		||||
import java.util.function.Function;
 | 
			
		||||
import javax.annotation.Nonnull;
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -30,9 +31,8 @@ public class MPQuery {
 | 
			
		||||
     * @return {@code true} if this query is contained wholly inside the given {@code key}.
 | 
			
		||||
     */
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    public <T extends Comparable<? super T>> Optional<Result<T>> find(final T option, final Function<T, CharSequence> keyForOption) {
 | 
			
		||||
        CharSequence key    = keyForOption.apply( option );
 | 
			
		||||
        Result<T>    result = Result.noneOf( option, key );
 | 
			
		||||
    public <V> Optional<Result<V>> matches(final V value, final CharSequence key) {
 | 
			
		||||
        Result<V> result = Result.noneOf( value, key );
 | 
			
		||||
        if (query.isEmpty())
 | 
			
		||||
            return Optional.of( result );
 | 
			
		||||
        if (key.length() == 0)
 | 
			
		||||
@@ -49,36 +49,49 @@ public class MPQuery {
 | 
			
		||||
            ++k;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // If query is consumed, the result is a hit.
 | 
			
		||||
        return (q >= query.length())? Optional.of( result ): Optional.empty();
 | 
			
		||||
        // If the match against the query broke before the end of the query, it failed.
 | 
			
		||||
        return (q < query.length())? Optional.empty(): Optional.of( result );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static class Result<T extends Comparable<? super T>> implements Comparable<Result<T>> {
 | 
			
		||||
    /**
 | 
			
		||||
     * @return Results for values that matched against the query, in the original values' order.
 | 
			
		||||
     */
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    public <V> ImmutableCollection<Result<? extends V>> find(final Iterable<? extends V> values,
 | 
			
		||||
                                                             final Function<V, CharSequence> valueToKey) {
 | 
			
		||||
        ImmutableList.Builder<Result<? extends V>> results = ImmutableList.builder();
 | 
			
		||||
        for (final V value : values)
 | 
			
		||||
            matches( value, valueToKey.apply( value ) ).ifPresent( results::add );
 | 
			
		||||
 | 
			
		||||
        private final T            option;
 | 
			
		||||
        return results.build();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static class Result<V> {
 | 
			
		||||
 | 
			
		||||
        private final V            value;
 | 
			
		||||
        private final CharSequence key;
 | 
			
		||||
        private final boolean[]    keyMatches;
 | 
			
		||||
 | 
			
		||||
        Result(final T option, final CharSequence key) {
 | 
			
		||||
            this.option = option;
 | 
			
		||||
        Result(final V value, final CharSequence key) {
 | 
			
		||||
            this.value = value;
 | 
			
		||||
            this.key = key;
 | 
			
		||||
 | 
			
		||||
            keyMatches = new boolean[key.length()];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static <T extends Comparable<? super T>> Result<T> noneOf(final T option, final CharSequence key) {
 | 
			
		||||
            return new Result<>( option, key );
 | 
			
		||||
        public static <T> Result<T> noneOf(final T value, final CharSequence key) {
 | 
			
		||||
            return new Result<>( value, key );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static <T extends Comparable<? super T>> Result<T> allOf(final T option, final CharSequence key) {
 | 
			
		||||
            Result<T> result = noneOf( option, key );
 | 
			
		||||
        public static <T> Result<T> allOf(final T value, final CharSequence key) {
 | 
			
		||||
            Result<T> result = noneOf( value, key );
 | 
			
		||||
            Arrays.fill( result.keyMatches, true );
 | 
			
		||||
            return result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Nonnull
 | 
			
		||||
        public T getOption() {
 | 
			
		||||
            return option;
 | 
			
		||||
        public V getValue() {
 | 
			
		||||
            return value;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Nonnull
 | 
			
		||||
@@ -130,23 +143,18 @@ public class MPQuery {
 | 
			
		||||
            keyMatches[k] = true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public int compareTo(@NotNull final Result<T> o) {
 | 
			
		||||
            return getOption().compareTo( o.getOption() );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public boolean equals(final Object o) {
 | 
			
		||||
            if (!(o instanceof Result))
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            Result<?> r = (Result<?>) o;
 | 
			
		||||
            return Objects.equals( option, r.option ) && Objects.equals( key, r.key ) && Arrays.equals( keyMatches, r.keyMatches );
 | 
			
		||||
            return Objects.equals( value, r.value ) && Objects.equals( key, r.key ) && Arrays.equals( keyMatches, r.keyMatches );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public int hashCode() {
 | 
			
		||||
            return getOption().hashCode();
 | 
			
		||||
            return getValue().hashCode();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,6 @@
 | 
			
		||||
 | 
			
		||||
package com.lyndir.masterpassword.model;
 | 
			
		||||
 | 
			
		||||
import com.google.common.collect.ImmutableCollection;
 | 
			
		||||
import com.google.common.primitives.UnsignedInteger;
 | 
			
		||||
import com.lyndir.masterpassword.*;
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
@@ -118,7 +117,4 @@ public interface MPSite<Q extends MPQuestion> extends Comparable<MPSite<?>> {
 | 
			
		||||
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    Collection<Q> getQuestions();
 | 
			
		||||
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    ImmutableCollection<MPQuery.Result<Q>> findQuestions(MPQuery query);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,6 @@
 | 
			
		||||
 | 
			
		||||
package com.lyndir.masterpassword.model;
 | 
			
		||||
 | 
			
		||||
import com.google.common.collect.ImmutableCollection;
 | 
			
		||||
import com.lyndir.masterpassword.*;
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
import javax.annotation.Nonnull;
 | 
			
		||||
@@ -111,9 +110,6 @@ public interface MPUser<S extends MPSite<?>> extends Comparable<MPUser<?>> {
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    Collection<S> getSites();
 | 
			
		||||
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    ImmutableCollection<MPQuery.Result<S>> findSites(MPQuery query);
 | 
			
		||||
 | 
			
		||||
    void addListener(Listener listener);
 | 
			
		||||
 | 
			
		||||
    void removeListener(Listener listener);
 | 
			
		||||
 
 | 
			
		||||
@@ -21,8 +21,6 @@ package com.lyndir.masterpassword.model.impl;
 | 
			
		||||
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*;
 | 
			
		||||
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
 | 
			
		||||
 | 
			
		||||
import com.google.common.collect.ImmutableCollection;
 | 
			
		||||
import com.google.common.collect.ImmutableSortedSet;
 | 
			
		||||
import com.google.common.primitives.UnsignedInteger;
 | 
			
		||||
import com.lyndir.masterpassword.*;
 | 
			
		||||
import com.lyndir.masterpassword.model.*;
 | 
			
		||||
@@ -39,7 +37,7 @@ public abstract class MPBasicSite<U extends MPUser<?>, Q extends MPQuestion> ext
 | 
			
		||||
 | 
			
		||||
    private final U             user;
 | 
			
		||||
    private final String        siteName;
 | 
			
		||||
    private final Collection<Q> questions = new LinkedHashSet<>();
 | 
			
		||||
    private final Collection<Q> questions = new TreeSet<>();
 | 
			
		||||
 | 
			
		||||
    private MPAlgorithm     algorithm;
 | 
			
		||||
    private UnsignedInteger counter;
 | 
			
		||||
@@ -202,16 +200,6 @@ public abstract class MPBasicSite<U extends MPUser<?>, Q extends MPQuestion> ext
 | 
			
		||||
        return Collections.unmodifiableCollection( questions );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    @Override
 | 
			
		||||
    public ImmutableCollection<MPQuery.Result<Q>> findQuestions(final MPQuery query) {
 | 
			
		||||
        ImmutableSortedSet.Builder<MPQuery.Result<Q>> results = ImmutableSortedSet.naturalOrder();
 | 
			
		||||
        for (final Q question : questions)
 | 
			
		||||
            query.find( question, MPQuestion::getKeyword ).ifPresent( results::add );
 | 
			
		||||
 | 
			
		||||
        return results.build();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected void onChanged() {
 | 
			
		||||
        super.onChanged();
 | 
			
		||||
 
 | 
			
		||||
@@ -20,8 +20,6 @@ package com.lyndir.masterpassword.model.impl;
 | 
			
		||||
 | 
			
		||||
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
 | 
			
		||||
 | 
			
		||||
import com.google.common.collect.ImmutableCollection;
 | 
			
		||||
import com.google.common.collect.ImmutableSortedSet;
 | 
			
		||||
import com.lyndir.lhunath.opal.system.CodeUtils;
 | 
			
		||||
import com.lyndir.lhunath.opal.system.logging.Logger;
 | 
			
		||||
import com.lyndir.masterpassword.*;
 | 
			
		||||
@@ -47,7 +45,7 @@ public abstract class MPBasicUser<S extends MPBasicSite<?, ?>> extends Changeabl
 | 
			
		||||
    @Nullable
 | 
			
		||||
    protected     MPMasterKey masterKey;
 | 
			
		||||
 | 
			
		||||
    private final Map<String, S> sites = new LinkedHashMap<>();
 | 
			
		||||
    private final Set<S> sites = new TreeSet<>();
 | 
			
		||||
 | 
			
		||||
    protected MPBasicUser(final String fullName, final MPAlgorithm algorithm) {
 | 
			
		||||
        this( 0, fullName, algorithm );
 | 
			
		||||
@@ -177,7 +175,7 @@ public abstract class MPBasicUser<S extends MPBasicSite<?, ?>> extends Changeabl
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    @Override
 | 
			
		||||
    public S addSite(final S site) {
 | 
			
		||||
        sites.put( site.getSiteName(), site );
 | 
			
		||||
        sites.add( site );
 | 
			
		||||
 | 
			
		||||
        setChanged();
 | 
			
		||||
        return site;
 | 
			
		||||
@@ -185,7 +183,7 @@ public abstract class MPBasicUser<S extends MPBasicSite<?, ?>> extends Changeabl
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean deleteSite(final MPSite<?> site) {
 | 
			
		||||
        if (!sites.values().remove( site ))
 | 
			
		||||
        if (!sites.remove( site ))
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        setChanged();
 | 
			
		||||
@@ -195,17 +193,7 @@ public abstract class MPBasicUser<S extends MPBasicSite<?, ?>> extends Changeabl
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    @Override
 | 
			
		||||
    public Collection<S> getSites() {
 | 
			
		||||
        return Collections.unmodifiableCollection( sites.values() );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Nonnull
 | 
			
		||||
    @Override
 | 
			
		||||
    public ImmutableCollection<MPQuery.Result<S>> findSites(final MPQuery query) {
 | 
			
		||||
        ImmutableSortedSet.Builder<MPQuery.Result<S>> results = ImmutableSortedSet.naturalOrder();
 | 
			
		||||
        for (final S site : sites.values())
 | 
			
		||||
            query.find( site, MPSite::getSiteName ).ifPresent( results::add );
 | 
			
		||||
 | 
			
		||||
        return results.build();
 | 
			
		||||
        return Collections.unmodifiableCollection( sites );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user