transaction tab: rearrange via transaction tree

This commit is contained in:
Craig Raw 2023-11-22 07:59:26 +02:00
parent bb32a1e7b1
commit 85eb4df7e9
8 changed files with 149 additions and 13 deletions

2
drongo

@ -1 +1 @@
Subproject commit 0815484c4cb384522cf215ef18fc69a666b43c37 Subproject commit 0bb5b75be52ca4ee9dc771dae30d2b7cb9a49bd2

View file

@ -0,0 +1,15 @@
package com.sparrowwallet.sparrow.event;
import com.sparrowwallet.drongo.psbt.PSBT;
public class PSBTReorderedEvent {
private final PSBT psbt;
public PSBTReorderedEvent(PSBT psbt) {
this.psbt = psbt;
}
public PSBT getPsbt() {
return psbt;
}
}

View file

@ -1593,6 +1593,14 @@ public class HeadersController extends TransactionFormController implements Init
} }
} }
@Subscribe
public void psbtReordered(PSBTReorderedEvent event) {
if(event.getPsbt().equals(headersForm.getPsbt())) {
updateTxId();
transactionDiagram.update(getWalletTransaction(headersForm.getInputTransactions()));
}
}
private static class WalletSignComparator implements Comparator<Wallet> { private static class WalletSignComparator implements Comparator<Wallet> {
private static final List<KeystoreSource> sourceOrder = List.of(KeystoreSource.SW_WATCH, KeystoreSource.HW_AIRGAPPED, KeystoreSource.HW_USB, KeystoreSource.SW_SEED); private static final List<KeystoreSource> sourceOrder = List.of(KeystoreSource.SW_WATCH, KeystoreSource.HW_AIRGAPPED, KeystoreSource.HW_USB, KeystoreSource.SW_SEED);

View file

@ -1,7 +1,7 @@
package com.sparrowwallet.sparrow.transaction; package com.sparrowwallet.sparrow.transaction;
public abstract class IndexedTransactionForm extends TransactionForm { public abstract class IndexedTransactionForm extends TransactionForm {
private final int index; private int index;
public IndexedTransactionForm(TransactionData txdata, int index) { public IndexedTransactionForm(TransactionData txdata, int index) {
super(txdata); super(txdata);
@ -11,4 +11,8 @@ public abstract class IndexedTransactionForm extends TransactionForm {
public int getIndex() { public int getIndex() {
return index; return index;
} }
public void setIndex(int index) {
this.index = index;
}
} }

View file

@ -570,4 +570,11 @@ public class InputController extends TransactionFormController implements Initia
updateScriptFields(event.getFinalTransaction().getInputs().get(inputForm.getIndex()), null); updateScriptFields(event.getFinalTransaction().getInputs().get(inputForm.getIndex()), null);
} }
} }
@Subscribe
public void psbtReordered(PSBTReorderedEvent event) {
if(event.getPsbt().equals(inputForm.getPsbt())) {
updateInputLegendFromWallet(inputForm.getTransactionInput(), null);
}
}
} }

View file

@ -9,6 +9,7 @@ import com.sparrowwallet.drongo.wallet.BlockTransaction;
import com.sparrowwallet.drongo.wallet.Wallet; import com.sparrowwallet.drongo.wallet.Wallet;
import com.sparrowwallet.sparrow.EventManager; import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.control.*; import com.sparrowwallet.sparrow.control.*;
import com.sparrowwallet.sparrow.event.PSBTReorderedEvent;
import com.sparrowwallet.sparrow.event.UnitFormatChangedEvent; import com.sparrowwallet.sparrow.event.UnitFormatChangedEvent;
import com.sparrowwallet.sparrow.event.BlockTransactionOutputsFetchedEvent; import com.sparrowwallet.sparrow.event.BlockTransactionOutputsFetchedEvent;
import com.sparrowwallet.sparrow.event.ViewTransactionEvent; import com.sparrowwallet.sparrow.event.ViewTransactionEvent;
@ -178,4 +179,11 @@ public class OutputController extends TransactionFormController implements Initi
public void unitFormatChanged(UnitFormatChangedEvent event) { public void unitFormatChanged(UnitFormatChangedEvent event) {
value.refresh(event.getUnitFormat(), event.getBitcoinUnit()); value.refresh(event.getUnitFormat(), event.getBitcoinUnit());
} }
@Subscribe
public void psbtReordered(PSBTReorderedEvent event) {
if(event.getPsbt().equals(outputForm.getPsbt())) {
updateOutputLegendFromWallet(outputForm.getTransactionOutput(), null);
}
}
} }

View file

@ -9,26 +9,20 @@ import javafx.scene.Node;
import java.io.IOException; import java.io.IOException;
public class OutputForm extends IndexedTransactionForm { public class OutputForm extends IndexedTransactionForm {
private final TransactionOutput transactionOutput;
private PSBTOutput psbtOutput;
public OutputForm(TransactionData txdata, PSBTOutput psbtOutput) { public OutputForm(TransactionData txdata, PSBTOutput psbtOutput) {
super(txdata, txdata.getPsbt().getPsbtOutputs().indexOf(psbtOutput)); super(txdata, txdata.getPsbt().getPsbtOutputs().indexOf(psbtOutput));
this.transactionOutput = txdata.getPsbt().getTransaction().getOutputs().get(txdata.getPsbt().getPsbtOutputs().indexOf(psbtOutput));
this.psbtOutput = psbtOutput;
} }
public OutputForm(TransactionData txdata, TransactionOutput transactionOutput) { public OutputForm(TransactionData txdata, TransactionOutput transactionOutput) {
super(txdata, txdata.getTransaction().getOutputs().indexOf(transactionOutput)); super(txdata, txdata.getTransaction().getOutputs().indexOf(transactionOutput));
this.transactionOutput = transactionOutput;
} }
public TransactionOutput getTransactionOutput() { public TransactionOutput getTransactionOutput() {
return transactionOutput; if(txdata.getTransaction() != null) {
} return txdata.getTransaction().getOutputs().get(getIndex());
}
public PSBTOutput getPsbtOutput() { return null;
return psbtOutput;
} }
public boolean isWalletConsolidation() { public boolean isWalletConsolidation() {
@ -59,6 +53,6 @@ public class OutputForm extends IndexedTransactionForm {
} }
public String toString() { public String toString() {
return "Output #" + transactionOutput.getIndex(); return "Output #" + getIndex();
} }
} }

View file

@ -23,6 +23,7 @@ import javafx.scene.Parent;
import javafx.scene.control.TreeCell; import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem; import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView; import javafx.scene.control.TreeView;
import javafx.scene.input.*;
import javafx.scene.layout.Pane; import javafx.scene.layout.Pane;
import org.controlsfx.control.MasterDetailPane; import org.controlsfx.control.MasterDetailPane;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -35,6 +36,7 @@ import java.util.stream.Collectors;
public class TransactionController implements Initializable { public class TransactionController implements Initializable {
private static final Logger log = LoggerFactory.getLogger(TransactionController.class); private static final Logger log = LoggerFactory.getLogger(TransactionController.class);
private static final DataFormat JAVA_FORMAT = new DataFormat("application/x-java-serialized-object");
@FXML @FXML
private Node tabContent; private Node tabContent;
@ -62,6 +64,9 @@ public class TransactionController implements Initializable {
private boolean allInputsFetchedFromWallet; private boolean allInputsFetchedFromWallet;
private boolean transactionsFetched; private boolean transactionsFetched;
private TreeItem<TransactionForm> draggedItem;
private TreeCell<TransactionForm> dropZone;
@Override @Override
public void initialize(URL location, ResourceBundle resources) { public void initialize(URL location, ResourceBundle resources) {
EventManager.get().register(this); EventManager.get().register(this);
@ -174,6 +179,14 @@ public class TransactionController implements Initializable {
setGraphic(TransactionDiagram.getPaymentGlyph()); setGraphic(TransactionDiagram.getPaymentGlyph());
} }
} }
setOnDragDetected(null);
setOnDragOver(null);
setOnDragDropped(null);
} else if(form.isEditable()) {
setOnDragDetected(event -> dragDetected(event, this));
setOnDragOver(event -> dragOver(event, this));
setOnDragDropped(event -> drop(event, this));
} }
} }
} }
@ -463,6 +476,85 @@ public class TransactionController implements Initializable {
this.initialIndex = initialIndex; this.initialIndex = initialIndex;
} }
private void dragDetected(MouseEvent event, TreeCell<TransactionForm> treeCell) {
draggedItem = treeCell.getTreeItem();
if(!draggedItem.getChildren().isEmpty()) {
return;
}
Dragboard db = treeCell.startDragAndDrop(TransferMode.MOVE);
ClipboardContent content = new ClipboardContent();
content.put(JAVA_FORMAT, draggedItem.getValue().toString());
db.setContent(content);
db.setDragView(treeCell.snapshot(null, null));
event.consume();
}
private void dragOver(DragEvent event, TreeCell<TransactionForm> treeCell) {
if(!event.getDragboard().hasContent(JAVA_FORMAT)) {
return;
}
TreeItem<TransactionForm> thisItem = treeCell.getTreeItem();
if(draggedItem == null || thisItem == null || thisItem == draggedItem) {
return;
}
if(draggedItem.getParent() == null || thisItem.getParent() == null) {
return;
}
if(draggedItem.getValue() instanceof InputForm && (thisItem.getValue() instanceof OutputForm || thisItem.getValue() instanceof OutputsForm)) {
return;
}
if(draggedItem.getValue() instanceof OutputForm && (thisItem.getValue() instanceof InputForm || thisItem.getValue() instanceof InputsForm)) {
return;
}
event.acceptTransferModes(TransferMode.MOVE);
if(!Objects.equals(dropZone, treeCell)) {
this.dropZone = treeCell;
}
}
private void drop(DragEvent event, TreeCell<TransactionForm> treeCell) {
Dragboard db = event.getDragboard();
if(!db.hasContent(JAVA_FORMAT)) {
return;
}
TreeItem<TransactionForm> thisItem = treeCell.getTreeItem();
TreeItem<TransactionForm> droppedItemParent = draggedItem.getParent();
int fromIndex = droppedItemParent.getChildren().indexOf(draggedItem);
int toIndex = Objects.equals(droppedItemParent, thisItem) ? 0 : thisItem.getParent().getChildren().indexOf(thisItem);
droppedItemParent.getChildren().remove(draggedItem);
if(Objects.equals(droppedItemParent, thisItem)) {
thisItem.getChildren().add(toIndex, draggedItem);
} else {
thisItem.getParent().getChildren().add(toIndex, draggedItem);
}
PSBT psbt = getPSBT();
if(draggedItem.getValue() instanceof InputForm) {
psbt.moveInput(fromIndex, toIndex);
} else if(draggedItem.getValue() instanceof OutputForm) {
psbt.moveOutput(fromIndex, toIndex);
}
for(int i = 0; i < draggedItem.getParent().getChildren().size(); i++) {
if(draggedItem.getParent().getChildren().get(i).getValue() instanceof IndexedTransactionForm indexedTransactionForm) {
indexedTransactionForm.setIndex(i);
}
}
txdata.setTransaction(psbt.getTransaction());
txtree.getSelectionModel().select(draggedItem);
event.setDropCompleted(true);
EventManager.get().post(new PSBTReorderedEvent(psbt));
}
@Subscribe @Subscribe
public void viewTransaction(ViewTransactionEvent event) { public void viewTransaction(ViewTransactionEvent event) {
if(txdata.getTransaction().getTxId().equals(event.getTransaction().getTxId())) { if(txdata.getTransaction().getTxId().equals(event.getTransaction().getTxId())) {
@ -594,4 +686,12 @@ public class TransactionController implements Initializable {
fetchTransactions(); fetchTransactions();
} }
} }
@Subscribe
public void psbtReordered(PSBTReorderedEvent event) {
if(event.getPsbt() == getPSBT()) {
txhex.setTransaction(getTransaction());
highlightTxHex();
}
}
} }