diff --git a/client/src/main/java/ru/trader/model/MarketModel.java b/client/src/main/java/ru/trader/model/MarketModel.java index 3a5fbc9..29b5059 100644 --- a/client/src/main/java/ru/trader/model/MarketModel.java +++ b/client/src/main/java/ru/trader/model/MarketModel.java @@ -87,6 +87,14 @@ public class MarketModel { return systemsList; } + public SystemModel get(String name){ + Place s = market.get(name); + if (s == null){ + return ModelFabric.NONE_SYSTEM; + } + return modeler.get(s); + } + public SystemModel add(String name, double x, double y, double z) { SystemModel system = modeler.get(market.addPlace(name, x, y, z)); LOG.info("Add system {} to market {}", system, this); diff --git a/client/src/main/java/ru/trader/view/support/autocomplete/AutoCompletion.java b/client/src/main/java/ru/trader/view/support/autocomplete/AutoCompletion.java new file mode 100644 index 0000000..54b4465 --- /dev/null +++ b/client/src/main/java/ru/trader/view/support/autocomplete/AutoCompletion.java @@ -0,0 +1,44 @@ +package ru.trader.view.support.autocomplete; + +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.scene.control.TextField; +import javafx.util.Callback; +import javafx.util.StringConverter; +import org.controlsfx.control.textfield.AutoCompletionBinding; +import org.controlsfx.control.textfield.TextFields; + +import java.util.Collection; + +public class AutoCompletion { + private final ObjectProperty completion = new SimpleObjectProperty<>(); + private final StringConverter converter; + private final AutoCompletionBinding binding; + + public AutoCompletion(final TextField textField, final Callback> suggestionProvider, final StringConverter converter) { + this.converter = converter; + binding = TextFields.bindAutoCompletion(textField, suggestionProvider, converter); + binding.setOnAutoCompleted(e -> completion.setValue(e.getCompletion())); + } + + public AutoCompletionBinding getBinding() { + return binding; + } + + public T getCompletion() { + return completion.get(); + } + + public ObjectProperty completionProperty() { + return completion; + } + + public void dispose(){ + binding.dispose(); + } + + public void setValue(T value) { + completion.setValue(value); + ((TextField)binding.getCompletionTarget()).setText(converter.toString(value)); + } +} diff --git a/client/src/main/java/ru/trader/view/support/autocomplete/CachedSuggestionProvider.java b/client/src/main/java/ru/trader/view/support/autocomplete/CachedSuggestionProvider.java new file mode 100644 index 0000000..db4bea6 --- /dev/null +++ b/client/src/main/java/ru/trader/view/support/autocomplete/CachedSuggestionProvider.java @@ -0,0 +1,77 @@ +package ru.trader.view.support.autocomplete; + + +import javafx.collections.ListChangeListener; +import javafx.collections.ObservableList; +import javafx.util.Callback; +import org.controlsfx.control.textfield.AutoCompletionBinding; + +import java.util.*; +import java.util.concurrent.locks.ReentrantLock; + +public abstract class CachedSuggestionProvider implements Callback> { + private final List cache = new ArrayList<>(); + private final ReentrantLock lock = new ReentrantLock(); + private final ObservableList possibleSuggestions; + private AutoCompletionBinding.ISuggestionRequest lastRequest; + + protected CachedSuggestionProvider(ObservableList possibleSuggestions) { + this.possibleSuggestions = possibleSuggestions; + possibleSuggestions.addListener(listChangeListener); + } + + @Override + public final Collection call(final AutoCompletionBinding.ISuggestionRequest request) { + List suggestions = new ArrayList<>(); + if(!request.getUserText().isEmpty()){ + lock.lock(); + try { + boolean cached = lastRequest != null && isContinue(lastRequest, request); + if (!cached){ + cache.clear(); + for (T possibleSuggestion : possibleSuggestions) { + if (isMatch(possibleSuggestion, request)) { + cache.add(possibleSuggestion); + } + } + Collections.sort(cache, getComparator()); + } else { + Iterator iterator = cache.iterator(); + while (iterator.hasNext()) { + T possibleSuggestion = iterator.next(); + if (!isMatch(possibleSuggestion, request)) { + iterator.remove(); + } + } + } + suggestions.addAll(cache); + lastRequest = request; + } finally { + lock.unlock(); + } + } + return suggestions; + } + + protected boolean isContinue(final AutoCompletionBinding.ISuggestionRequest lastRequest, final AutoCompletionBinding.ISuggestionRequest request){ + String last = lastRequest.getUserText(); + String current = request.getUserText(); + return last != null && current != null && current.toLowerCase().startsWith(last.toLowerCase()); + } + + protected abstract Comparator getComparator(); + protected abstract boolean isMatch(T suggestion, AutoCompletionBinding.ISuggestionRequest request); + + public void dispose(){ + possibleSuggestions.removeListener(listChangeListener); + } + + private final ListChangeListener listChangeListener = c -> { + lock.lock(); + try { + lastRequest = null; + } finally { + lock.unlock(); + } + }; +} diff --git a/client/src/main/java/ru/trader/view/support/autocomplete/SystemsProvider.java b/client/src/main/java/ru/trader/view/support/autocomplete/SystemsProvider.java new file mode 100644 index 0000000..39aaed1 --- /dev/null +++ b/client/src/main/java/ru/trader/view/support/autocomplete/SystemsProvider.java @@ -0,0 +1,36 @@ +package ru.trader.view.support.autocomplete; + +import javafx.util.StringConverter; +import org.controlsfx.control.textfield.AutoCompletionBinding; +import ru.trader.model.MarketModel; +import ru.trader.model.SystemModel; + +import java.util.Comparator; + +public class SystemsProvider extends CachedSuggestionProvider { + + private final StringConverter converter; + private final Comparator comparator; + + + public SystemsProvider(MarketModel market) { + super(market.systemsProperty()); + converter = new SystemsStringConverter(market); + comparator = (s1, s2) -> converter.toString(s1).toLowerCase().compareTo(converter.toString(s2).toLowerCase()); + } + + @Override + protected Comparator getComparator() { + return comparator; + } + + @Override + protected boolean isMatch(SystemModel suggestion, AutoCompletionBinding.ISuggestionRequest request) { + String s = converter.toString(suggestion).toLowerCase(); + return s.contains(request.getUserText().toLowerCase()); + } + + public StringConverter getConverter() { + return converter; + } +} diff --git a/client/src/main/java/ru/trader/view/support/autocomplete/SystemsStringConverter.java b/client/src/main/java/ru/trader/view/support/autocomplete/SystemsStringConverter.java new file mode 100644 index 0000000..70a75ed --- /dev/null +++ b/client/src/main/java/ru/trader/view/support/autocomplete/SystemsStringConverter.java @@ -0,0 +1,23 @@ +package ru.trader.view.support.autocomplete; + +import javafx.util.StringConverter; +import ru.trader.model.MarketModel; +import ru.trader.model.SystemModel; + +public class SystemsStringConverter extends StringConverter { + private final MarketModel market; + + public SystemsStringConverter(MarketModel market) { + this.market = market; + } + + @Override + public String toString(SystemModel system) { + return system.getName(); + } + + @Override + public SystemModel fromString(String name) { + return market.get(name); + } +}