Add BondedRoles proposal and views

This commit is contained in:
Manfred Karrer 2018-07-23 02:22:18 +02:00
parent 6077cca35f
commit ccd3e9c5ba
No known key found for this signature in database
GPG key ID: 401250966A6B2C46
16 changed files with 973 additions and 163 deletions

View file

@ -136,12 +136,12 @@ class ArbitratorRegistrationViewModel extends ActivatableViewModel {
}
boolean setPrivKeyAndCheckPubKey(String privKeyString) {
ECKey _registrationKey = arbitratorManager.getRegistrationKey(privKeyString);
if (_registrationKey != null) {
String _registrationPubKeyAsHex = Utils.HEX.encode(_registrationKey.getPubKey());
ECKey registrationKey = arbitratorManager.getRegistrationKey(privKeyString);
if (registrationKey != null) {
String _registrationPubKeyAsHex = Utils.HEX.encode(registrationKey.getPubKey());
boolean isKeyValid = arbitratorManager.isPublicKeyInList(_registrationPubKeyAsHex);
if (isKeyValid) {
registrationKey = _registrationKey;
this.registrationKey = registrationKey;
registrationPubKeyAsHex.set(_registrationPubKeyAsHex);
}
updateDisableStates();

View file

@ -181,7 +181,7 @@ public abstract class BaseProposalView extends ActivatableView<GridPane, Void> {
proposalDisplayView.setManaged(true);
proposalDisplay.createAllFields(Res.get("dao.proposal.selectedProposal"), 0, 0, proposal.getType(),
false, false);
false);
proposalDisplay.setEditable(false);
proposalDisplay.applyProposalPayload(proposal);
proposalDisplayInitialized = true;

View file

@ -29,6 +29,7 @@ import bisq.desktop.main.MainView;
import bisq.desktop.main.dao.DaoView;
import bisq.desktop.main.dao.bonding.dashboard.BondingDashboardView;
import bisq.desktop.main.dao.bonding.lockup.LockupView;
import bisq.desktop.main.dao.bonding.roles.BondedRolesView;
import bisq.desktop.main.dao.bonding.unlock.UnlockView;
import bisq.core.locale.Res;
@ -52,7 +53,7 @@ public class BondingView extends ActivatableViewAndModel {
private final ViewLoader viewLoader;
private final Navigation navigation;
private MenuItem dashboard, lockupBSQ, unlockBSQ;
private MenuItem dashboard, bondedRoles, lockupBSQ, unlockBSQ;
private Navigation.Listener listener;
@FXML
@ -82,16 +83,20 @@ public class BondingView extends ActivatableViewAndModel {
final List<Class<? extends View>> baseNavPath = Arrays.asList(MainView.class, DaoView.class, bisq.desktop.main.dao.bonding.BondingView.class);
dashboard = new MenuItem(navigation, toggleGroup, Res.get("shared.dashboard"),
BondingDashboardView.class, AwesomeIcon.DASHBOARD, baseNavPath);
bondedRoles = new MenuItem(navigation, toggleGroup, Res.get("dao.bonding.menuItem.bondedRoles"),
BondedRolesView.class, AwesomeIcon.SHIELD, baseNavPath);
lockupBSQ = new MenuItem(navigation, toggleGroup, Res.get("dao.bonding.menuItem.lockupBSQ"),
LockupView.class, AwesomeIcon.LOCK, baseNavPath);
unlockBSQ = new MenuItem(navigation, toggleGroup, Res.get("dao.bonding.menuItem.unlockBSQ"),
UnlockView.class, AwesomeIcon.UNLOCK, baseNavPath);
leftVBox.getChildren().addAll(dashboard, lockupBSQ, unlockBSQ);
leftVBox.getChildren().addAll(dashboard, bondedRoles, lockupBSQ, unlockBSQ);
}
@Override
protected void activate() {
dashboard.activate();
bondedRoles.activate();
lockupBSQ.activate();
unlockBSQ.activate();
@ -100,7 +105,7 @@ public class BondingView extends ActivatableViewAndModel {
if (viewPath.size() == 3 && viewPath.indexOf(BondingView.class) == 2 ||
viewPath.size() == 2 && viewPath.indexOf(DaoView.class) == 1) {
if (selectedViewClass == null)
selectedViewClass = LockupView.class;
selectedViewClass = BondedRolesView.class;
loadView(selectedViewClass);
@ -115,6 +120,7 @@ public class BondingView extends ActivatableViewAndModel {
navigation.removeListener(listener);
dashboard.deactivate();
bondedRoles.deactivate();
lockupBSQ.deactivate();
unlockBSQ.deactivate();
}
@ -124,6 +130,7 @@ public class BondingView extends ActivatableViewAndModel {
content.getChildren().setAll(view.getRoot());
if (view instanceof BondingDashboardView) dashboard.setSelected(true);
else if (view instanceof BondedRolesView) bondedRoles.setSelected(true);
else if (view instanceof LockupView) lockupBSQ.setSelected(true);
else if (view instanceof UnlockView) unlockBSQ.setSelected(true);
}

View file

@ -35,10 +35,9 @@ import bisq.core.btc.wallet.BsqBalanceListener;
import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.btc.wallet.WalletsSetup;
import bisq.core.dao.DaoFacade;
import bisq.core.dao.bonding.Bond;
import bisq.core.dao.bonding.BondingConsensus;
import bisq.core.dao.bonding.Bonds;
import bisq.core.dao.bonding.lockup.LockupType;
import bisq.core.dao.role.BondedRole;
import bisq.core.locale.Res;
import bisq.core.util.BsqFormatter;
import bisq.core.util.validation.IntegerValidator;
@ -61,7 +60,6 @@ import javafx.collections.FXCollections;
import javafx.util.StringConverter;
import java.util.Arrays;
import java.util.Optional;
import static bisq.desktop.util.FormBuilder.addButtonAfterGroup;
import static bisq.desktop.util.FormBuilder.addLabelComboBox;
@ -84,10 +82,12 @@ public class LockupView extends ActivatableView<GridPane, Void> implements BsqBa
private InputTextField amountInputTextField;
private InputTextField timeInputTextField;
private ComboBox<LockupType> lockupTypeComboBox;
private ComboBox<Bond> bondsComboBox;
private ComboBox<BondedRole> bondedRolesComboBox;
private Button lockupButton;
private ChangeListener<Boolean> focusOutListener;
private ChangeListener<String> inputTextFieldListener;
private ChangeListener<BondedRole> bondedRolesListener;
private ChangeListener<LockupType> lockupTypeListener;
///////////////////////////////////////////////////////////////////////////////////////////
@ -134,11 +134,11 @@ public class LockupView extends ActivatableView<GridPane, Void> implements BsqBa
timeInputTextField.setValidator(timeInputTextFieldValidator);
lockupTypeComboBox = addLabelComboBox(root, ++gridRow, Res.get("dao.bonding.lock.type")).second;
lockupTypeComboBox.setPromptText(Res.get("list.currency.select"));
lockupTypeComboBox.setPromptText(Res.get("shared.select"));
lockupTypeComboBox.setConverter(new StringConverter<LockupType>() {
@Override
public String toString(LockupType lockupType) {
return lockupType.toString();
return lockupType.getDisplayString();
}
@Override
@ -147,35 +147,52 @@ public class LockupView extends ActivatableView<GridPane, Void> implements BsqBa
}
});
lockupTypeComboBox.setItems(FXCollections.observableArrayList(Arrays.asList(LockupType.values())));
lockupTypeListener = (observable, oldValue, newValue) -> {
if (newValue != null) {
bondedRolesComboBox.getSelectionModel().clearSelection();
}
};
//TODO handle trade type
lockupTypeComboBox.getSelectionModel().select(0);
bondsComboBox = addLabelComboBox(root, ++gridRow, Res.get("dao.bonding.lock.bonds")).second;
bondsComboBox.setPromptText(Res.get("list.currency.select"));
bondsComboBox.setConverter(new StringConverter<Bond>() {
bondedRolesComboBox = addLabelComboBox(root, ++gridRow, Res.get("dao.bonding.lock.bondedRoles")).second;
bondedRolesComboBox.setPromptText(Res.get("shared.select"));
bondedRolesComboBox.setConverter(new StringConverter<BondedRole>() {
@Override
public String toString(Bond bond) {
return bond.toDisplayString();
public String toString(BondedRole bondedRole) {
return bondedRole.getDisplayString();
}
@Override
public Bond fromString(String string) {
public BondedRole fromString(String string) {
return null;
}
});
bondsComboBox.setItems(FXCollections.observableArrayList(Bonds.getBonds()));
bondedRolesListener = (observable, oldValue, newValue) -> {
if (newValue != null) {
amountInputTextField.setText(bsqFormatter.formatCoin(Coin.valueOf(newValue.getBondedRoleType().getRequiredBond())));
timeInputTextField.setText(String.valueOf(newValue.getBondedRoleType().getUnlockTime()));
amountInputTextField.resetValidation();
timeInputTextField.resetValidation();
amountInputTextField.setEditable(false);
timeInputTextField.setEditable(false);
} else {
amountInputTextField.clear();
timeInputTextField.clear();
amountInputTextField.resetValidation();
timeInputTextField.resetValidation();
amountInputTextField.setEditable(true);
timeInputTextField.setEditable(true);
}
};
lockupButton = addButtonAfterGroup(root, ++gridRow, Res.get("dao.bonding.lock.lockupButton"));
lockupButton.setOnAction((event) -> {
if (GUIUtil.isReadyForTxBroadcast(p2PService, walletsSetup)) {
Coin lockupAmount = bsqFormatter.parseToCoin(amountInputTextField.getText());
int lockupTime = Integer.parseInt(timeInputTextField.getText());
LockupType type = lockupTypeComboBox.getValue();
//TODO use mapping to human readable input
Optional<byte[]> hashOfBondId;
if (type == LockupType.BONDED_ROLE) {
hashOfBondId = Optional.of(bondsComboBox.getSelectionModel().getSelectedItem().getHash());
} else {
hashOfBondId = Optional.empty();
}
LockupType lockupType = lockupTypeComboBox.getValue();
BondedRole bondedRole = bondedRolesComboBox.getValue();
new Popup<>().headLine(Res.get("dao.bonding.lock.sendFunds.headline"))
.confirmation(Res.get("dao.bonding.lock.sendFunds.details",
bsqFormatter.formatCoinWithCode(lockupAmount),
@ -185,8 +202,8 @@ public class LockupView extends ActivatableView<GridPane, Void> implements BsqBa
.onAction(() -> {
daoFacade.publishLockupTx(lockupAmount,
lockupTime,
type,
hashOfBondId,
lockupType,
bondedRole,
() -> {
new Popup<>().feedback(Res.get("dao.tx.published.success")).show();
},
@ -218,9 +235,12 @@ public class LockupView extends ActivatableView<GridPane, Void> implements BsqBa
amountInputTextField.textProperty().addListener(inputTextFieldListener);
timeInputTextField.textProperty().addListener(inputTextFieldListener);
amountInputTextField.focusedProperty().addListener(focusOutListener);
lockupTypeComboBox.getSelectionModel().selectedItemProperty().addListener(lockupTypeListener);
bondedRolesComboBox.getSelectionModel().selectedItemProperty().addListener(bondedRolesListener);
bsqWalletService.addBsqBalanceListener(this);
bondedRolesComboBox.setItems(FXCollections.observableArrayList(daoFacade.getBondedRoleList()));
onUpdateBalances();
}
@ -231,6 +251,8 @@ public class LockupView extends ActivatableView<GridPane, Void> implements BsqBa
amountInputTextField.textProperty().removeListener(inputTextFieldListener);
timeInputTextField.textProperty().removeListener(inputTextFieldListener);
amountInputTextField.focusedProperty().removeListener(focusOutListener);
lockupTypeComboBox.getSelectionModel().selectedItemProperty().removeListener(lockupTypeListener);
bondedRolesComboBox.getSelectionModel().selectedItemProperty().removeListener(bondedRolesListener);
bsqWalletService.removeBsqBalanceListener(this);
}
@ -259,7 +281,7 @@ public class LockupView extends ActivatableView<GridPane, Void> implements BsqBa
private void updateButtonState() {
lockupButton.setDisable(!bsqValidator.validate(amountInputTextField.getText()).isValid ||
!timeInputTextFieldValidator.validate(timeInputTextField.getText()).isValid ||
bondsComboBox.getSelectionModel().getSelectedItem() == null ||
bondedRolesComboBox.getSelectionModel().getSelectedItem() == null ||
lockupTypeComboBox.getSelectionModel().getSelectedItem() == null);
}

View file

@ -0,0 +1,93 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.desktop.main.dao.bonding.roles;
import bisq.desktop.main.overlays.Overlay;
import bisq.desktop.util.FormBuilder;
import bisq.core.dao.role.BondedRoleType;
import bisq.core.locale.Res;
import bisq.core.util.BsqFormatter;
import org.bitcoinj.core.Coin;
import javafx.geometry.Insets;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class BondedRoleTypeWindow extends Overlay<BondedRoleTypeWindow> {
private final BondedRoleType bondedRoleType;
private final BsqFormatter bsqFormatter;
public BondedRoleTypeWindow(BondedRoleType bondedRoleType, BsqFormatter bsqFormatter) {
this.bondedRoleType = bondedRoleType;
this.bsqFormatter = bsqFormatter;
width = 900;
type = Type.Confirmation;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Public API
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void show() {
headLine = Res.get("dao.bond.bondedRoleType.details.header");
createGridPane();
addHeadLine();
addSeparator();
addContent();
addCloseButton();
applyStyles();
display();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Protected
///////////////////////////////////////////////////////////////////////////////////////////
@Override
protected void createGridPane() {
super.createGridPane();
gridPane.setPadding(new Insets(35, 40, 30, 40));
gridPane.getStyleClass().add("grid-pane");
}
private void addContent() {
FormBuilder.addLabelTextField(gridPane, ++rowIndex, Res.getWithCol("dao.bond.bondedRoleType.details.role"),
bondedRoleType.getDisplayString());
FormBuilder.addLabelTextField(gridPane, ++rowIndex, Res.getWithCol("dao.bond.bondedRoleType.details.requiredBond"),
bsqFormatter.formatCoinWithCode(Coin.valueOf(bondedRoleType.getRequiredBond())));
FormBuilder.addLabelTextField(gridPane, ++rowIndex, Res.getWithCol("dao.bond.bondedRoleType.details.unlockTime"),
Res.get("dao.bond.bondedRoleType.details.blocks", bondedRoleType.getUnlockTime()));
FormBuilder.addLabelHyperlinkWithIcon(gridPane, ++rowIndex, Res.getWithCol("dao.bond.bondedRoleType.details.link"),
bondedRoleType.getLink(), bondedRoleType.getLink());
FormBuilder.addLabelTextField(gridPane, ++rowIndex, Res.getWithCol("dao.bond.bondedRoleType.details.isSingleton"),
bsqFormatter.booleanToYesNo(bondedRoleType.isAllowMultipleHolders()));
}
}

View file

@ -0,0 +1,72 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.desktop.main.dao.bonding.roles;
import bisq.desktop.components.AutoTooltipButton;
import bisq.core.dao.DaoFacade;
import bisq.core.dao.role.BondedRole;
import bisq.core.locale.Res;
import bisq.core.util.BsqFormatter;
import java.util.Date;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
@EqualsAndHashCode
@Data
class BondedRolesListItem {
@Getter
private final BondedRole bondedRole;
private final DaoFacade daoFacade;
private final BsqFormatter bsqFormatter;
private final AutoTooltipButton button;
BondedRolesListItem(BondedRole bondedRole,
DaoFacade daoFacade,
BsqFormatter bsqFormatter) {
this.bondedRole = bondedRole;
this.daoFacade = daoFacade;
this.bsqFormatter = bsqFormatter;
button = new AutoTooltipButton();
button.setMinWidth(70);
button.setText(Res.get("dao.bond.table.revoke"));
button.setVisible(true);
button.setManaged(true);
}
public String getStartDate() {
return bondedRole.getStartDate() > 0 ?
bsqFormatter.formatDateTime(new Date(bondedRole.getStartDate())) :
"-";
}
public String getRevokeDate() {
return bondedRole.getRevokeDate() > 0 ?
bsqFormatter.formatDateTime(new Date(bondedRole.getRevokeDate())) :
"-";
}
public static void cleanup() {
}
}

View file

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ This file is part of Bisq.
~
~ Bisq is free software: you can redistribute it and/or modify it
~ under the terms of the GNU Affero General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or (at
~ your option) any later version.
~
~ Bisq is distributed in the hope that it will be useful, but WITHOUT
~ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
~ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
~ License for more details.
~
~ You should have received a copy of the GNU Affero General Public License
~ along with Bisq. If not, see <http://www.gnu.org/licenses/>.
-->
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<GridPane fx:id="root" fx:controller="bisq.desktop.main.dao.bonding.roles.BondedRolesView"
hgap="5.0" vgap="5.0"
AnchorPane.bottomAnchor="20.0" AnchorPane.leftAnchor="20.0"
AnchorPane.rightAnchor="25.0" AnchorPane.topAnchor="20.0"
xmlns:fx="http://javafx.com/fxml">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" halignment="RIGHT" minWidth="160.0"/>
<ColumnConstraints hgrow="ALWAYS" minWidth="300.0"/>
</columnConstraints>
</GridPane>

View file

@ -0,0 +1,490 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.desktop.main.dao.bonding.roles;
import bisq.desktop.common.view.ActivatableView;
import bisq.desktop.common.view.FxmlView;
import bisq.desktop.components.AutoTooltipLabel;
import bisq.desktop.components.AutoTooltipTableColumn;
import bisq.desktop.components.HyperlinkWithIcon;
import bisq.desktop.components.TableGroupHeadline;
import bisq.desktop.main.dao.wallet.BsqBalanceUtil;
import bisq.desktop.util.GUIUtil;
import bisq.core.btc.wallet.WalletsSetup;
import bisq.core.dao.DaoFacade;
import bisq.core.dao.role.BondedRoleType;
import bisq.core.dao.state.BsqStateListener;
import bisq.core.dao.state.blockchain.Block;
import bisq.core.locale.Res;
import bisq.core.user.Preferences;
import bisq.core.util.BsqFormatter;
import bisq.network.p2p.P2PService;
import javax.inject.Inject;
import de.jensd.fx.fontawesome.AwesomeIcon;
import javafx.scene.control.Button;
import javafx.scene.control.Hyperlink;
import javafx.scene.control.Label;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.GridPane;
import javafx.geometry.Insets;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.SortedList;
import javafx.util.Callback;
import java.util.stream.Collectors;
@FxmlView
public class BondedRolesView extends ActivatableView<GridPane, Void> implements BsqStateListener {
private TableView<BondedRolesListItem> tableView;
private final BsqFormatter bsqFormatter;
private final DaoFacade daoFacade;
private final Preferences preferences;
private final WalletsSetup walletsSetup;
private final P2PService p2PService;
private int gridRow = 0;
private final ObservableList<BondedRolesListItem> observableList = FXCollections.observableArrayList();
private final SortedList<BondedRolesListItem> sortedList = new SortedList<>(observableList);
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, lifecycle
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
private BondedRolesView(BsqFormatter bsqFormatter,
BsqBalanceUtil bsqBalanceUtil,
DaoFacade daoFacade,
Preferences preferences,
WalletsSetup walletsSetup,
P2PService p2PService) {
this.bsqFormatter = bsqFormatter;
this.daoFacade = daoFacade;
this.preferences = preferences;
this.walletsSetup = walletsSetup;
this.p2PService = p2PService;
}
@Override
public void initialize() {
TableGroupHeadline headline = new TableGroupHeadline(Res.get("dao.bond.table.header"));
GridPane.setRowIndex(headline, gridRow);
GridPane.setMargin(headline, new Insets(0, -10, -10, -10));
GridPane.setColumnSpan(headline, 2);
root.getChildren().add(headline);
tableView = new TableView<>();
tableView.setPlaceholder(new AutoTooltipLabel(Res.get("table.placeholder.noData")));
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
createColumns();
GridPane.setRowIndex(tableView, gridRow);
GridPane.setMargin(tableView, new Insets(20, -10, 5, -10));
GridPane.setColumnSpan(tableView, 2);
root.getChildren().add(tableView);
sortedList.comparatorProperty().bind(tableView.comparatorProperty());
tableView.setItems(sortedList);
}
@Override
protected void activate() {
daoFacade.addBsqStateListener(this);
updateList();
}
@Override
protected void deactivate() {
daoFacade.removeBsqStateListener(this);
observableList.forEach(e -> BondedRolesListItem.cleanup());
}
///////////////////////////////////////////////////////////////////////////////////////////
// BsqStateListener
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void onNewBlockHeight(int blockHeight) {
}
@Override
public void onEmptyBlockAdded(Block block) {
}
@Override
public void onParseTxsComplete(Block block) {
updateList();
}
@Override
public void onParseBlockChainComplete() {
}
///////////////////////////////////////////////////////////////////////////////////////////
// Private
///////////////////////////////////////////////////////////////////////////////////////////
private void updateList() {
observableList.forEach(e -> BondedRolesListItem.cleanup());
observableList.setAll(daoFacade.getBondedRoleList().stream()
.map(bondedRole -> new BondedRolesListItem(bondedRole, daoFacade, bsqFormatter))
.collect(Collectors.toList()));
}
private void onButtonClick() {
if (GUIUtil.isReadyForTxBroadcast(p2PService, walletsSetup)) {
// revoke TODO
/* Optional<TxOutput> lockupTxOutput = daoFacade.getBondedRolesOutput(selectedItem.getTxId());
if (!lockupTxOutput.isPresent()) {
log.warn("Lockup output not found, txId = ", selectedItem.getTxId());
return;
}
Coin unlockAmount = Coin.valueOf(lockupTxOutput.get().getValue());
Optional<Integer> opLockTime = daoFacade.getLockTime(selectedItem.getTxId());
int lockTime = opLockTime.orElse(-1);
try {
new Popup<>().headLine(Res.get("dao.bonding.unlock.sendTx.headline"))
.confirmation(Res.get("dao.bonding.unlock.sendTx.details",
bsqFormatter.formatCoinWithCode(unlockAmount),
lockTime
))
.actionButtonText(Res.get("shared.yes"))
.onAction(() -> {
daoFacade.publishUnlockTx(selectedItem.getTxId(),
() -> {
new Popup<>().confirmation(Res.get("dao.tx.published.success")).show();
},
errorMessage -> new Popup<>().warning(errorMessage.toString()).show()
);
})
.closeButtonText(Res.get("shared.cancel"))
.show();
} catch (Throwable t) {
log.error(t.toString());
t.printStackTrace();
new Popup<>().warning(t.getMessage()).show();
}*/
} else {
GUIUtil.showNotReadyForTxBroadcastPopups(p2PService, walletsSetup);
}
// log.info("unlock tx: {}", selectedItem.getTxId());
}
private void openTxInBlockExplorer(String transactionId) {
if (transactionId != null)
GUIUtil.openWebPage(preferences.getBsqBlockChainExplorer().txUrl + transactionId);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Table columns
///////////////////////////////////////////////////////////////////////////////////////////
private void createColumns() {
TableColumn<BondedRolesListItem, BondedRolesListItem> column;
column = new AutoTooltipTableColumn<>(Res.get("dao.bond.table.column.header.name"));
column.setCellValueFactory(item -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setMinWidth(120);
column.setCellFactory(
new Callback<TableColumn<BondedRolesListItem, BondedRolesListItem>, TableCell<BondedRolesListItem,
BondedRolesListItem>>() {
@Override
public TableCell<BondedRolesListItem, BondedRolesListItem> call(TableColumn<BondedRolesListItem,
BondedRolesListItem> column) {
return new TableCell<BondedRolesListItem, BondedRolesListItem>() {
@Override
public void updateItem(final BondedRolesListItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null && !empty) {
setText(item.getBondedRole().getName());
} else
setText("");
}
};
}
});
tableView.getColumns().add(column);
column = new AutoTooltipTableColumn<>(Res.get("dao.bond.table.column.header.linkToAccount"));
column.setCellValueFactory(item -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setMinWidth(60);
column.setCellFactory(
new Callback<TableColumn<BondedRolesListItem, BondedRolesListItem>, TableCell<BondedRolesListItem,
BondedRolesListItem>>() {
@Override
public TableCell<BondedRolesListItem, BondedRolesListItem> call(TableColumn<BondedRolesListItem,
BondedRolesListItem> column) {
return new TableCell<BondedRolesListItem, BondedRolesListItem>() {
private HyperlinkWithIcon hyperlinkWithIcon;
@Override
public void updateItem(final BondedRolesListItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null && !empty) {
String link = item.getBondedRole().getLinkToAccount();
hyperlinkWithIcon = new HyperlinkWithIcon(link, AwesomeIcon.EXTERNAL_LINK);
hyperlinkWithIcon.setOnAction(event -> GUIUtil.openWebPage(link));
hyperlinkWithIcon.setTooltip(new Tooltip(Res.get("shared.openURL", link)));
setGraphic(hyperlinkWithIcon);
} else {
setGraphic(null);
if (hyperlinkWithIcon != null)
hyperlinkWithIcon.setOnAction(null);
}
}
};
}
});
tableView.getColumns().add(column);
column = new AutoTooltipTableColumn<>(Res.get("dao.bond.table.column.header.bondedRoleType"));
column.setCellValueFactory(item -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setMinWidth(120);
column.setCellFactory(
new Callback<TableColumn<BondedRolesListItem, BondedRolesListItem>, TableCell<BondedRolesListItem,
BondedRolesListItem>>() {
@Override
public TableCell<BondedRolesListItem, BondedRolesListItem> call(TableColumn<BondedRolesListItem,
BondedRolesListItem> column) {
return new TableCell<BondedRolesListItem, BondedRolesListItem>() {
private Hyperlink hyperlink;
@Override
public void updateItem(final BondedRolesListItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null && !empty) {
BondedRoleType bondedRoleType = item.getBondedRole().getBondedRoleType();
String type = bondedRoleType.getDisplayString();
hyperlink = new Hyperlink(type);
hyperlink.setOnAction(event -> {
new BondedRoleTypeWindow(bondedRoleType, bsqFormatter).show();
});
hyperlink.setTooltip(new Tooltip(Res.get("tooltip.openPopupForDetails", type)));
setGraphic(hyperlink);
} else {
setGraphic(null);
if (hyperlink != null)
hyperlink.setOnAction(null);
}
}
};
}
});
tableView.getColumns().add(column);
column = new AutoTooltipTableColumn<>(Res.get("dao.bond.table.column.header.startDate"));
column.setCellValueFactory(item -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setMinWidth(60);
column.setCellFactory(
new Callback<TableColumn<BondedRolesListItem, BondedRolesListItem>, TableCell<BondedRolesListItem,
BondedRolesListItem>>() {
@Override
public TableCell<BondedRolesListItem, BondedRolesListItem> call(TableColumn<BondedRolesListItem,
BondedRolesListItem> column) {
return new TableCell<BondedRolesListItem, BondedRolesListItem>() {
@Override
public void updateItem(final BondedRolesListItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null && !empty) {
setText(item.getStartDate());
} else
setText("");
}
};
}
});
tableView.getColumns().add(column);
column = new AutoTooltipTableColumn<>(Res.get("dao.bond.table.column.header.revokeDate"));
column.setCellValueFactory(item -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setMinWidth(60);
column.setCellFactory(
new Callback<TableColumn<BondedRolesListItem, BondedRolesListItem>, TableCell<BondedRolesListItem,
BondedRolesListItem>>() {
@Override
public TableCell<BondedRolesListItem, BondedRolesListItem> call(TableColumn<BondedRolesListItem,
BondedRolesListItem> column) {
return new TableCell<BondedRolesListItem, BondedRolesListItem>() {
@Override
public void updateItem(final BondedRolesListItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null && !empty) {
setText(item.getRevokeDate());
} else
setText("");
}
};
}
});
tableView.getColumns().add(column);
column = new AutoTooltipTableColumn<>(Res.get("dao.bond.table.column.header.lockupTxId"));
column.setCellValueFactory(item -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setMinWidth(60);
column.setCellFactory(
new Callback<TableColumn<BondedRolesListItem, BondedRolesListItem>, TableCell<BondedRolesListItem,
BondedRolesListItem>>() {
@Override
public TableCell<BondedRolesListItem, BondedRolesListItem> call(TableColumn<BondedRolesListItem,
BondedRolesListItem> column) {
return new TableCell<BondedRolesListItem, BondedRolesListItem>() {
private HyperlinkWithIcon hyperlinkWithIcon;
private Label label;
@Override
public void updateItem(final BondedRolesListItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null && !empty) {
String transactionId = item.getBondedRole().getLockupTxId();
if (transactionId != null) {
hyperlinkWithIcon = new HyperlinkWithIcon(transactionId, AwesomeIcon.EXTERNAL_LINK);
hyperlinkWithIcon.setOnAction(event -> openTxInBlockExplorer(transactionId));
hyperlinkWithIcon.setTooltip(new Tooltip(Res.get("tooltip.openBlockchainForTx", transactionId)));
setGraphic(hyperlinkWithIcon);
} else {
label = new Label("-");
setGraphic(label);
}
} else {
setGraphic(null);
if (hyperlinkWithIcon != null)
hyperlinkWithIcon.setOnAction(null);
if (label != null)
label = null;
}
}
};
}
});
tableView.getColumns().add(column);
column = new AutoTooltipTableColumn<>(Res.get("dao.bond.table.column.header.unlockTxId"));
column.setCellValueFactory(item -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setMinWidth(60);
column.setCellFactory(
new Callback<TableColumn<BondedRolesListItem, BondedRolesListItem>, TableCell<BondedRolesListItem,
BondedRolesListItem>>() {
@Override
public TableCell<BondedRolesListItem, BondedRolesListItem> call(TableColumn<BondedRolesListItem,
BondedRolesListItem> column) {
return new TableCell<BondedRolesListItem, BondedRolesListItem>() {
private HyperlinkWithIcon hyperlinkWithIcon;
private Label label;
@Override
public void updateItem(final BondedRolesListItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null && !empty) {
String transactionId = item.getBondedRole().getUnlockTxId();
if (transactionId != null) {
hyperlinkWithIcon = new HyperlinkWithIcon(transactionId, AwesomeIcon.EXTERNAL_LINK);
hyperlinkWithIcon.setOnAction(event -> openTxInBlockExplorer(transactionId));
hyperlinkWithIcon.setTooltip(new Tooltip(Res.get("tooltip.openBlockchainForTx", transactionId)));
setGraphic(hyperlinkWithIcon);
} else {
label = new Label("-");
setGraphic(label);
}
} else {
setGraphic(null);
if (hyperlinkWithIcon != null)
hyperlinkWithIcon.setOnAction(null);
if (label != null)
label = null;
}
}
};
}
});
tableView.getColumns().add(column);
column = new TableColumn<>();
column.setCellValueFactory(item -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setMinWidth(60);
column.setCellFactory(
new Callback<TableColumn<BondedRolesListItem, BondedRolesListItem>, TableCell<BondedRolesListItem,
BondedRolesListItem>>() {
@Override
public TableCell<BondedRolesListItem, BondedRolesListItem> call(TableColumn<BondedRolesListItem,
BondedRolesListItem> column) {
return new TableCell<BondedRolesListItem, BondedRolesListItem>() {
Button button;
@Override
public void updateItem(final BondedRolesListItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null && !empty) {
if (button == null) {
button = item.getButton();
button.setOnAction(e -> {
onButtonClick();
});
setGraphic(button);
}
} else {
setGraphic(null);
if (button != null) {
button.setOnAction(null);
button = null;
}
}
}
};
}
});
tableView.getColumns().add(column);
}
}

View file

@ -422,8 +422,8 @@ public class UnlockView extends ActivatableView<GridPane, Void> implements BsqBa
if (button == null) {
button = item.getButton();
button.setOnAction(e -> {
UnlockView.this.selectedItem = item;
UnlockView.this.onButtonClick();
selectedItem = item;
onButtonClick();
});
setGraphic(button);
}

View file

@ -28,8 +28,8 @@ import bisq.desktop.util.validation.BsqValidator;
import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.dao.DaoFacade;
import bisq.core.dao.bonding.Bond;
import bisq.core.dao.bonding.Bonds;
import bisq.core.dao.role.BondedRole;
import bisq.core.dao.role.BondedRoleType;
import bisq.core.dao.state.blockchain.Tx;
import bisq.core.dao.state.ext.Param;
import bisq.core.dao.voting.proposal.Proposal;
@ -39,10 +39,14 @@ import bisq.core.dao.voting.proposal.compensation.CompensationConsensus;
import bisq.core.dao.voting.proposal.compensation.CompensationProposal;
import bisq.core.dao.voting.proposal.confiscatebond.ConfiscateBondProposal;
import bisq.core.dao.voting.proposal.param.ChangeParamProposal;
import bisq.core.dao.voting.proposal.role.BondedRoleProposal;
import bisq.core.locale.Res;
import bisq.core.util.BsqFormatter;
import bisq.common.util.Tuple2;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
@ -56,12 +60,13 @@ import javafx.geometry.HPos;
import javafx.beans.value.ChangeListener;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.util.StringConverter;
import java.util.Optional;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
@ -80,7 +85,9 @@ public class ProposalDisplay {
private DaoFacade daoFacade;
private InputTextField uidTextField;
private TextField proposalFeeTextField;
private TextField proposalTypeTextField;
public InputTextField nameTextField;
@Nullable
public InputTextField titleTextField;
public InputTextField linkInputTextField;
@Nullable
@ -88,15 +95,20 @@ public class ProposalDisplay {
@Nullable
public ComboBox<Param> paramComboBox;
@Nullable
public ComboBox<byte[]> confiscateBondComboBox;
public ComboBox<BondedRole> confiscateBondComboBox;
@Nullable
public ComboBox<BondedRoleType> bondedRoleTypeComboBox;
@Getter
private int gridRow;
@Nullable
public TextArea descriptionTextArea;
private HyperlinkWithIcon linkHyperlinkWithIcon;
@Nullable
private TxIdTextField txIdTextField;
private final ChangeListener<String> descriptionTextAreaListener;
private int gridRowStartIndex;
private Label linkLabel;
// TODO get that warning at closing the window...
@ -115,90 +127,131 @@ public class ProposalDisplay {
descriptionTextAreaListener = (observable, oldValue, newValue) -> {
if (!ProposalConsensus.isDescriptionSizeValid(newValue)) {
new Popup<>().warning(Res.get("dao.proposal.display.description.tooLong", maxLengthDescriptionText)).show();
descriptionTextArea.setText(newValue.substring(0, maxLengthDescriptionText));
if (descriptionTextArea != null)
descriptionTextArea.setText(newValue.substring(0, maxLengthDescriptionText));
}
};
}
public void createAllFields(String title, int gridRowStartIndex, double top, ProposalType proposalType,
boolean isMakeProposalScreen, boolean showDetails) {
boolean isMakeProposalScreen) {
removeAllFields();
this.gridRowStartIndex = gridRowStartIndex;
this.gridRow = gridRowStartIndex;
int rowSpan;
boolean hasAddedFields = proposalType == ProposalType.COMPENSATION_REQUEST ||
proposalType == ProposalType.CHANGE_PARAM || proposalType == ProposalType.CONFISCATE_BOND;
if (isMakeProposalScreen) {
rowSpan = hasAddedFields ? 8 : 6;
} else if (showDetails) {
rowSpan = hasAddedFields ? 9 : 7;
} else {
//noinspection IfCanBeSwitch
if (proposalType == ProposalType.COMPENSATION_REQUEST)
rowSpan = 6;
else if (proposalType == ProposalType.CHANGE_PARAM)
rowSpan = 7;
else if (proposalType == ProposalType.CONFISCATE_BOND)
rowSpan = 6;
else
rowSpan = 5;
}
addTitledGroupBg(gridPane, gridRow, rowSpan, title, top);
if (showDetails) {
uidTextField = addLabelInputTextField(gridPane, gridRow,
Res.getWithCol("shared.id"), top == Layout.GROUP_DISTANCE ? Layout.FIRST_ROW_AND_GROUP_DISTANCE : Layout.FIRST_ROW_DISTANCE).second;
uidTextField.setEditable(false);
nameTextField = addLabelInputTextField(gridPane, ++gridRow, Res.get("dao.proposal.display.name")).second;
} else {
nameTextField = addLabelInputTextField(gridPane, gridRow, Res.get("dao.proposal.display.name"),
top == Layout.GROUP_DISTANCE ? Layout.FIRST_ROW_AND_GROUP_DISTANCE : Layout.FIRST_ROW_DISTANCE).second;
}
titleTextField = addLabelInputTextField(gridPane, ++gridRow, Res.getWithCol("dao.proposal.title")).second;
descriptionTextArea = addLabelTextArea(gridPane, ++gridRow, Res.get("dao.proposal.display.description"),
Res.get("dao.proposal.display.description.prompt", maxLengthDescriptionText)).second;
descriptionTextArea.setMaxHeight(42); // for 2 lines
descriptionTextArea.setMinHeight(descriptionTextArea.getMaxHeight());
if (isMakeProposalScreen)
descriptionTextArea.textProperty().addListener(descriptionTextAreaListener);
linkInputTextField = addLabelInputTextField(gridPane, ++gridRow, Res.get("dao.proposal.display.link")).second;
linkHyperlinkWithIcon = addLabelHyperlinkWithIcon(gridPane, gridRow, Res.get("dao.proposal.display.link"), "", "").second;
linkHyperlinkWithIcon.setVisible(false);
linkHyperlinkWithIcon.setManaged(false);
linkInputTextField.setPromptText(Res.get("dao.proposal.display.link.prompt"));
int rowSpan = 5;
boolean showTitle = true;
boolean showDescription = true;
switch (proposalType) {
case COMPENSATION_REQUEST:
rowSpan = 6;
break;
case BONDED_ROLE:
rowSpan = 3;
showTitle = false;
showDescription = false;
break;
case REMOVE_ALTCOIN:
break;
case CHANGE_PARAM:
rowSpan = 6;
break;
case GENERIC:
break;
case CONFISCATE_BOND:
rowSpan = 5;
break;
}
if (isMakeProposalScreen)
rowSpan += 2;
requestedBsqTextField = addLabelInputTextField(gridPane, ++gridRow, Res.get("dao.proposal.display.requestedBsq")).second;
addTitledGroupBg(gridPane, gridRow, rowSpan, title, top);
double proposalTypeTop = top == Layout.GROUP_DISTANCE ? Layout.FIRST_ROW_AND_GROUP_DISTANCE : Layout.FIRST_ROW_DISTANCE;
proposalTypeTextField = addLabelTextField(gridPane, gridRow,
Res.getWithCol("dao.proposal.display.type"), proposalType.getDisplayName(), proposalTypeTop).second;
if (!isMakeProposalScreen) {
uidTextField = addLabelInputTextField(gridPane, ++gridRow, Res.getWithCol("shared.id")).second;
uidTextField.setEditable(false);
nameTextField = addLabelInputTextField(gridPane, ++gridRow, Res.get("dao.proposal.display.name")).second;
} else {
nameTextField = addLabelInputTextField(gridPane, ++gridRow, Res.get("dao.proposal.display.name")).second;
}
if (showTitle)
titleTextField = addLabelInputTextField(gridPane, ++gridRow, Res.getWithCol("dao.proposal.title")).second;
if (showDescription) {
descriptionTextArea = addLabelTextArea(gridPane, ++gridRow, Res.get("dao.proposal.display.description"),
Res.get("dao.proposal.display.description.prompt", maxLengthDescriptionText)).second;
descriptionTextArea.setMaxHeight(42); // for 2 lines
descriptionTextArea.setMinHeight(descriptionTextArea.getMaxHeight());
if (isMakeProposalScreen)
descriptionTextArea.textProperty().addListener(descriptionTextAreaListener);
}
Tuple2<Label, InputTextField> tuple = addLabelInputTextField(gridPane, ++gridRow,
Res.get("dao.proposal.display.link"));
linkLabel = tuple.first;
linkInputTextField = tuple.second;
linkInputTextField.setPromptText(Res.get("dao.proposal.display.link.prompt"));
linkHyperlinkWithIcon = addLabelHyperlinkWithIcon(gridPane, gridRow,
"", "", "").second;
linkHyperlinkWithIcon.setVisible(false);
linkHyperlinkWithIcon.setManaged(false);
switch (proposalType) {
case COMPENSATION_REQUEST:
requestedBsqTextField = addLabelInputTextField(gridPane, ++gridRow,
Res.get("dao.proposal.display.requestedBsq")).second;
BsqValidator bsqValidator = new BsqValidator(bsqFormatter);
bsqValidator.setMinValue(CompensationConsensus.getMinCompensationRequestAmount());
checkNotNull(requestedBsqTextField, "requestedBsqTextField must not be null");
requestedBsqTextField.setValidator(bsqValidator);
// TODO validator, addressTF
if (showDetails) {
bsqAddressTextField = addLabelInputTextField(gridPane, ++gridRow,
Res.get("dao.proposal.display.bsqAddress")).second;
checkNotNull(bsqAddressTextField, "bsqAddressTextField must not be null");
bsqAddressTextField.setText("B" + bsqWalletService.getUnusedAddress().toBase58());
bsqAddressTextField.setValidator(new BsqAddressValidator(bsqFormatter));
}
bsqAddressTextField = addLabelInputTextField(gridPane, ++gridRow,
Res.get("dao.proposal.display.bsqAddress")).second;
checkNotNull(bsqAddressTextField, "bsqAddressTextField must not be null");
bsqAddressTextField.setText("B" + bsqWalletService.getUnusedAddress().toBase58());
bsqAddressTextField.setValidator(new BsqAddressValidator(bsqFormatter));
break;
case GENERIC:
case BONDED_ROLE:
linkLabel.setText(Res.get("dao.proposal.display.link.bondRole"));
linkInputTextField.setPromptText(Res.get("dao.proposal.display.link.bondRole.prompt"));
bondedRoleTypeComboBox = addLabelComboBox(gridPane, ++gridRow,
Res.getWithCol("dao.proposal.display.bondedRoleComboBox.label")).second;
checkNotNull(bondedRoleTypeComboBox, "bondedRoleTypeComboBox must not be null");
bondedRoleTypeComboBox.setPromptText(Res.get("shared.select"));
bondedRoleTypeComboBox.setItems(FXCollections.observableArrayList(BondedRoleType.values()));
bondedRoleTypeComboBox.setConverter(new StringConverter<BondedRoleType>() {
@Override
public String toString(BondedRoleType bondedRoleType) {
return bondedRoleType.getDisplayString();
}
@Override
public BondedRoleType fromString(String string) {
return null;
}
});
break;
case REMOVE_ALTCOIN:
break;
case CHANGE_PARAM:
checkNotNull(gridPane, "gridPane must not be null");
paramComboBox = addLabelComboBox(gridPane, ++gridRow, Res.get("dao.proposal.display.paramComboBox.label")).second;
paramComboBox = addLabelComboBox(gridPane, ++gridRow,
Res.getWithCol("dao.proposal.display.paramComboBox.label")).second;
checkNotNull(paramComboBox, "paramComboBox must not be null");
paramComboBox.setItems(FXCollections.observableArrayList(Param.values()));
paramComboBox.setPromptText(Res.get("shared.select"));
List<Param> list = Arrays.stream(Param.values())
.filter(e -> e != Param.UNDEFINED && e != Param.PHASE_UNDEFINED)
.collect(Collectors.toList());
paramComboBox.setItems(FXCollections.observableArrayList(list));
paramComboBox.setConverter(new StringConverter<Param>() {
@Override
public String toString(Param param) {
return param.name();
return param.toDisplayString();
}
@Override
@ -206,33 +259,32 @@ public class ProposalDisplay {
return null;
}
});
paramValueTextField = addLabelInputTextField(gridPane, ++gridRow, Res.get("dao.proposal.display.paramValue")).second;
paramValueTextField = addLabelInputTextField(gridPane, ++gridRow,
Res.get("dao.proposal.display.paramValue")).second;
break;
case REMOVE_ALTCOIN:
case GENERIC:
break;
case CONFISCATE_BOND:
confiscateBondComboBox = addLabelComboBox(gridPane, ++gridRow,
Res.get("dao.proposal.display.confiscateBondComboBox.label")).second;
ObservableList<byte[]> lockupAndUnlockingBondIds =
FXCollections.observableArrayList(daoFacade.getLockupAndUnlockingBondIds());
confiscateBondComboBox.setItems(lockupAndUnlockingBondIds);
confiscateBondComboBox.setConverter(new StringConverter<byte[]>() {
Res.getWithCol("dao.proposal.display.confiscateBondComboBox.label")).second;
checkNotNull(confiscateBondComboBox, "confiscateBondComboBox must not be null");
confiscateBondComboBox.setPromptText(Res.get("shared.select"));
confiscateBondComboBox.setItems(FXCollections.observableArrayList(daoFacade.getValidBondedRoleList()));
confiscateBondComboBox.setConverter(new StringConverter<BondedRole>() {
@Override
public String toString(byte[] hashOfBondId) {
Optional<Bond> bond = Bonds.getBond(hashOfBondId);
return bond.isPresent() ? bond.get().toDisplayString() : "-";
public String toString(BondedRole bondedRole) {
return bondedRole.getDisplayString();
}
@Override
public byte[] fromString(String string) {
public BondedRole fromString(String string) {
return null;
}
});
break;
}
if (!isMakeProposalScreen && showDetails)
if (!isMakeProposalScreen)
txIdTextField = addLabelTxIdTextField(gridPane, ++gridRow,
Res.get("dao.proposal.display.txId"), "").second;
@ -242,11 +294,14 @@ public class ProposalDisplay {
}
public void applyProposalPayload(Proposal proposal) {
proposalTypeTextField.setText(proposal.getType().getDisplayName());
if (uidTextField != null)
uidTextField.setText(proposal.getUid());
nameTextField.setText(proposal.getName());
titleTextField.setText(proposal.getTitle());
descriptionTextArea.setText(proposal.getDescription());
if (titleTextField != null)
titleTextField.setText(proposal.getTitle());
if (descriptionTextArea != null)
descriptionTextArea.setText(proposal.getDescription());
linkInputTextField.setVisible(false);
linkInputTextField.setManaged(false);
linkHyperlinkWithIcon.setVisible(true);
@ -265,10 +320,17 @@ public class ProposalDisplay {
paramComboBox.getSelectionModel().select(changeParamProposal.getParam());
checkNotNull(paramValueTextField, "paramValueTextField must not be null");
paramValueTextField.setText(String.valueOf(changeParamProposal.getParamValue()));
} else if (proposal instanceof BondedRoleProposal) {
BondedRoleProposal bondedRoleProposal = (BondedRoleProposal) proposal;
checkNotNull(bondedRoleTypeComboBox, "bondedRoleComboBox must not be null");
BondedRole bondedRole = bondedRoleProposal.getBondedRole();
bondedRoleTypeComboBox.getSelectionModel().select(bondedRole.getBondedRoleType());
} else if (proposal instanceof ConfiscateBondProposal) {
ConfiscateBondProposal confiscateBondProposal = (ConfiscateBondProposal) proposal;
checkNotNull(confiscateBondComboBox, "confiscateBondComboBox must not be null");
confiscateBondComboBox.getSelectionModel().select(confiscateBondProposal.getHashOfBondId());
daoFacade.getBondedRoleFromHash(confiscateBondProposal.getHash())
.ifPresent(bondedRole -> confiscateBondComboBox.getSelectionModel().select(bondedRole));
}
int chainHeight;
if (txIdTextField != null) {
@ -291,6 +353,7 @@ public class ProposalDisplay {
if (bsqAddressTextField != null) bsqAddressTextField.clear();
if (paramComboBox != null) paramComboBox.getSelectionModel().clearSelection();
if (paramValueTextField != null) paramValueTextField.clear();
if (bondedRoleTypeComboBox != null) bondedRoleTypeComboBox.getSelectionModel().clearSelection();
if (confiscateBondComboBox != null) confiscateBondComboBox.getSelectionModel().clearSelection();
if (txIdTextField != null) txIdTextField.cleanup();
if (descriptionTextArea != null) descriptionTextArea.textProperty().removeListener(descriptionTextAreaListener);
@ -299,8 +362,10 @@ public class ProposalDisplay {
public void fillWithMock() {
uidTextField.setText(UUID.randomUUID().toString());
nameTextField.setText("Manfred Karrer");
titleTextField.setText("Development work November 2017");
descriptionTextArea.setText("Development work");
if (titleTextField != null)
titleTextField.setText("Development work November 2017");
if (descriptionTextArea != null)
descriptionTextArea.setText("Development work");
linkInputTextField.setText("https://github.com/bisq-network/compensation/issues/12");
if (requestedBsqTextField != null)
requestedBsqTextField.setText("14000");
@ -315,8 +380,10 @@ public class ProposalDisplay {
public void setEditable(boolean isEditable) {
nameTextField.setEditable(isEditable);
titleTextField.setEditable(isEditable);
descriptionTextArea.setEditable(isEditable);
if (titleTextField != null)
titleTextField.setEditable(isEditable);
if (descriptionTextArea != null)
descriptionTextArea.setEditable(isEditable);
linkInputTextField.setEditable(isEditable);
if (requestedBsqTextField != null)
requestedBsqTextField.setEditable(isEditable);
@ -331,6 +398,9 @@ public class ProposalDisplay {
if (confiscateBondComboBox != null)
confiscateBondComboBox.setDisable(!isEditable);
if (bondedRoleTypeComboBox != null)
bondedRoleTypeComboBox.setDisable(!isEditable);
linkInputTextField.setVisible(true);
linkInputTextField.setManaged(true);
linkHyperlinkWithIcon.setVisible(false);

View file

@ -59,7 +59,7 @@ public class ProposalWindow extends Overlay<ProposalWindow> {
proposalDisplay = new ProposalDisplay(gridPane, bsqFormatter, bsqWalletService, daoFacade);
proposalDisplay.createAllFields(Res.get("dao.proposal.details"), 1, Layout.GROUP_DISTANCE,
proposal.getType(), false, true);
proposal.getType(), false);
proposalDisplay.setEditable(false);
proposalDisplay.applyProposalPayload(proposal);

View file

@ -123,7 +123,7 @@ public class ActiveProposalsView extends ProposalItemsView {
//noinspection IfCanBeSwitch,IfCanBeSwitch,IfCanBeSwitch
if (phase == DaoPhase.Phase.PROPOSAL) {
if (selectedBaseProposalListItem != null && selectedBaseProposalListItem.getProposal() != null) {
button.setText(Res.get("dao.proposal.active.remove"));
button.setText(Res.get("shared.remove"));
final boolean isMyProposal = daoFacade.isMyProposal(selectedBaseProposalListItem.getProposal());
button.setVisible(isMyProposal);
button.setManaged(isMyProposal);

View file

@ -30,6 +30,7 @@ import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.btc.wallet.InsufficientBsqException;
import bisq.core.btc.wallet.WalletsSetup;
import bisq.core.dao.DaoFacade;
import bisq.core.dao.role.BondedRole;
import bisq.core.dao.state.BsqStateListener;
import bisq.core.dao.state.blockchain.Block;
import bisq.core.dao.state.ext.Param;
@ -65,6 +66,8 @@ import javafx.util.StringConverter;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
@ -120,7 +123,7 @@ public class MakeProposalView extends ActivatableView<GridPane, Void> implements
proposalTypeComboBox.setConverter(new StringConverter<ProposalType>() {
@Override
public String toString(ProposalType proposalType) {
return Res.get("dao.proposal.type." + proposalType.name());
return proposalType.getDisplayName();
}
@Override
@ -135,7 +138,12 @@ public class MakeProposalView extends ActivatableView<GridPane, Void> implements
addProposalDisplay();
};
proposalTypeComboBox.setItems(FXCollections.observableArrayList(Arrays.asList(ProposalType.values())));
//TODO remove filter once all are implemented
List<ProposalType> proposalTypes = Arrays.stream(ProposalType.values())
.filter(proposalType -> proposalType != ProposalType.GENERIC &&
proposalType != ProposalType.REMOVE_ALTCOIN)
.collect(Collectors.toList());
proposalTypeComboBox.setItems(FXCollections.observableArrayList(proposalTypes));
}
@Override
@ -234,31 +242,42 @@ public class MakeProposalView extends ActivatableView<GridPane, Void> implements
WalletException, IOException {
validateInputs();
BondedRole bondedRole;
switch (type) {
case COMPENSATION_REQUEST:
checkNotNull(proposalDisplay.requestedBsqTextField,
"proposalDisplay.requestedBsqTextField must not be null");
checkNotNull(proposalDisplay.bsqAddressTextField,
"proposalDisplay.bsqAddressTextField must not be null");
checkNotNull(proposalDisplay.titleTextField,
"proposalDisplay.titleTextField must not be null");
checkNotNull(proposalDisplay.descriptionTextArea,
"proposalDisplay.descriptionTextArea must not be null");
return daoFacade.getCompensationProposalWithTransaction(proposalDisplay.nameTextField.getText(),
proposalDisplay.titleTextField.getText(),
proposalDisplay.descriptionTextArea.getText(),
proposalDisplay.linkInputTextField.getText(),
bsqFormatter.parseToCoin(proposalDisplay.requestedBsqTextField.getText()),
proposalDisplay.bsqAddressTextField.getText());
case GENERIC:
case BONDED_ROLE:
checkNotNull(proposalDisplay.bondedRoleTypeComboBox,
"proposalDisplay.bondedRoleTypeComboBox must not be null");
bondedRole = new BondedRole(proposalDisplay.nameTextField.getText(),
proposalDisplay.linkInputTextField.getText(),
proposalDisplay.bondedRoleTypeComboBox.getSelectionModel().getSelectedItem());
return daoFacade.getBondedRoleProposalWithTransaction(bondedRole);
case REMOVE_ALTCOIN:
//TODO
throw new RuntimeException("Not implemented yet");
/*
return genericBallotFactory.makeTxAndGetGenericProposal(
proposalDisplay.nameTextField.getText(),
proposalDisplay.titleTextField.getText(),
proposalDisplay.descriptionTextArea.getText(),
proposalDisplay.linkInputTextField.getText());*/
case CHANGE_PARAM:
checkNotNull(proposalDisplay.paramComboBox, "proposalDisplay.paramComboBox must no tbe null");
checkNotNull(proposalDisplay.paramValueTextField, "proposalDisplay.paramValueTextField must no tbe null");
checkNotNull(proposalDisplay.paramComboBox,
"proposalDisplay.paramComboBox must no tbe null");
checkNotNull(proposalDisplay.paramValueTextField,
"proposalDisplay.paramValueTextField must no tbe null");
checkNotNull(proposalDisplay.titleTextField,
"proposalDisplay.titleTextField must not be null");
checkNotNull(proposalDisplay.descriptionTextArea,
"proposalDisplay.descriptionTextArea must not be null");
Param selectedParam = proposalDisplay.paramComboBox.getSelectionModel().getSelectedItem();
if (selectedParam == null)
throw new ValidationException("selectedParam is null");
@ -272,26 +291,28 @@ public class MakeProposalView extends ActivatableView<GridPane, Void> implements
throw new ValidationException("paramValue is not a long value", t);
}
//TODO add more custom param validation
return daoFacade.getParamProposalWithTransaction(proposalDisplay.nameTextField.getText(),
proposalDisplay.titleTextField.getText(),
proposalDisplay.descriptionTextArea.getText(),
proposalDisplay.linkInputTextField.getText(),
selectedParam,
paramValue);
case REMOVE_ALTCOIN:
case GENERIC:
//TODO
throw new RuntimeException("Not implemented yet");
case CONFISCATE_BOND:
byte[] hashOfBondId = proposalDisplay.confiscateBondComboBox.getSelectionModel().getSelectedItem();
if (hashOfBondId == null || hashOfBondId.length == 0)
throw new ValidationException("Invalid bond id, null or zero length");
checkNotNull(proposalDisplay.confiscateBondComboBox,
"proposalDisplay.confiscateBondComboBox must not be null");
checkNotNull(proposalDisplay.titleTextField,
"proposalDisplay.titleTextField must not be null");
checkNotNull(proposalDisplay.descriptionTextArea,
"proposalDisplay.descriptionTextArea must not be null");
bondedRole = proposalDisplay.confiscateBondComboBox.getSelectionModel().getSelectedItem();
return daoFacade.getConfiscateBondProposalWithTransaction(proposalDisplay.nameTextField.getText(),
proposalDisplay.titleTextField.getText(),
proposalDisplay.descriptionTextArea.getText(),
proposalDisplay.linkInputTextField.getText(),
hashOfBondId);
bondedRole.getHash());
default:
final String msg = "Undefined ProposalType " + selectedProposalType;
log.error(msg);
@ -303,8 +324,9 @@ public class MakeProposalView extends ActivatableView<GridPane, Void> implements
if (selectedProposalType != null) {
proposalDisplay = new ProposalDisplay(root, bsqFormatter, bsqWalletService, daoFacade);
proposalDisplay.createAllFields(Res.get("dao.proposal.create.createNew"), 1, Layout.GROUP_DISTANCE,
selectedProposalType, true, true);
proposalDisplay.fillWithMock();
selectedProposalType, true);
// proposalDisplay.fillWithMock();
createButton = addButtonAfterGroup(root, proposalDisplay.incrementAndGetGridRow(), Res.get("dao.proposal.create.create.button"));
setCreateButtonHandler();
@ -332,10 +354,11 @@ public class MakeProposalView extends ActivatableView<GridPane, Void> implements
private void validateInputs() {
// We check in proposalDisplay that no invalid input as allowed
checkArgument(ProposalConsensus.isDescriptionSizeValid(proposalDisplay.descriptionTextArea.getText()),
"descriptionText must not be longer than " +
ProposalConsensus.getMaxLengthDescriptionText() + " chars");
if (proposalDisplay.descriptionTextArea != null) {
checkArgument(ProposalConsensus.isDescriptionSizeValid(proposalDisplay.descriptionTextArea.getText()),
"descriptionText must not be longer than " +
ProposalConsensus.getMaxLengthDescriptionText() + " chars");
}
// TODO add more checks for all input fields
}
}

View file

@ -243,6 +243,7 @@ public class ResultsView extends ActivatableViewAndModel<AnchorPane, Activatable
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
createColumns(tableView);
GridPane.setRowIndex(tableView, gridRow);
GridPane.setMargin(tableView, new Insets(20, -10, 5, -10));
GridPane.setColumnSpan(tableView, 2);
@ -274,16 +275,16 @@ public class ResultsView extends ActivatableViewAndModel<AnchorPane, Activatable
case BSQ_TAKER_FEE_IN_PERCENT:
case BTC_MAKER_FEE_IN_PERCENT:
case BTC_TAKER_FEE_IN_PERCENT:
label = Res.getWithCol("dao.results.cycle.param." + param.name());
label = Res.getWithCol("dao.param." + param.name());
value = bsqFormatter.formatToPercentWithSymbol(paramValue / 10000d);
break;
case PROPOSAL_FEE:
label = Res.getWithCol("dao.results.cycle.param." + param.name());
label = Res.getWithCol("dao.param." + param.name());
value = bsqFormatter.formatCoinWithCode(ProposalConsensus.getFee(bsqStateService, height));
break;
case BLIND_VOTE_FEE:
label = Res.getWithCol("dao.results.cycle.param." + param.name());
label = Res.getWithCol("dao.param." + param.name());
value = bsqFormatter.formatCoinWithCode(BlindVoteConsensus.getFee(bsqStateService, height));
break;
@ -292,7 +293,7 @@ public class ResultsView extends ActivatableViewAndModel<AnchorPane, Activatable
case QUORUM_CHANGE_PARAM:
case QUORUM_REMOVE_ASSET:
case QUORUM_CONFISCATION:
label = Res.getWithCol("dao.results.cycle.param." + param.name());
label = Res.getWithCol("dao.param." + param.name());
value = bsqFormatter.formatCoinWithCode(Coin.valueOf(paramValue));
break;
case THRESHOLD_PROPOSAL:
@ -301,7 +302,7 @@ public class ResultsView extends ActivatableViewAndModel<AnchorPane, Activatable
case THRESHOLD_CHANGE_PARAM:
case THRESHOLD_REMOVE_ASSET:
case THRESHOLD_CONFISCATION:
label = Res.getWithCol("dao.results.cycle.param." + param.name());
label = Res.getWithCol("dao.param." + param.name());
value = bsqFormatter.formatToPercentWithSymbol(paramValue / 10000d);
break;

View file

@ -17,6 +17,7 @@
package bisq.desktop.main.dao.results.proposals;
import bisq.core.dao.voting.proposal.ProposalType;
import bisq.core.dao.voting.proposal.compensation.CompensationProposal;
import bisq.core.dao.voting.voteresult.EvaluatedProposal;
import bisq.core.dao.voting.voteresult.ProposalVoteResult;
@ -82,18 +83,13 @@ public class ProposalResultsListItem {
}
public String getIssuance() {
switch (evaluatedProposal.getProposal().getType()) {
case COMPENSATION_REQUEST:
Coin requestedBsq = evaluatedProposal.isAccepted() ?
((CompensationProposal) evaluatedProposal.getProposal()).getRequestedBsq() :
Coin.ZERO;
return bsqFormatter.formatCoinWithCode(requestedBsq);
case GENERIC:
case CHANGE_PARAM:
case REMOVE_ALTCOIN:
default:
return "";
if (evaluatedProposal.getProposal().getType() == ProposalType.COMPENSATION_REQUEST) {
Coin requestedBsq = evaluatedProposal.isAccepted() ?
((CompensationProposal) evaluatedProposal.getProposal()).getRequestedBsq() :
Coin.ZERO;
return bsqFormatter.formatCoinWithCode(requestedBsq);
} else {
return "";
}
}
}

View file

@ -88,8 +88,8 @@ public class VoteResultsForProposalWindow extends Overlay<VoteResultsForProposal
@Override
public void show() {
rowIndex = -1;
width = MainView.getRootContainer().getWidth() - 20;
createGridPane();
addContent();
display();
@ -103,6 +103,7 @@ public class VoteResultsForProposalWindow extends Overlay<VoteResultsForProposal
@Override
protected void createGridPane() {
super.createGridPane();
gridPane.setPadding(new Insets(35, 40, 30, 40));
gridPane.getStyleClass().add("grid-pane");
}
@ -114,6 +115,7 @@ public class VoteResultsForProposalWindow extends Overlay<VoteResultsForProposal
GridPane.setColumnSpan(headline, 2);
gridPane.getChildren().add(headline);
// For some weird reason the stage key handler (ESC, ENTER) does not work as soon a tableView gets added...
tableView = new TableView<>();
tableView.setPlaceholder(new AutoTooltipLabel(Res.get("table.placeholder.noData")));
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);