Merge branch 'master' into add-check-for-bsq-balance

# Conflicts:
#	core/src/main/resources/i18n/displayStrings.properties
This commit is contained in:
Manfred Karrer 2019-03-28 19:53:23 -05:00
commit 18a3f1e5fe
No known key found for this signature in database
GPG Key ID: 401250966A6B2C46
11 changed files with 163 additions and 63 deletions

View File

@ -198,6 +198,7 @@ shared.actions=Actions
shared.buyerUpperCase=Buyer
shared.sellerUpperCase=Seller
shared.new=NEW
shared.blindVoteTxId=Blind vote transaction ID
####################################################################
# UI views
@ -1677,7 +1678,6 @@ dao.proposal.type.short.GENERIC=Generic proposal
# suppress inspection "UnusedProperty"
dao.proposal.type.short.CONFISCATE_BOND=Confiscating a bond
dao.proposal.details=Proposal details
dao.proposal.selectedProposal=Selected proposal
dao.proposal.active.header=Proposals of current cycle
@ -1691,7 +1691,6 @@ dao.proposal.myVote.reject=Reject proposal
dao.proposal.myVote.removeMyVote=Ignore proposal
dao.proposal.myVote.merit=Vote weight from earned BSQ
dao.proposal.myVote.stake=Vote weight from stake
dao.proposal.myVote.blindVoteTxId=Blind vote transaction ID
dao.proposal.myVote.revealTxId=Vote reveal transaction ID
dao.proposal.myVote.stake.prompt=Max. available stake for voting: {0}
dao.proposal.votes.header=Set stake for voting and publish your votes

View File

@ -952,6 +952,7 @@ textfield */
}
.hyperlink,
.hyperlink.force-underline .text,
.hyperlink:hover,
.hyperlink:visited,
.hyperlink:hover:visited,

View File

@ -62,6 +62,10 @@ public class HyperlinkWithIcon extends Hyperlink {
setIcon(textIcon);
}
public void hideIcon() {
setGraphic(null);
}
private void setIcon(Node icon) {
setGraphic(icon);

View File

@ -19,12 +19,14 @@ package bisq.desktop.components;
import bisq.common.UserThread;
import de.jensd.fx.fontawesome.AwesomeIcon;
import de.jensd.fx.glyphs.GlyphIcons;
import org.controlsfx.control.PopOver;
import javafx.scene.Node;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Label;
import javafx.scene.text.Text;
import javafx.geometry.Insets;
@ -32,13 +34,9 @@ import java.util.concurrent.TimeUnit;
import static bisq.desktop.util.FormBuilder.getIcon;
import de.jensd.fx.glyphs.GlyphIcons;
public class InfoAutoTooltipLabel extends AutoTooltipLabel {
private Text textIcon;
private Node textIcon;
private Boolean hidePopover;
private PopOver infoPopover;
@ -46,12 +44,23 @@ public class InfoAutoTooltipLabel extends AutoTooltipLabel {
super(text);
textIcon = getIcon(icon);
addIcon(contentDisplay, info, 300);
}
public InfoAutoTooltipLabel(String text, AwesomeIcon icon, ContentDisplay contentDisplay, String info, double width) {
super(text);
textIcon = getIcon(icon);
addIcon(contentDisplay, info, width);
}
private void addIcon(ContentDisplay contentDisplay, String info, double width) {
textIcon.setOpacity(0.4);
textIcon.setOnMouseEntered(e -> {
hidePopover = false;
final Label helpLabel = new Label(info);
helpLabel.setMaxWidth(300);
helpLabel.setMaxWidth(width);
helpLabel.setWrapText(true);
helpLabel.setPadding(new Insets(10));
showInfoPopOver(helpLabel);
@ -73,6 +82,7 @@ public class InfoAutoTooltipLabel extends AutoTooltipLabel {
setContentDisplay(contentDisplay);
}
private void showInfoPopOver(Node node) {
node.getStyleClass().add("default-text");

View File

@ -21,6 +21,7 @@ import bisq.desktop.common.view.ActivatableView;
import bisq.desktop.common.view.FxmlView;
import bisq.desktop.components.AutoTooltipTableColumn;
import bisq.desktop.components.HyperlinkWithIcon;
import bisq.desktop.components.InfoAutoTooltipLabel;
import bisq.desktop.util.FormBuilder;
import bisq.desktop.util.GUIUtil;
@ -35,8 +36,10 @@ import bisq.core.util.BsqFormatter;
import javax.inject.Inject;
import de.jensd.fx.fontawesome.AwesomeIcon;
import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIcon;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
@ -253,14 +256,27 @@ public class BondsView extends ActivatableView<GridPane, Void> {
@Override
public TableCell<BondListItem, BondListItem> call(TableColumn<BondListItem, BondListItem> column) {
return new TableCell<>() {
private InfoAutoTooltipLabel infoTextField;
@Override
public void updateItem(final BondListItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null && !empty) {
setText(item.getBondDetails());
String info = Res.get("shared.id") + ": " + item.getBond().getBondedAsset().getUid();
if (item.getBond() instanceof BondedRole) {
info = item.getBondDetails() + "\n" + info;
}
infoTextField = new InfoAutoTooltipLabel(item.getBondDetails(),
AwesomeIcon.INFO_SIGN,
ContentDisplay.LEFT,
info,
350
);
setGraphic(infoTextField);
} else
setText("");
setGraphic(null);
}
};
}
@ -308,6 +324,7 @@ public class BondsView extends ActivatableView<GridPane, Void> {
hyperlinkWithIcon = new HyperlinkWithIcon(lockupTxId, MaterialDesignIcon.LINK);
hyperlinkWithIcon.setOnAction(event -> GUIUtil.openTxInBsqBlockExplorer(lockupTxId, preferences));
hyperlinkWithIcon.setTooltip(new Tooltip(Res.get("tooltip.openBlockchainForTx", lockupTxId)));
if (item.getLockupDateString().equals("-")) hyperlinkWithIcon.hideIcon();
setGraphic(hyperlinkWithIcon);
} else {
setGraphic(null);

View File

@ -63,7 +63,6 @@ import bisq.core.util.validation.UrlInputValidator;
import bisq.asset.Asset;
import bisq.common.util.Tuple3;
import bisq.common.util.Utilities;
import org.bitcoinj.core.Coin;
@ -87,6 +86,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import lombok.Getter;
@ -141,10 +141,11 @@ public class ProposalDisplay {
private ChangeListener<Param> paramChangeListener;
private ChangeListener<BondedRoleType> requiredBondForRoleListener;
private TitledGroupBg myVoteTitledGroup;
private int titledGroupBgRowSpan;
private VBox linkWithIconContainer, comboBoxValueContainer, myVoteBox, voteResultBox;
private int votingBoxRowSpan;
private Optional<Runnable> navigateHandlerOptional;
public ProposalDisplay(GridPane gridPane,
BsqFormatter bsqFormatter,
DaoFacade daoFacade,
@ -179,31 +180,27 @@ public class ProposalDisplay {
boolean isMakeProposalScreen) {
createAllFields(title, gridRowStartIndex, top, proposalType, isMakeProposalScreen, null);
}
public void createAllFields(String title, int gridRowStartIndex, double top, ProposalType proposalType,
boolean isMakeProposalScreen, String titledGroupStyle) {
removeAllFields();
this.gridRowStartIndex = gridRowStartIndex;
this.gridRow = gridRowStartIndex;
titledGroupBgRowSpan = 5;
int titledGroupBgRowSpan = 5;
switch (proposalType) {
case COMPENSATION_REQUEST:
case REIMBURSEMENT_REQUEST:
case CONFISCATE_BOND:
case REMOVE_ASSET:
break;
case CHANGE_PARAM:
titledGroupBgRowSpan = 6;
break;
case BONDED_ROLE:
titledGroupBgRowSpan = 6;
break;
case CONFISCATE_BOND:
break;
case GENERIC:
titledGroupBgRowSpan = 4;
break;
case REMOVE_ASSET:
break;
}
TitledGroupBg titledGroupBg = addTitledGroupBg(gridPane, gridRow, titledGroupBgRowSpan, title, top);
@ -358,16 +355,13 @@ public class ProposalDisplay {
confiscateBondComboBox.setConverter(new StringConverter<>() {
@Override
public String toString(Bond bond) {
String bondType;
String bondDetails;
if (bond instanceof BondedRole) {
bondType = Res.get("dao.bond.bondedRoles");
bondDetails = bond.getBondedAsset().getDisplayString();
} else {
bondType = Res.get("dao.bond.bondedReputation");
bondDetails = Utilities.bytesAsHexString(bond.getBondedAsset().getHash());
bondDetails = Res.get("dao.bond.bondedReputation");
}
return bondType + ": " + bondDetails;
return bondDetails + " (" + Res.get("shared.id") + ": " + bond.getBondedAsset().getUid() + ")";
}
@Override
@ -414,7 +408,6 @@ public class ProposalDisplay {
if (isMakeProposalScreen) {
proposalFeeTextField = addTopLabelTextField(gridPane, ++gridRow, Res.get("dao.proposal.display.proposalFee")).second;
//noinspection ConstantConditions
proposalFeeTextField.setText(bsqFormatter.formatCoinWithCode(daoFacade.getProposalFee(daoFacade.getChainHeight())));
}
@ -553,10 +546,13 @@ public class ProposalDisplay {
.ifPresent(bond -> {
confiscateBondComboBox.getSelectionModel().select(bond);
comboBoxValueTextField.setText(confiscateBondComboBox.getConverter().toString(bond));
comboBoxValueTextField.setOnMouseClicked(e ->
navigation.navigateToWithData(bond, MainView.class, DaoView.class, BondingView.class,
BondsView.class));
comboBoxValueTextField.getStyleClass().addAll("hyperlink", "show-hand");
comboBoxValueTextField.setOnMouseClicked(e -> {
navigateHandlerOptional.ifPresent(Runnable::run);
navigation.navigateToWithData(bond, MainView.class, DaoView.class, BondingView.class,
BondsView.class);
});
comboBoxValueTextField.getStyleClass().addAll("hyperlink", "force-underline", "show-hand");
});
} else if (proposal instanceof GenericProposal) {
// do nothing
@ -651,6 +647,10 @@ public class ProposalDisplay {
comboBoxes.clear();
}
public void onNavigate(Runnable navigateHandler) {
this.navigateHandlerOptional = Optional.of(navigateHandler);
}
public int incrementAndGetGridRow() {
return ++gridRow;
}

View File

@ -637,7 +637,7 @@ public class ProposalsView extends ActivatableView<GridPane, Void> implements Bs
voteFields.add(stakeInputTextField);
Tuple3<Label, TxIdTextField, VBox> tuple = addTopLabelTxIdTextField(root, ++gridRow,
Res.get("dao.proposal.myVote.blindVoteTxId"), 0);
Res.get("shared.blindVoteTxId"), 0);
blindVoteTxIdTextField = tuple.second;
blindVoteTxIdContainer = tuple.third;
blindVoteTxIdTextField.setBsq(true);

View File

@ -29,6 +29,7 @@ import org.bitcoinj.core.Coin;
import de.jensd.fx.fontawesome.AwesomeIcon;
import java.util.Date;
import java.util.Optional;
import lombok.Getter;
@ -48,6 +49,8 @@ public class VoteListItem {
private String blindVoteTxId = "";
@Getter
private String voteRevealTxId = "";
@Getter
private Date blindVoteDate;
VoteListItem(Proposal proposal,
DecryptedBallotsWithMerits decryptedBallotsWithMerits,
@ -62,6 +65,7 @@ public class VoteListItem {
merit = decryptedBallotsWithMerits.getMerit(daoStateService);
stake = decryptedBallotsWithMerits.getStake();
blindVoteTxId = decryptedBallotsWithMerits.getBlindVoteTxId();
daoStateService.getTx(blindVoteTxId).ifPresent(tx -> blindVoteDate = new Date(tx.getTime()));
voteRevealTxId = decryptedBallotsWithMerits.getVoteRevealTxId();
}
}

View File

@ -127,7 +127,8 @@ public class VoteResultView extends ActivatableView<GridPane, Void> implements D
private final BsqFormatter bsqFormatter;
private final MyProposalListService myProposalListService;
private final MyBlindVoteListService myBlindVoteListService;
private ProposalResultsWindow proposalResultsWindow;
private final ProposalResultsWindow proposalResultsWindow;
private Button exportButton;
private int gridRow = 0;
@ -192,6 +193,8 @@ public class VoteResultView extends ActivatableView<GridPane, Void> implements D
GridPane.setMargin(exportButton, new Insets(10, -10, -50, 0));
GridPane.setColumnSpan(exportButton, 2);
GridPane.setHalignment(exportButton, HPos.RIGHT);
proposalResultsWindow.onClose(() -> proposalsTableView.getSelectionModel().clearSelection());
}
@Override
@ -267,7 +270,7 @@ public class VoteResultView extends ActivatableView<GridPane, Void> implements D
item.getResultsOfCycle().getCycle().getHeightOfFirstBlock()))
.forEach(e -> {
sb.append("\n")
.append(Res.getWithCol("dao.proposal.myVote.blindVoteTxId")).append(" ")
.append(Res.getWithCol("shared.blindVoteTxId")).append(" ")
.append(e.getBlindVoteTxId()).append("\n")
.append(Res.getWithCol("dao.results.votes.table.header.stake")).append(" ")
.append(bsqFormatter.formatCoinWithCode(Coin.valueOf(e.getStake()))).append("\n");

View File

@ -3,14 +3,15 @@ package bisq.desktop.main.overlays.windows;
import bisq.desktop.Navigation;
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.governance.ProposalDisplay;
import bisq.desktop.main.dao.governance.result.VoteListItem;
import bisq.desktop.main.overlays.TabbedOverlay;
import bisq.desktop.util.GUIUtil;
import bisq.desktop.util.Layout;
import bisq.core.dao.DaoFacade;
import bisq.core.dao.governance.proposal.param.ChangeParamValidator;
import bisq.core.dao.state.model.governance.Ballot;
import bisq.core.dao.state.model.governance.EvaluatedProposal;
import bisq.core.dao.state.model.governance.Proposal;
@ -24,6 +25,7 @@ import javax.inject.Inject;
import de.jensd.fx.fontawesome.AwesomeDude;
import de.jensd.fx.fontawesome.AwesomeIcon;
import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIcon;
import javafx.scene.Scene;
import javafx.scene.control.Button;
@ -32,6 +34,7 @@ import javafx.scene.control.Tab;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.Tooltip;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
@ -47,8 +50,6 @@ import javafx.collections.transformation.SortedList;
import javafx.util.Callback;
import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
import static bisq.desktop.util.FormBuilder.addButtonAfterGroup;
@ -58,15 +59,8 @@ public class ProposalResultsWindow extends TabbedOverlay<ProposalResultsWindow>
private final BsqFormatter bsqFormatter;
private final DaoFacade daoFacade;
private final ChangeParamValidator changeParamValidator;
private final Navigation navigation;
private final Preferences preferences;
private Optional<Runnable> acceptHandlerOptional;
private Optional<Runnable> rejectHandlerOptional;
private Optional<Runnable> ignoreHandlerOptional;
private Optional<Runnable> removeHandlerOptional;
private EvaluatedProposal evaluatedProposal;
private Ballot ballot;
private boolean isVoteIncludedInResult;
private SortedList<VoteListItem> sortedVotes;
private Tab proposalTab, votesTab;
@ -76,12 +70,12 @@ public class ProposalResultsWindow extends TabbedOverlay<ProposalResultsWindow>
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
public ProposalResultsWindow(BsqFormatter bsqFormatter, DaoFacade daoFacade,
ChangeParamValidator changeParamValidator, Navigation navigation,
public ProposalResultsWindow(BsqFormatter bsqFormatter,
DaoFacade daoFacade,
Navigation navigation,
Preferences preferences) {
this.bsqFormatter = bsqFormatter;
this.daoFacade = daoFacade;
this.changeParamValidator = changeParamValidator;
this.navigation = navigation;
this.preferences = preferences;
}
@ -89,8 +83,6 @@ public class ProposalResultsWindow extends TabbedOverlay<ProposalResultsWindow>
public void show(EvaluatedProposal evaluatedProposal, Ballot ballot,
boolean isVoteIncludedInResult, SortedList<VoteListItem> sortedVotes) {
this.evaluatedProposal = evaluatedProposal;
this.ballot = ballot;
this.isVoteIncludedInResult = isVoteIncludedInResult;
this.sortedVotes = sortedVotes;
@ -166,10 +158,9 @@ public class ProposalResultsWindow extends TabbedOverlay<ProposalResultsWindow>
votesTab.setContent(createVotesTable());
}
private Button addCloseButton(GridPane gridPane, int rowIndex) {
private void addCloseButton(GridPane gridPane, int rowIndex) {
Button closeButton = addButtonAfterGroup(gridPane, rowIndex, Res.get("shared.close"));
closeButton.setOnAction(event -> doClose());
return closeButton;
}
private GridPane createVotesTable() {
@ -191,7 +182,7 @@ public class ProposalResultsWindow extends TabbedOverlay<ProposalResultsWindow>
GridPane.setColumnSpan(votesTableHeader, 2);
votesGridPane.getChildren().add(votesTableHeader);
TableView votesTableView = new TableView<>();
TableView<VoteListItem> votesTableView = new TableView<>();
votesTableView.setPlaceholder(new AutoTooltipLabel(Res.get("table.placeholder.noData")));
votesTableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
@ -212,11 +203,12 @@ public class ProposalResultsWindow extends TabbedOverlay<ProposalResultsWindow>
private void createColumns(TableView<VoteListItem> votesTableView) {
TableColumn<VoteListItem, VoteListItem> column;
column = new AutoTooltipTableColumn<>(Res.get("dao.results.votes.table.header.vote"));
column.setSortable(false);
column.setMinWidth(50);
column.setMaxWidth(column.getMinWidth());
column = new AutoTooltipTableColumn<>(Res.get("shared.dateTime"));
column.getStyleClass().add("first-column");
column.setSortable(false);
column.setMinWidth(180);
column.setMaxWidth(column.getMinWidth() + 20);
column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setCellFactory(
new Callback<>() {
@ -224,20 +216,49 @@ public class ProposalResultsWindow extends TabbedOverlay<ProposalResultsWindow>
public TableCell<VoteListItem, VoteListItem> call(
TableColumn<VoteListItem, VoteListItem> column) {
return new TableCell<>() {
private Label icon;
@Override
public void updateItem(final VoteListItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null && !empty) {
Tuple2<AwesomeIcon, String> iconStyleTuple = item.getIconStyleTuple();
icon = new Label();
AwesomeDude.setIcon(icon, iconStyleTuple.first);
icon.getStyleClass().add(iconStyleTuple.second);
setGraphic(icon);
setText(bsqFormatter.formatDateTime(item.getBlindVoteDate()));
} else {
setText("");
}
}
};
}
});
votesTableView.getColumns().add(column);
column = new AutoTooltipTableColumn<>(Res.get("shared.blindVoteTxId"));
column.setSortable(false);
column.setMinWidth(100);
column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setCellFactory(
new Callback<>() {
@Override
public TableCell<VoteListItem, VoteListItem> call(
TableColumn<VoteListItem, VoteListItem> column) {
return new TableCell<>() {
private HyperlinkWithIcon hyperlinkWithIcon;
@Override
public void updateItem(final VoteListItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null && !empty) {
String transactionId = item.getBlindVoteTxId();
hyperlinkWithIcon = new HyperlinkWithIcon(transactionId, MaterialDesignIcon.LINK);
hyperlinkWithIcon.setOnAction(event -> openTxInBlockExplorer(item));
hyperlinkWithIcon.setTooltip(new Tooltip(Res.get("tooltip.openBlockchainForTx", transactionId)));
setGraphic(hyperlinkWithIcon);
} else {
setGraphic(null);
if (hyperlinkWithIcon != null)
hyperlinkWithIcon.setOnAction(null);
}
}
};
@ -267,6 +288,7 @@ public class ProposalResultsWindow extends TabbedOverlay<ProposalResultsWindow>
}
});
votesTableView.getColumns().add(column);
column = new AutoTooltipTableColumn<>(Res.get("dao.results.votes.table.header.merit"));
column.setSortable(false);
column.setMinWidth(100);
@ -293,7 +315,6 @@ public class ProposalResultsWindow extends TabbedOverlay<ProposalResultsWindow>
column = new AutoTooltipTableColumn<>(Res.get("dao.results.votes.table.header.stake"));
column.setSortable(false);
column.setMinWidth(100);
column.getStyleClass().add("last-column");
column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setCellFactory(
new Callback<>() {
@ -313,6 +334,39 @@ public class ProposalResultsWindow extends TabbedOverlay<ProposalResultsWindow>
}
});
votesTableView.getColumns().add(column);
column = new AutoTooltipTableColumn<>(Res.get("dao.results.votes.table.header.vote"));
column.setSortable(false);
column.setMinWidth(50);
column.getStyleClass().add("last-column");
column.setMaxWidth(column.getMinWidth());
column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setCellFactory(
new Callback<>() {
@Override
public TableCell<VoteListItem, VoteListItem> call(
TableColumn<VoteListItem, VoteListItem> column) {
return new TableCell<>() {
private Label icon;
@Override
public void updateItem(final VoteListItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null && !empty) {
Tuple2<AwesomeIcon, String> iconStyleTuple = item.getIconStyleTuple();
icon = new Label();
AwesomeDude.setIcon(icon, iconStyleTuple.first);
icon.getStyleClass().add(iconStyleTuple.second);
setGraphic(icon);
} else {
setGraphic(null);
}
}
};
}
});
votesTableView.getColumns().add(column);
}
private void setupCloseKeyHandler(Scene scene) {
@ -323,4 +377,9 @@ public class ProposalResultsWindow extends TabbedOverlay<ProposalResultsWindow>
}
});
}
private void openTxInBlockExplorer(VoteListItem item) {
if (item.getBlindVoteTxId() != null)
GUIUtil.openWebPage(preferences.getBsqBlockChainExplorer().txUrl + item.getBlindVoteTxId(), false);
}
}

View File

@ -128,6 +128,9 @@ public class SelectProposalWindow extends Overlay<SelectProposalWindow> {
private void addContent(Proposal proposal, EvaluatedProposal evaluatedProposal, Ballot ballot) {
ProposalDisplay proposalDisplay = new ProposalDisplay(gridPane, bsqFormatter, daoFacade, changeParamValidator,
navigation, preferences);
proposalDisplay.onNavigate(this::doClose);
proposalDisplay.createAllFields("", rowIndex, -Layout.FIRST_ROW_DISTANCE, proposal.getType(),
false, "last");
proposalDisplay.setEditable(false);