diff --git a/client/src/main/java/ru/trader/db/controllers/ItemsController.java b/client/src/main/java/ru/trader/db/controllers/ItemsController.java new file mode 100644 index 0000000..8b7043d --- /dev/null +++ b/client/src/main/java/ru/trader/db/controllers/ItemsController.java @@ -0,0 +1,101 @@ +package ru.trader.db.controllers; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.fxml.FXML; +import javafx.scene.control.ButtonType; +import javafx.scene.control.TableColumn; +import javafx.scene.control.TableView; +import javafx.scene.control.cell.ComboBoxTableCell; +import ru.trader.controllers.MainController; +import ru.trader.controllers.Screeners; +import ru.trader.core.FACTION; +import ru.trader.core.GOVERNMENT; +import ru.trader.model.GroupModel; +import ru.trader.model.ItemModel; +import ru.trader.model.MarketModel; +import ru.trader.model.support.ChangeMarketListener; +import ru.trader.view.support.FactionStringConverter; +import ru.trader.view.support.GovernmentStringConverter; +import ru.trader.view.support.Localization; +import ru.trader.view.support.ViewUtils; +import ru.trader.view.support.cells.CheckComboBoxTableCell; + +import java.util.Collection; +import java.util.Optional; + +public class ItemsController { + + @FXML + private TableView tblItems; + @FXML + private TableColumn group; + @FXML + private TableColumn> factions; + @FXML + private TableColumn> governments; + + private ObservableList items = FXCollections.observableArrayList(); + private ObservableList groups = FXCollections.observableArrayList(); + private MarketModel world = null; + + @FXML + private void initialize() { + tblItems.setItems(items); + group.setCellFactory(ComboBoxTableCell.forTableColumn(groups)); + factions.setCellFactory(CheckComboBoxTableCell.forTableColumn(factions, + FXCollections.observableArrayList(FACTION.values()), new FactionStringConverter(), ItemModel::setIllegal) + ); + governments.setCellFactory(CheckComboBoxTableCell.forTableColumn(governments, + FXCollections.observableArrayList(GOVERNMENT.values()), new GovernmentStringConverter(), ItemModel::setIllegal) + ); + init(); + } + + void init(){ + if (world != null) world.getNotificator().remove(marketChangeListener); + world = MainController.getWorld(); + world.getNotificator().add(marketChangeListener); + items.clear(); + items.addAll(world.itemsProperty()); + groups.clear(); + groups.addAll(world.getGroups()); + } + + @FXML + private void add(){ + Screeners.showAddItem(world); + } + + @FXML + private void remove(){ + ItemModel item = tblItems.getSelectionModel().getSelectedItem(); + if (item != null){ + remove(item); + } + } + + private void remove(ItemModel item){ + Optional res = Screeners.showConfirm(String.format(Localization.getString("dialog.confirm.remove"), item.getName())); + if (res.isPresent() && res.get() == ButtonType.YES) { + world.remove(item); + } + } + + + private final ChangeMarketListener marketChangeListener = new ChangeMarketListener() { + @Override + public void add(ItemModel item) { + ViewUtils.doFX(() -> { + ItemsController.this.items.add(item); + }); + } + + @Override + public void remove(ItemModel item) { + ViewUtils.doFX(() -> { + ItemsController.this.items.remove(item); + }); + } + }; +} diff --git a/client/src/main/java/ru/trader/model/ItemModel.java b/client/src/main/java/ru/trader/model/ItemModel.java index 40f5d5c..1b751af 100644 --- a/client/src/main/java/ru/trader/model/ItemModel.java +++ b/client/src/main/java/ru/trader/model/ItemModel.java @@ -3,10 +3,13 @@ package ru.trader.model; import javafx.beans.property.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import ru.trader.core.FACTION; +import ru.trader.core.GOVERNMENT; import ru.trader.core.Item; import ru.trader.core.OFFER_TYPE; import ru.trader.view.support.Localization; +import java.util.Collection; import java.util.List; public class ItemModel implements Comparable { @@ -113,6 +116,26 @@ public class ItemModel implements Comparable { return item.getGroup() != null && item.getGroup().isMarket(); } + public Collection getIllegalFactions(){ + return item.getIllegalFactions(); + } + + public void setIllegalFactions(Collection factions){ + LOG.debug("Set illegal factions {}", factions); + } + + public void setIllegal(FACTION faction, boolean illegal){ + item.setIllegal(faction, illegal); + } + + public Collection getIllegalGovernments(){ + return item.getIllegalGovernments(); + } + + public void setIllegal(GOVERNMENT government, boolean illegal){ + item.setIllegal(government, illegal); + } + public void refresh(){ LOG.trace("Refresh stats of itemDesc {}", this); statBuy.refresh(); diff --git a/client/src/main/java/ru/trader/model/MarketModel.java b/client/src/main/java/ru/trader/model/MarketModel.java index a96169e..d72cbd6 100644 --- a/client/src/main/java/ru/trader/model/MarketModel.java +++ b/client/src/main/java/ru/trader/model/MarketModel.java @@ -162,6 +162,13 @@ public class MarketModel { return item; } + public void remove(ItemModel item) { + LOG.info("Remove item {} from market {}", item, this); + market.remove(ModelFabric.get(item)); + notificator.sendRemove(item); + items.remove(item); + } + ItemStat getStat(OFFER_TYPE type, Item item){ return market.getStat(type, item); } diff --git a/client/src/main/java/ru/trader/view/support/cells/CheckComboBoxTableCell.java b/client/src/main/java/ru/trader/view/support/cells/CheckComboBoxTableCell.java new file mode 100644 index 0000000..74b5a0b --- /dev/null +++ b/client/src/main/java/ru/trader/view/support/cells/CheckComboBoxTableCell.java @@ -0,0 +1,111 @@ +package ru.trader.view.support.cells; + + +import impl.org.controlsfx.skin.CheckComboBoxSkin; +import javafx.beans.value.ChangeListener; +import javafx.collections.ListChangeListener; +import javafx.collections.ObservableList; +import javafx.scene.control.*; +import javafx.util.Callback; +import javafx.util.StringConverter; +import org.controlsfx.control.CheckComboBox; + +import java.util.Collection; +import java.util.Optional; + +public class CheckComboBoxTableCell extends TableCell> { + private final CheckComboBox box; + private final ChangeListener onShowListener; + private ComboBox comboBox; + + public CheckComboBoxTableCell(final TableColumn> column, final ObservableList choiceList, final StringConverter converter, final CheckedFunction onCheckFunction) { + box = new CheckComboBox<>(choiceList); + box.setConverter(converter); + box.disableProperty().bind(column.editableProperty().not()); + + onShowListener = (ov, o, n) -> { + final TableView tableView = getTableView(); + if (n && !isEditing()) { + tableView.getSelectionModel().select(getTableRow().getIndex()); + tableView.edit(tableView.getSelectionModel().getSelectedIndex(), column); + } else { + if (!n && isEditing()) { + cancelEdit(); + } + } + }; + box.skinProperty().addListener(e -> { + if (comboBox != null){ + comboBox.showingProperty().removeListener(onShowListener); + } + comboBox = getComboBox(box); + if (comboBox != null) { + comboBox.showingProperty().addListener(onShowListener); + } else { + throw new IllegalStateException("Don't found ComboBox in checkComboBox"); + } + }); + box.getCheckModel().getCheckedItems().addListener((ListChangeListener) c -> { + if (isEditing()){ + @SuppressWarnings("unchecked") + S entry = (S) getTableRow().getItem(); + if (entry != null){ + while (c.next()) { + if (c.wasAdded()) + for (T item : c.getAddedSubList()) { + onCheckFunction.apply(entry, item, true); + } else if (c.wasRemoved()){ + for (T item : c.getRemoved()) { + onCheckFunction.apply(entry, item, false); + } + } + } + } + } + }); + setContentDisplay(ContentDisplay.GRAPHIC_ONLY); + } + + public static Callback>, TableCell>> forTableColumn(final TableColumn> column, final ObservableList choiceList, final StringConverter converter, final CheckedFunction onCheckFunction) { + return cell -> new CheckComboBoxTableCell<>(column, choiceList, converter, onCheckFunction); + } + + @Override + protected void updateItem(Collection items, boolean empty) { + super.updateItem(items, empty); + + setText(null); + if (empty || items == null) { + setGraphic(null); + } else { + checkAll(items); + setGraphic(box); + } + } + + private void checkAll(Collection items){ + box.getCheckModel().clearChecks(); + for (T item : items) { + box.getCheckModel().check(item); + } + } + + + private static ComboBox getComboBox(CheckComboBox box){ + Skin skin = box.getSkin(); + if (skin instanceof CheckComboBoxSkin){ + Optional node = ((CheckComboBoxSkin) skin).getChildren().stream().findFirst(); + if (node.isPresent() && node.get() instanceof ComboBox){ + return (ComboBox) node.get(); + } + } + return null; + } + + @FunctionalInterface + public interface CheckedFunction { + + void apply(S entry, T item, boolean check); + + } +} \ No newline at end of file diff --git a/client/src/main/resources/view/db/items.fxml b/client/src/main/resources/view/db/items.fxml new file mode 100644 index 0000000..703d438 --- /dev/null +++ b/client/src/main/resources/view/db/items.fxml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/core/src/main/java/ru/trader/store/simple/SimpleMarket.java b/core/src/main/java/ru/trader/store/simple/SimpleMarket.java index f161ea9..1d1a4ce 100644 --- a/core/src/main/java/ru/trader/store/simple/SimpleMarket.java +++ b/core/src/main/java/ru/trader/store/simple/SimpleMarket.java @@ -104,6 +104,16 @@ public class SimpleMarket extends AbstractMarket { @Override protected void removeItem(Item item) { + ItemStat stat = sellItems.get(item); + for (Offer offer : stat.getOffers()) { + SimpleVendor vendor = (SimpleVendor) offer.getVendor(); + vendor.removeOffer(offer); + } + stat = buyItems.get(item); + for (Offer offer : stat.getOffers()) { + SimpleVendor vendor = (SimpleVendor) offer.getVendor(); + vendor.removeOffer(offer); + } items.remove(item); sellItems.remove(item); buyItems.remove(item);