Archived
0

implement search stations

This commit is contained in:
iMoHax
2015-01-21 13:20:43 +03:00
parent d43af2939e
commit 7c1e828eae
16 changed files with 507 additions and 37 deletions

View File

@@ -0,0 +1,199 @@
package ru.trader.controllers;
import javafx.beans.property.*;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.util.StringConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.trader.core.MarketFilter;
import ru.trader.core.SERVICE_TYPE;
import ru.trader.model.*;
import ru.trader.model.support.BindingsHelper;
import ru.trader.model.support.ChangeMarketListener;
import ru.trader.view.support.NumberField;
import ru.trader.view.support.cells.CustomListCell;
import java.util.Collection;
import java.util.List;
public class SearchController {
private final static Logger LOG = LoggerFactory.getLogger(SearchController.class);
@FXML
private ComboBox<SystemModel> source;
@FXML
private ComboBox<ItemModel> items;
@FXML
private NumberField distance;
@FXML
private CheckBox cbMarket;
@FXML
private CheckBox cbBlackMarket;
@FXML
private CheckBox cbRepair;
@FXML
private CheckBox cbMunition;
@FXML
private CheckBox cbOutfit;
@FXML
private CheckBox cbShipyard;
@FXML
private CheckBox cbMediumLandpad;
@FXML
private CheckBox cbLargeLandpad;
@FXML
private TableView<ResultEntry> tblResults;
private final List<ResultEntry> results = FXCollections.observableArrayList();
private final ObservableList<ItemModel> itemsList = FXCollections.observableArrayList();
private MarketModel market;
@FXML
private void initialize() {
items.setCellFactory(new CustomListCell<>(ItemModel::getName));
items.setConverter(new StringConverter<ItemModel>() {
@Override
public String toString(ItemModel item) {
return item.getName();
}
@Override
public ItemModel fromString(String string) {
throw new UnsupportedOperationException("Is not editable field");
}
});
BindingsHelper.setTableViewItems(tblResults, results);
items.setItems(itemsList);
init();
}
void init(){
market = MainController.getMarket();
market.getNotificator().add(new SearchChangeListener());
source.setItems(market.systemsProperty());
itemsList.clear();
itemsList.add(ModelFabric.NONE_ITEM);
itemsList.addAll(market.itemsProperty().get());
source.getSelectionModel().selectFirst();
}
private void addItem(ItemModel item){
itemsList.add(item);
}
private void removeItem(ItemModel item){
itemsList.remove(item);
}
@FXML
private void searchStations(){
MarketFilter filter = new MarketFilter();
filter.setDistance(distance.getValue().doubleValue());
if (cbMarket.isSelected()) filter.add(SERVICE_TYPE.MARKET); else filter.remove(SERVICE_TYPE.MARKET);
if (cbBlackMarket.isSelected()) filter.add(SERVICE_TYPE.BLACK_MARKET); else filter.remove(SERVICE_TYPE.BLACK_MARKET);
if (cbMunition.isSelected()) filter.add(SERVICE_TYPE.MUNITION); else filter.remove(SERVICE_TYPE.MUNITION);
if (cbRepair.isSelected()) filter.add(SERVICE_TYPE.REPAIR); else filter.remove(SERVICE_TYPE.REPAIR);
if (cbOutfit.isSelected()) filter.add(SERVICE_TYPE.OUTFIT); else filter.remove(SERVICE_TYPE.OUTFIT);
if (cbShipyard.isSelected()) filter.add(SERVICE_TYPE.SHIPYARD); else filter.remove(SERVICE_TYPE.SHIPYARD);
if (cbMediumLandpad.isSelected()) filter.add(SERVICE_TYPE.MEDIUM_LANDPAD); else filter.remove(SERVICE_TYPE.MEDIUM_LANDPAD);
if (cbLargeLandpad.isSelected()) filter.add(SERVICE_TYPE.LARGE_LANDPAD); else filter.remove(SERVICE_TYPE.LARGE_LANDPAD);
ItemModel item = items.getValue();
if (item == null || item == ModelFabric.NONE_ITEM){
Collection<StationModel> stations = market.getStations(filter);
fill(stations);
} else {
Collection<OfferModel> offers = market.getOffers(item, filter);
fill(offers);
}
}
private void fill(Collection<?> entries){
results.clear();
for (Object entry : entries) {
if (entry instanceof StationModel){
results.add(new ResultEntry((StationModel) entry));
} else {
if (entry instanceof OfferModel) {
results.add(new ResultEntry((OfferModel) entry));
} else {
throw new IllegalArgumentException("Argument must have StationModel or OfferModel class");
}
}
}
}
public class ResultEntry {
private final StationModel station;
private final OfferModel offer;
private final ReadOnlyDoubleProperty distance;
private ResultEntry(StationModel station) {
this(station, null);
}
private ResultEntry(OfferModel offer) {
this(offer.getStation(), offer);
}
private ResultEntry(StationModel station, OfferModel offer) {
this.station = station;
this.offer = offer;
this.distance = new SimpleDoubleProperty(source.getValue().getDistance(station.getSystem()));
}
public SystemModel getSystem(){
return station.getSystem();
}
private StationModel getStation(){
return station;
}
private OfferModel getOffer() {
return offer;
}
public ReadOnlyStringProperty stationProperty(){
return new SimpleStringProperty(String.format("%s (%.0f Ls)", station.getName(), station.getDistance()));
}
public ReadOnlyStringProperty nameProperty(){
return offer != null ? offer.nameProperty() : new SimpleStringProperty("");
}
public ReadOnlyDoubleProperty priceProperty(){
return offer != null ? offer.priceProperty() : new SimpleDoubleProperty(Double.NaN);
}
public ReadOnlyLongProperty countProperty(){
return offer != null ? offer.countProperty() : new SimpleLongProperty(0);
}
public ReadOnlyDoubleProperty distanceProperty(){
return distance;
}
}
private class SearchChangeListener extends ChangeMarketListener {
@Override
public void add(ItemModel item) {
addItem(item);
}
@Override
public void remove(ItemModel item) {
removeItem(item);
}
}
}

View File

@@ -18,6 +18,12 @@ public class ItemModel {
private final ItemStatModel statSell;
private final ItemStatModel statBuy;
ItemModel() {
this.item = null;
this.statSell = null;
this.statBuy = null;
}
ItemModel(Item item, MarketModel market) {
this.item = item;
this.statSell = new ItemStatModel(market.getStat(OFFER_TYPE.SELL, item), market);
@@ -30,7 +36,7 @@ public class ItemModel {
public String getId() {return item.getName();}
public String getName() {return name != null ? name.get() : item.getName();}
public String getName() {return name != null ? name.get() : Localization.getString("item." + item.getName(), item.getName());}
public void setName(String value) {
LOG.info("Change name of item {} to {}", item, value);

View File

@@ -20,6 +20,7 @@ import ru.trader.services.OrdersSearchTask;
import ru.trader.services.RoutesSearchTask;
import ru.trader.view.support.Localization;
import java.util.Collection;
import java.util.function.Consumer;
@@ -122,6 +123,14 @@ public class MarketModel {
return market.getStat(type, item);
}
public ObservableList<OfferModel> getOffers(ItemModel item, MarketFilter filter){
return BindingsHelper.observableList(analyzer.getOffers(item.getItem(), filter), modeler::get);
}
public Collection<StationModel> getStations(MarketFilter filter){
return BindingsHelper.observableList(analyzer.getVendors(filter), modeler::get);
}
public void getOrders(SystemModel from, double balance, Consumer<ObservableList<OrderModel>> result) {
getOrders(from, ModelFabric.NONE_STATION, ModelFabric.NONE_SYSTEM, ModelFabric.NONE_STATION, balance, result);
}

View File

@@ -1,5 +1,7 @@
package ru.trader.model;
import javafx.beans.property.ReadOnlyDoubleProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
@@ -117,6 +119,7 @@ public class ModelFabric {
public static SystemModel NONE_SYSTEM = new FAKE_SYSTEM_MODEL();
public static StationModel NONE_STATION = new FAKE_STATION_MODEL();
public static ItemModel NONE_ITEM = new FAKE_ITEM_MODEL();
private static class FAKE_SYSTEM_MODEL extends SystemModel {
FAKE_SYSTEM_MODEL() {
@@ -130,7 +133,7 @@ public class ModelFabric {
@Override
public String getName() {
throw new UnsupportedOperationException("Is fake system, change unsupported");
return "";
}
@Override
@@ -207,7 +210,7 @@ public class ModelFabric {
@Override
public String getName() {
throw new UnsupportedOperationException("Is fake system, unsupported");
return "";
}
@Override
@@ -290,4 +293,110 @@ public class ModelFabric {
return "";
}
}
public static class FAKE_ITEM_MODEL extends ItemModel {
FAKE_ITEM_MODEL() {
super();
}
FAKE_ITEM_MODEL(Item item, MarketModel market) {
super(item, market);
}
@Override
Item getItem() {
throw new UnsupportedOperationException("Is fake item, unsupported");
}
@Override
public String getId() {
throw new UnsupportedOperationException("Is fake item, unsupported");
}
@Override
public String getName() {
return "";
}
@Override
public void setName(String value) {
throw new UnsupportedOperationException("Is fake item, unsupported");
}
@Override
public ReadOnlyStringProperty nameProperty() {
throw new UnsupportedOperationException("Is fake item, unsupported");
}
@Override
public ReadOnlyDoubleProperty avgBuyProperty() {
throw new UnsupportedOperationException("Is fake item, unsupported");
}
@Override
public ReadOnlyObjectProperty<OfferModel> minBuyProperty() {
throw new UnsupportedOperationException("Is fake item, unsupported");
}
@Override
public ReadOnlyObjectProperty<OfferModel> maxBuyProperty() {
throw new UnsupportedOperationException("Is fake item, unsupported");
}
@Override
public ReadOnlyObjectProperty<OfferModel> bestBuyProperty() {
throw new UnsupportedOperationException("Is fake item, unsupported");
}
@Override
public ReadOnlyDoubleProperty avgSellProperty() {
throw new UnsupportedOperationException("Is fake item, unsupported");
}
@Override
public ReadOnlyObjectProperty<OfferModel> minSellProperty() {
throw new UnsupportedOperationException("Is fake item, unsupported");
}
@Override
public ReadOnlyObjectProperty<OfferModel> maxSellProperty() {
throw new UnsupportedOperationException("Is fake item, unsupported");
}
@Override
public ReadOnlyObjectProperty<OfferModel> bestSellProperty() {
throw new UnsupportedOperationException("Is fake item, unsupported");
}
@Override
public List<OfferModel> getSeller() {
throw new UnsupportedOperationException("Is fake item, unsupported");
}
@Override
public List<OfferModel> getBuyer() {
throw new UnsupportedOperationException("Is fake item, unsupported");
}
@Override
public boolean isMarketItem() {
throw new UnsupportedOperationException("Is fake item, unsupported");
}
@Override
public void refresh() {
throw new UnsupportedOperationException("Is fake item, unsupported");
}
@Override
public void refresh(OFFER_TYPE type) {
throw new UnsupportedOperationException("Is fake item, unsupported");
}
@Override
public String toString() {
return "";
}
}
}

View File

@@ -29,7 +29,6 @@ market.order.seller=Seller
market.order.distance=Distance
# Route
routes=Routes
routes.path=Path
routes.jumps=Jumps
routes.refills=Refills
@@ -64,6 +63,8 @@ main.menu.settings.language=Language
main.menu.settings.language.item=English
main.menu.settings.parameters=Preferences
main.menu.settings.filter=Filter
main.tab.routes=Routes
main.tab.search=Search
# add item dialog
dialog.item.title=Adding new commodity
@@ -118,6 +119,7 @@ router.pane.route.to=To:
router.pane.route.jumps=Jumps:
router.button.recompute=Recompute
router.button.rebuild=Rebuild
router.button.routes=Routes
router.button.top=TOP 100
router.pane.total=Total
router.pane.total.profit=Profit:
@@ -155,4 +157,10 @@ analyzer.find.success=%d paths found
analyzer.graph.station.build=Building graph from %s (%s)
analyzer.graph.build=Building graph from %s
analyzer.graph.success=Graph is built
analyser.finish=Finish
analyser.finish=Finish
# search.fxml
search.text.from=From:
search.text.item=Commodity:
search.text.distance=Distance \nto station(Ls):
search.button.find=Find

View File

@@ -29,7 +29,6 @@ market.order.seller=\u041F\u0440\u043E\u0434\u0430\u0432\u0435\u0446
market.order.distance=\u0414\u0438\u0441\u0442\u0430\u043D\u0446\u0438\u044F
# Route
routes=\u041C\u0430\u0440\u0448\u0440\u0443\u0442\u044B
routes.path=\u041F\u0443\u0442\u044C
routes.jumps=\u041F\u0440\u044B\u0436\u043A\u043E\u0432
routes.refills=\u0417\u0430\u043F\u0440\u0430\u0432\u043E\u043A
@@ -65,6 +64,8 @@ main.menu.settings.language=\u042F\u0437\u044B\u043A
main.menu.settings.language.item=\u0420\u0443\u0441\u0441\u043A\u0438\u0439
main.menu.settings.parameters=\u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B
main.menu.settings.filter=\u0424\u0438\u043B\u044C\u0442\u0440
main.tab.routes=\u041C\u0430\u0440\u0448\u0440\u0443\u0442\u044B
main.tab.search=\u041F\u043E\u0438\u0441\u043A
# add item dialog
dialog.item.title=\u0414\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u043D\u043E\u0432\u043E\u0433\u043E \u0442\u043E\u0432\u0430\u0440\u0430
@@ -118,6 +119,7 @@ router.pane.route.to=\u0414\u043E:
router.pane.route.jumps=\u041F\u0440\u044B\u0436\u043A\u043E\u0432:
router.button.recompute=\u041F\u0435\u0440\u0435\u0441\u0447\u0438\u0442\u0430\u0442\u044C
router.button.rebuild=\u041F\u0435\u0440\u0435\u0441\u0442\u0440\u043E\u0438\u0442\u044C
router.button.routes=\u041C\u0430\u0440\u0448\u0440\u0443\u0442\u044B
router.button.top=TOP 100
router.pane.total=\u0418\u0442\u043E\u0433\u043E
router.pane.total.profit=\u041F\u0440\u0438\u0431\u044B\u043B\u044C:
@@ -155,4 +157,10 @@ analyzer.find.success=%d \u043F\u0443\u0442\u0435\u0439 \u043D\u0430\u0439\u0434
analyzer.graph.station.build=\u041F\u043E\u0441\u0442\u0440\u043E\u0439\u043A\u0430 \u0433\u0440\u0430\u0444\u0430 \u043E\u0442 %s (%s)
analyzer.graph.build=\u041F\u043E\u0441\u0442\u0440\u043E\u0439\u043A\u0430 \u0433\u0440\u0430\u0444\u0430 \u043E\u0442 %s
analyzer.graph.success=\u0413\u0440\u0430\u0444 \u043F\u043E\u0441\u0442\u0440\u043E\u0435\u043D
analyser.finish=\u0413\u043E\u0442\u043E\u0432\u043E
analyser.finish=\u0413\u043E\u0442\u043E\u0432\u043E
# search.fxml
search.text.from=\u041E\u0442:
search.text.item=\u0422\u043E\u0432\u0430\u0440:
search.text.distance=\u0414\u0438\u0441\u0442\u0430\u043D\u0446\u0438\u044F \n\u0434\u043E \u0441\u0442\u0430\u043D\u0446\u0438\u0438(Ls):
search.button.find=\u041D\u0430\u0439\u0442\u0438

View File

@@ -45,9 +45,12 @@
<Tab text="%market.systems">
<fx:include fx:id="offers" source="offers.fxml"/>
</Tab>
<Tab text="%routes">
<Tab text="%main.tab.routes">
<fx:include fx:id="router" source="router.fxml"/>
</Tab>
<Tab text="%main.tab.search">
<fx:include source="search.fxml"/>
</Tab>
</TabPane>
</center>

View File

@@ -64,7 +64,7 @@
<Button text="%router.button.top" onAction="#showTopOrders" />
</HBox>
<HBox alignment="CENTER" spacing="5">
<Button prefWidth="80" text="%routes" onAction="#showRoutes" />
<Button prefWidth="80" text="%router.button.routes" onAction="#showRoutes" />
<Button text="%router.button.top" onAction="#showTopRoutes" />
</HBox>
</VBox>

View File

@@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.control.cell.PropertyValueFactory?>
<?import ru.trader.view.support.NumberField?>
<?import ru.trader.view.support.cells.DistanceCell?>
<GridPane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="ru.trader.controllers.SearchController">
<fx:define><Insets fx:id="separator_margin" top="10" bottom="10"/></fx:define>
<columnConstraints>
<ColumnConstraints minWidth="270" maxWidth="270"/>
<ColumnConstraints fillWidth="true"/>
</columnConstraints>
<TitledPane text="%market.systems" prefHeight="590" collapsible="false">
<GridPane vgap="4">
<columnConstraints>
<ColumnConstraints minWidth="100"/>
<ColumnConstraints minWidth="150" maxWidth="150"/>
</columnConstraints>
<Label text="%search.text.from" />
<ComboBox fx:id="source" prefWidth="150" GridPane.columnIndex="1" />
<Label text="%search.text.item" GridPane.rowIndex="1"/>
<ComboBox fx:id="items" prefWidth="150" GridPane.columnIndex="1" GridPane.rowIndex="1"/>
<Label text="%search.text.distance" GridPane.rowIndex="2" />
<NumberField fx:id="distance" GridPane.columnIndex="1" GridPane.rowIndex="2" />
<Label text="%filter.services" GridPane.rowIndex="3" />
<TilePane hgap="5" vgap="5" tileAlignment="BASELINE_LEFT" GridPane.columnSpan="2" GridPane.rowIndex="4" >
<CheckBox fx:id="cbMarket" text="%services.MARKET"/>
<CheckBox fx:id="cbBlackMarket" text="%services.BLACK_MARKET"/>
<CheckBox fx:id="cbRepair" text="%services.REPAIR"/>
<CheckBox fx:id="cbMunition" text="%services.MUNITION"/>
<CheckBox fx:id="cbOutfit" text="%services.OUTFIT"/>
<CheckBox fx:id="cbShipyard" text="%services.SHIPYARD"/>
<CheckBox fx:id="cbMediumLandpad" text="%services.MEDIUM_LANDPAD"/>
<CheckBox fx:id="cbLargeLandpad" text="%services.LARGE_LANDPAD"/>
</TilePane>
<Separator GridPane.columnSpan="2" GridPane.rowIndex="5" GridPane.margin="$separator_margin"/>
<HBox GridPane.columnSpan="2" GridPane.rowIndex="6" spacing="10" alignment="CENTER">
<Button text="%search.button.find" onAction="#searchStations" />
</HBox>
</GridPane>
</TitledPane>
<TableView fx:id="tblResults" GridPane.columnIndex="1" GridPane.hgrow="ALWAYS" GridPane.vgrow="ALWAYS">
<columns>
<TableColumn minWidth="200.0" text="%market.system.name">
<cellValueFactory><PropertyValueFactory property="system"/></cellValueFactory>
</TableColumn>
<TableColumn minWidth="200.0" text="%market.station.name">
<cellValueFactory><PropertyValueFactory property="station"/></cellValueFactory>
</TableColumn>
<TableColumn minWidth="180.0" text="%market.item.name">
<cellValueFactory><PropertyValueFactory property="name"/></cellValueFactory>
</TableColumn>
<TableColumn minWidth="110.0" text="%market.offer.price">
<cellValueFactory><PropertyValueFactory property="price"/></cellValueFactory>
</TableColumn>
<TableColumn minWidth="110.0" text="%market.offer.supply">
<cellValueFactory><PropertyValueFactory property="count"/></cellValueFactory>
</TableColumn>
<TableColumn minWidth="110.0" text="%market.order.distance" fx:id="sortColumn" sortType="ASCENDING">
<cellFactory><DistanceCell /></cellFactory>
<cellValueFactory><PropertyValueFactory property="distance"/></cellValueFactory>
</TableColumn>
</columns>
<columnResizePolicy>
<TableView fx:constant="UNCONSTRAINED_RESIZE_POLICY"/>
</columnResizePolicy>
<sortOrder>
<fx:reference source="sortColumn"/>
</sortOrder>
</TableView>
</GridPane>