Improve vote result view

This commit is contained in:
Manfred Karrer 2018-08-08 00:06:36 +02:00
parent 1df3dfe4c8
commit 697e7ae058
No known key found for this signature in database
GPG key ID: 401250966A6B2C46
4 changed files with 214 additions and 223 deletions

View file

@ -17,36 +17,21 @@
package bisq.desktop.main.dao.governance.proposals;
import bisq.desktop.components.indicator.TxConfidenceIndicator;
import bisq.core.btc.listeners.TxConfidenceListener;
import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.dao.DaoFacade;
import bisq.core.dao.governance.ballot.Ballot;
import bisq.core.dao.governance.ballot.vote.BooleanVote;
import bisq.core.dao.governance.ballot.vote.Vote;
import bisq.core.dao.governance.proposal.Proposal;
import bisq.core.dao.state.BsqStateListener;
import bisq.core.dao.state.blockchain.Block;
import bisq.core.dao.state.blockchain.Tx;
import bisq.core.dao.state.period.DaoPhase;
import bisq.core.locale.Res;
import bisq.core.util.BsqFormatter;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionConfidence;
import de.jensd.fx.fontawesome.AwesomeDude;
import de.jensd.fx.fontawesome.AwesomeIcon;
import javafx.scene.control.Label;
import javafx.scene.control.Tooltip;
import javafx.beans.value.ChangeListener;
import java.util.Objects;
import java.util.Optional;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
@ -57,11 +42,11 @@ import javax.annotation.Nullable;
@ToString
@Slf4j
@EqualsAndHashCode
public class ProposalsListItem implements BsqStateListener {
//TODO merge with vote result ProposalListItem
public class ProposalsListItem {
@Getter
private final Proposal proposal;
private final DaoFacade daoFacade;
private final BsqWalletService bsqWalletService;
private final BsqFormatter bsqFormatter;
@Getter
@ -71,15 +56,7 @@ public class ProposalsListItem implements BsqStateListener {
@Getter
private Label icon;
@Getter
private TxConfidenceIndicator txConfidenceIndicator;
@Getter
private Integer confirmations = 0;
private TxConfidenceListener txConfidenceListener;
private Tooltip tooltip = new Tooltip(Res.get("confidence.unknown"));
private Transaction walletTransaction;
private ChangeListener<DaoPhase.Phase> phaseChangeListener;
private ChangeListener<Number> chainHeightListener;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor, lifecycle
@ -87,11 +64,9 @@ public class ProposalsListItem implements BsqStateListener {
ProposalsListItem(Proposal proposal,
DaoFacade daoFacade,
BsqWalletService bsqWalletService,
BsqFormatter bsqFormatter) {
this.proposal = proposal;
this.daoFacade = daoFacade;
this.bsqWalletService = bsqWalletService;
this.bsqFormatter = bsqFormatter;
init();
@ -99,33 +74,21 @@ public class ProposalsListItem implements BsqStateListener {
ProposalsListItem(Ballot ballot,
DaoFacade daoFacade,
BsqWalletService bsqWalletService,
BsqFormatter bsqFormatter) {
this.ballot = ballot;
this.proposal = ballot.getProposal();
this.daoFacade = daoFacade;
this.bsqWalletService = bsqWalletService;
this.bsqFormatter = bsqFormatter;
init();
}
private void init() {
phaseChangeListener = (observable, oldValue, newValue) -> onPhaseChanged(newValue);
///////////////////////////////////////////////////////////////////////////////////////////
// BsqStateListener
///////////////////////////////////////////////////////////////////////////////////////////
daoFacade.phaseProperty().addListener(phaseChangeListener);
@Override
public void onNewBlockHeight(int blockHeight) {
}
@Override
public void onParseTxsComplete(Block block) {
setupConfidence();
}
@Override
public void onParseBlockChainComplete() {
onPhaseChanged(daoFacade.phaseProperty().get());
}
@ -134,11 +97,6 @@ public class ProposalsListItem implements BsqStateListener {
///////////////////////////////////////////////////////////////////////////////////////////
public void cleanup() {
daoFacade.removeBsqStateListener(this);
bsqWalletService.getChainHeightProperty().removeListener(chainHeightListener);
if (txConfidenceListener != null)
bsqWalletService.removeTxConfidenceListener(txConfidenceListener);
daoFacade.phaseProperty().removeListener(phaseChangeListener);
}
@ -176,104 +134,4 @@ public class ProposalsListItem implements BsqStateListener {
icon.layout();
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// Protected
///////////////////////////////////////////////////////////////////////////////////////////
private void init() {
txConfidenceIndicator = new TxConfidenceIndicator();
txConfidenceIndicator.setId("funds-confidence");
txConfidenceIndicator.setProgress(-1);
txConfidenceIndicator.setPrefSize(24, 24);
txConfidenceIndicator.setTooltip(tooltip);
chainHeightListener = (observable, oldValue, newValue) -> setupConfidence();
bsqWalletService.getChainHeightProperty().addListener(chainHeightListener);
setupConfidence();
daoFacade.addBsqStateListener(this);
phaseChangeListener = (observable, oldValue, newValue) -> onPhaseChanged(newValue);
daoFacade.phaseProperty().addListener(phaseChangeListener);
onPhaseChanged(daoFacade.phaseProperty().get());
}
private void setupConfidence() {
final String txId = proposal.getTxId();
Optional<Tx> optionalTx = daoFacade.getTx(txId);
optionalTx.ifPresent(tx -> {
// We cache the walletTransaction once found
if (walletTransaction == null) {
final Optional<Transaction> transactionOptional = bsqWalletService.isWalletTransaction(txId);
transactionOptional.ifPresent(transaction -> walletTransaction = transaction);
}
if (walletTransaction != null) {
// It is our tx so we get confidence updates
if (txConfidenceListener == null) {
txConfidenceListener = new TxConfidenceListener(txId) {
@Override
public void onTransactionConfidenceChanged(TransactionConfidence confidence) {
updateConfidence(confidence.getConfidenceType(), confidence.getDepthInBlocks(), confidence.numBroadcastPeers());
}
};
bsqWalletService.addTxConfidenceListener(txConfidenceListener);
}
} else {
// tx from other users, we don't get confidence updates but as we have the bsq tx we can calculate it
// we get setupConfidence called at each new block from above listener so no need to register a new listener
int depth = bsqWalletService.getChainHeightProperty().get() - tx.getBlockHeight() + 1;
if (depth > 0)
updateConfidence(TransactionConfidence.ConfidenceType.BUILDING, depth, -1);
}
final TransactionConfidence confidence = bsqWalletService.getConfidenceForTxId(txId);
if (confidence != null)
updateConfidence(confidence, confidence.getDepthInBlocks());
});
}
private void updateConfidence(TransactionConfidence confidence, int depthInBlocks) {
if (confidence != null) {
updateConfidence(confidence.getConfidenceType(), confidence.getDepthInBlocks(), confidence.numBroadcastPeers());
confirmations = depthInBlocks;
}
}
private void updateConfidence(TransactionConfidence.ConfidenceType confidenceType, int depthInBlocks, int numBroadcastPeers) {
switch (confidenceType) {
case UNKNOWN:
tooltip.setText(Res.get("confidence.unknown"));
txConfidenceIndicator.setProgress(0);
break;
case PENDING:
tooltip.setText(Res.get("confidence.seen", numBroadcastPeers > -1 ? numBroadcastPeers : Res.get("shared.na")));
txConfidenceIndicator.setProgress(-1.0);
break;
case BUILDING:
tooltip.setText(Res.get("confidence.confirmed", depthInBlocks));
txConfidenceIndicator.setProgress(Math.min(1, (double) depthInBlocks / 6.0));
break;
case DEAD:
tooltip.setText(Res.get("confidence.invalid"));
txConfidenceIndicator.setProgress(0);
break;
}
txConfidenceIndicator.setPrefSize(24, 24);
}
public Optional<BooleanVote> getBooleanVote() {
//noinspection ConstantConditions
return Optional.ofNullable(ballot)
.map(Ballot::getVote)
.filter(Objects::nonNull)
.filter(vote -> vote instanceof BooleanVote)
.map(v -> (BooleanVote) v);
}
}

View file

@ -92,6 +92,7 @@ import javafx.util.Callback;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
@ -279,13 +280,13 @@ public class ProposalsView extends ActivatableView<GridPane, Void> implements Bs
// proposal phase
List<Proposal> list = daoFacade.getActiveOrMyUnconfirmedProposals();
listItems.setAll(list.stream()
.map(proposal -> new ProposalsListItem(proposal, daoFacade, bsqWalletService, bsqFormatter))
.map(proposal -> new ProposalsListItem(proposal, daoFacade, bsqFormatter))
.collect(Collectors.toSet()));
} else {
// blind vote phase
List<Ballot> ballotList = daoFacade.getValidAndConfirmedBallots();
listItems.setAll(ballotList.stream()
.map(ballot -> new ProposalsListItem(ballot, daoFacade, bsqWalletService, bsqFormatter))
.map(ballot -> new ProposalsListItem(ballot, daoFacade, bsqFormatter))
.collect(Collectors.toSet()));
}
@ -520,6 +521,15 @@ public class ProposalsView extends ActivatableView<GridPane, Void> implements Bs
return selectedItem;
}
private Optional<BooleanVote> getBooleanVote(Ballot ballot) {
//noinspection ConstantConditions
return Optional.ofNullable(ballot)
.map(Ballot::getVote)
.filter(Objects::nonNull)
.filter(vote -> vote instanceof BooleanVote)
.map(v -> (BooleanVote) v);
}
private void updateViews() {
boolean isBlindVotePhaseButNotLastBlock = isBlindVotePhaseButNotLastBlock();
boolean hasVotedOnProposal = hasVotedOnProposal();
@ -529,7 +539,7 @@ public class ProposalsView extends ActivatableView<GridPane, Void> implements Bs
List<MyVote> myVoteListForCycle = daoFacade.getMyVoteListForCycle();
boolean hasAlreadyVoted = !myVoteListForCycle.isEmpty();
if (selectedItem != null && acceptButton != null) {
Optional<BooleanVote> optionalVote = selectedItem.getBooleanVote();
Optional<BooleanVote> optionalVote = getBooleanVote(selectedItem.getBallot());
boolean isPresent = optionalVote.isPresent();
boolean isAccepted = isPresent && optionalVote.get().isAccepted();
acceptButton.setDisable((isPresent && isAccepted));
@ -791,34 +801,31 @@ public class ProposalsView extends ActivatableView<GridPane, Void> implements Bs
tableView.getColumns().add(column);
column = new TableColumn<>(Res.get("shared.confirmations"));
column.setMinWidth(130);
column.setMaxWidth(column.getMinWidth());
column = new AutoTooltipTableColumn<>(Res.get("dao.proposal.table.header.proposalType"));
column.setMinWidth(60);
column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setCellFactory(new Callback<TableColumn<ProposalsListItem, ProposalsListItem>,
TableCell<ProposalsListItem, ProposalsListItem>>() {
@Override
public TableCell<ProposalsListItem, ProposalsListItem> call(TableColumn<ProposalsListItem,
ProposalsListItem> column) {
return new TableCell<ProposalsListItem, ProposalsListItem>() {
column.setCellFactory(
new Callback<TableColumn<ProposalsListItem, ProposalsListItem>, TableCell<ProposalsListItem,
ProposalsListItem>>() {
@Override
public void updateItem(final ProposalsListItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null && !empty) {
setGraphic(item.getTxConfidenceIndicator());
} else {
setGraphic(null);
}
public TableCell<ProposalsListItem, ProposalsListItem> call(
TableColumn<ProposalsListItem, ProposalsListItem> column) {
return new TableCell<ProposalsListItem, ProposalsListItem>() {
@Override
public void updateItem(final ProposalsListItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null)
setText(Res.get("dao.proposal.type." + item.getProposal().getType().name()));
else
setText("");
}
};
}
};
}
});
column.setComparator(Comparator.comparing(ProposalsListItem::getConfirmations));
});
column.setComparator(Comparator.comparing(o2 -> o2.getProposal().getName()));
tableView.getColumns().add(column);
column = new TableColumn<>();
column.setMinWidth(40);
column.setMaxWidth(column.getMinWidth());

View file

@ -17,6 +17,9 @@
package bisq.desktop.main.dao.governance.result;
import bisq.core.dao.governance.ballot.Ballot;
import bisq.core.dao.governance.ballot.vote.BooleanVote;
import bisq.core.dao.governance.ballot.vote.Vote;
import bisq.core.dao.governance.proposal.Proposal;
import bisq.core.dao.governance.proposal.compensation.CompensationProposal;
import bisq.core.dao.governance.proposal.confiscatebond.ConfiscateBondProposal;
@ -24,31 +27,56 @@ import bisq.core.dao.governance.proposal.param.ChangeParamProposal;
import bisq.core.dao.governance.proposal.role.BondedRoleProposal;
import bisq.core.dao.governance.role.BondedRole;
import bisq.core.dao.governance.voteresult.EvaluatedProposal;
import bisq.core.dao.governance.voteresult.ProposalVoteResult;
import bisq.core.locale.Res;
import bisq.core.util.BsqFormatter;
import org.bitcoinj.core.Coin;
import de.jensd.fx.fontawesome.AwesomeDude;
import de.jensd.fx.fontawesome.AwesomeIcon;
import javafx.scene.control.Label;
import javafx.scene.control.TableRow;
import lombok.Getter;
public class ProposalListItem {
private final ProposalVoteResult proposalVoteResult;
private final BsqFormatter bsqFormatter;
private TableRow tableRow;
@Getter
private EvaluatedProposal evaluatedProposal;
@Getter
private final Proposal proposal;
private final Vote vote;
private final BsqFormatter bsqFormatter;
ProposalListItem(EvaluatedProposal evaluatedProposal, BsqFormatter bsqFormatter) {
private TableRow tableRow;
ProposalListItem(EvaluatedProposal evaluatedProposal, Ballot ballot, BsqFormatter bsqFormatter) {
this.evaluatedProposal = evaluatedProposal;
proposalVoteResult = evaluatedProposal.getProposalVoteResult();
proposal = evaluatedProposal.getProposal();
vote = ballot.getVote();
this.bsqFormatter = bsqFormatter;
}
// If myVoteIcon would be set in constructor styles are not applied correctly
public Label getMyVoteIcon() {
Label myVoteIcon;
if (vote != null && vote instanceof BooleanVote) {
if (((BooleanVote) vote).isAccepted()) {
myVoteIcon = AwesomeDude.createIconLabel(AwesomeIcon.THUMBS_UP);
myVoteIcon.getStyleClass().addAll("icon", "dao-accepted-icon");
} else {
myVoteIcon = AwesomeDude.createIconLabel(AwesomeIcon.THUMBS_DOWN);
myVoteIcon.getStyleClass().addAll("icon", "dao-rejected-icon");
}
} else {
myVoteIcon = AwesomeDude.createIconLabel(AwesomeIcon.MINUS);
myVoteIcon.getStyleClass().addAll("icon", "dao-ignored-icon");
}
return myVoteIcon;
}
public void setTableRow(TableRow tableRow) {
this.tableRow = tableRow;
@ -65,30 +93,6 @@ public class ProposalListItem {
return evaluatedProposal.getProposal().getName();
}
public String getProposalId() {
return evaluatedProposal.getProposal().getShortId();
}
public String getAccepted() {
return Res.get("dao.results.proposals.table.item.votes",
bsqFormatter.formatCoinWithCode(Coin.valueOf(proposalVoteResult.getStakeOfAcceptedVotes())),
String.valueOf(proposalVoteResult.getNumAcceptedVotes()));
}
public String getRejected() {
return Res.get("dao.results.proposals.table.item.votes",
bsqFormatter.formatCoinWithCode(Coin.valueOf(proposalVoteResult.getStakeOfRejectedVotes())),
String.valueOf(proposalVoteResult.getNumRejectedVotes()));
}
public String getThreshold() {
return proposalVoteResult.getThreshold() > 0 ? (proposalVoteResult.getThreshold() / 100D) + "%" : "";
}
public String getQuorum() {
return bsqFormatter.formatCoinWithCode(Coin.valueOf(proposalVoteResult.getQuorum()));
}
public AwesomeIcon getIcon() {
return evaluatedProposal.isAccepted() ? AwesomeIcon.OK_SIGN : AwesomeIcon.BAN_CIRCLE;
}
@ -97,38 +101,30 @@ public class ProposalListItem {
return evaluatedProposal.isAccepted() ? "dao-accepted-icon" : "dao-rejected-icon";
}
public String getColorStyle() {
return evaluatedProposal.isAccepted() ? "-fx-text-fill: -bs-green;" : "-fx-text-fill: -bs-error-red;";
}
public String getIssuance() {
public String getDetails() {
Proposal proposal = evaluatedProposal.getProposal();
switch (proposal.getType()) {
case COMPENSATION_REQUEST:
CompensationProposal compensationProposal = (CompensationProposal) proposal;
Coin requestedBsq = evaluatedProposal.isAccepted() ? compensationProposal.getRequestedBsq() : Coin.ZERO;
return Res.get("dao.results.proposals.table.issuance", bsqFormatter.formatCoinWithCode(requestedBsq));
return bsqFormatter.formatCoinWithCode(requestedBsq);
case BONDED_ROLE:
BondedRoleProposal bondedRoleProposal = (BondedRoleProposal) proposal;
BondedRole bondedRole = bondedRoleProposal.getBondedRole();
String name = bondedRole.getName();
String type = Res.get("dao.bond.bondedRoleType." + bondedRole.getBondedRoleType().name());
return Res.get("dao.results.proposals.table.bondedRole", name, type);
return Res.get("dao.bond.bondedRoleType." + bondedRole.getBondedRoleType().name());
case REMOVE_ALTCOIN:
// TODO
return "N/A";
case CHANGE_PARAM:
ChangeParamProposal changeParamProposal = (ChangeParamProposal) proposal;
return Res.get("dao.results.proposals.table.paramChange",
changeParamProposal.getParam().getDisplayString(),
changeParamProposal.getParamValue());
return changeParamProposal.getParam().getDisplayString();
case GENERIC:
// TODO
return "N/A";
case CONFISCATE_BOND:
ConfiscateBondProposal confiscateBondProposal = (ConfiscateBondProposal) proposal;
// TODO add info to bond
return Res.get("dao.results.proposals.table.confiscateBond", confiscateBondProposal.getTxId());
return confiscateBondProposal.getTxId();
}
return "-";
}

View file

@ -78,6 +78,7 @@ import javafx.util.Callback;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
@ -328,10 +329,15 @@ public class VoteResultView extends ActivatableView<GridPane, Void> implements B
proposalList.clear();
proposalList.forEach(ProposalListItem::resetTableRow);
Map<String, Ballot> ballotByProposalTxIdMap = daoFacade.getAllBallots()
.stream()
.collect(Collectors.toMap(Ballot::getProposalTxId, ballot -> ballot));
proposalList.setAll(resultsOfCycle.getEvaluatedProposals().stream()
.map(evaluatedProposal -> new ProposalListItem(evaluatedProposal, bsqFormatter))
.map(evaluatedProposal -> new ProposalListItem(evaluatedProposal,
ballotByProposalTxIdMap.get(evaluatedProposal.getProposalTxId()),
bsqFormatter))
.collect(Collectors.toList()));
proposalList.sort(Comparator.comparing(proposalListItem -> proposalListItem.getEvaluatedProposal().getProposal().getCreationDate()));
GUIUtil.setFitToRowsForTableView(proposalsTableView, 33, 28, 80);
}
@ -542,8 +548,36 @@ public class VoteResultView extends ActivatableView<GridPane, Void> implements B
private void createProposalsColumns(TableView<ProposalListItem> votesTableView) {
TableColumn<ProposalListItem, ProposalListItem> column;
column = new AutoTooltipTableColumn<>(Res.get("shared.dateTime"));
column.setMinWidth(190);
column.setMaxWidth(column.getMinWidth());
column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setCellFactory(
new Callback<TableColumn<ProposalListItem, ProposalListItem>, TableCell<ProposalListItem,
ProposalListItem>>() {
@Override
public TableCell<ProposalListItem, ProposalListItem> call(
TableColumn<ProposalListItem, ProposalListItem> column) {
return new TableCell<ProposalListItem, ProposalListItem>() {
@Override
public void updateItem(final ProposalListItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null)
setText(bsqFormatter.formatDateTime(item.getProposal().getCreationDate()));
else
setText("");
}
};
}
});
column.setComparator(Comparator.comparing(o3 -> o3.getProposal().getCreationDate()));
column.setSortType(TableColumn.SortType.DESCENDING);
votesTableView.getColumns().add(column);
votesTableView.getSortOrder().add(column);
column = new AutoTooltipTableColumn<>(Res.get("dao.results.proposals.table.header.proposalOwnerName"));
column.setMinWidth(110);
column.setMinWidth(80);
column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setCellFactory(
new Callback<TableColumn<ProposalListItem, ProposalListItem>, TableCell<ProposalListItem,
@ -570,8 +604,44 @@ public class VoteResultView extends ActivatableView<GridPane, Void> implements B
votesTableView.getColumns().add(column);
column = new AutoTooltipTableColumn<>(Res.get("dao.results.proposals.table.header.details"));
column = new AutoTooltipTableColumn<>(Res.get("dao.proposal.table.header.link"));
column.setMinWidth(100);
column.setMaxWidth(column.getMinWidth());
column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setCellFactory(
new Callback<TableColumn<ProposalListItem, ProposalListItem>, TableCell<ProposalListItem,
ProposalListItem>>() {
@Override
public TableCell<ProposalListItem, ProposalListItem> call(TableColumn<ProposalListItem,
ProposalListItem> column) {
return new TableCell<ProposalListItem, ProposalListItem>() {
private HyperlinkWithIcon field;
@Override
public void updateItem(final ProposalListItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null && !empty) {
final Proposal proposal = item.getProposal();
field = new HyperlinkWithIcon(proposal.getLink(), AwesomeIcon.EXTERNAL_LINK);
field.setOnAction(event -> GUIUtil.openWebPage(Res.get("shared.openURL", proposal.getLink())));
field.setTooltip(new Tooltip(proposal.getLink()));
setGraphic(field);
} else {
setGraphic(null);
if (field != null)
field.setOnAction(null);
}
}
};
}
});
column.setComparator(Comparator.comparing(o -> o.getProposal().getUid()));
votesTableView.getColumns().add(column);
column = new AutoTooltipTableColumn<>(Res.get("dao.proposal.table.header.proposalType"));
column.setMinWidth(150);
column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setCellFactory(
new Callback<TableColumn<ProposalListItem, ProposalListItem>, TableCell<ProposalListItem,
@ -584,16 +654,76 @@ public class VoteResultView extends ActivatableView<GridPane, Void> implements B
public void updateItem(final ProposalListItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null)
setText(item.getIssuance());
setText(Res.get("dao.proposal.type.short." + item.getProposal().getType().name()));
else
setText("");
}
};
}
});
column.setComparator(Comparator.comparing(ProposalListItem::getThreshold));
column.setComparator(Comparator.comparing(o2 -> o2.getProposal().getName()));
votesTableView.getColumns().add(column);
column = new AutoTooltipTableColumn<>(Res.get("dao.results.proposals.table.header.details"));
column.setMinWidth(180);
column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setCellFactory(
new Callback<TableColumn<ProposalListItem, ProposalListItem>, TableCell<ProposalListItem,
ProposalListItem>>() {
@Override
public TableCell<ProposalListItem, ProposalListItem> call(
TableColumn<ProposalListItem, ProposalListItem> column) {
return new TableCell<ProposalListItem, ProposalListItem>() {
@Override
public void updateItem(final ProposalListItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null)
setText(item.getDetails());
else
setText("");
}
};
}
});
column.setComparator(Comparator.comparing(ProposalListItem::getDetails));
votesTableView.getColumns().add(column);
column = new AutoTooltipTableColumn<>(Res.get("dao.results.proposals.table.header.myVote"));
column.setMinWidth(70);
column.setMaxWidth(column.getMinWidth());
column.setCellValueFactory((item) -> new ReadOnlyObjectWrapper<>(item.getValue()));
column.setCellFactory(new Callback<TableColumn<ProposalListItem, ProposalListItem>,
TableCell<ProposalListItem, ProposalListItem>>() {
@Override
public TableCell<ProposalListItem, ProposalListItem> call(TableColumn<ProposalListItem,
ProposalListItem> column) {
return new TableCell<ProposalListItem, ProposalListItem>() {
Label myVoteIcon;
@Override
public void updateItem(final ProposalListItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null && !empty) {
if (myVoteIcon == null) {
myVoteIcon = item.getMyVoteIcon();
setGraphic(myVoteIcon);
}
} else {
setGraphic(null);
if (myVoteIcon != null)
myVoteIcon = null;
}
}
};
}
});
votesTableView.getColumns().add(column);
column = new AutoTooltipTableColumn<>(Res.get("dao.results.proposals.table.header.result"));
column.setMinWidth(90);
column.setMaxWidth(column.getMinWidth());