Browse Source

GUI: Added account browsing by keys and various other changes

Herman Schoenfeld 7 years ago
parent
commit
0f5cfc4cf5

+ 10 - 0
src/core/UAccounts.pas

@@ -191,6 +191,8 @@ Type
 
   // This is a class to quickly find accountkeys and their respective account number/s
   TOrderedAccountKeysList = Class
+  Private Type
+    TAccountKeyArray = array of TAccountKey;
   Private
     FAutoAddAll : Boolean;
     FAccountList : TPCSafeBox;
@@ -213,6 +215,7 @@ Type
     Function Count : Integer;
     Property SafeBox : TPCSafeBox read FAccountList;
     Procedure Clear;
+    function ToArray : TAccountKeyArray;
   End;
 
   // Maintans a Cardinal ordered (without duplicates) list with TRawData each
@@ -4248,6 +4251,13 @@ begin
   ClearAccounts(true);
 end;
 
+function TOrderedAccountKeysList.ToArray : TAccountKeyArray;
+var i : Integer;
+begin
+  SetLength(Result, Count);
+  for i := 0 to Count - 1 do Result[i] := Self.AccountKey[i];
+end;
+
 procedure TOrderedAccountKeysList.ClearAccounts(RemoveAccountList : Boolean);
 Var P : POrderedAccountKeyList;
   i : Integer;

+ 54 - 2
src/core/UCoreHelpers.pas → src/core/UCore.pas

@@ -1,7 +1,9 @@
-unit UCoreHelpers;
+unit UCore;
 
 { Copyright (c) 2018 by PascalCoin Project
 
+  Contains common types for Core module.
+
   Distributed under the MIT software license, see the accompanying file LICENSE
   or visit http://www.opensource.org/licenses/mit-license.php.
 
@@ -14,10 +16,24 @@ unit UCoreHelpers;
 interface
 
 uses
-  Classes, SysUtils, UCrypto, UAccounts, UBlockChain;
+  Classes, SysUtils, UCrypto, UAccounts, UBlockChain,
+  Generics.Collections, Generics.Defaults;
 
 type
 
+TAccountKeyComparer = class (TComparer<TAccountKey>)
+  function Compare(constref ALeft, ARight: T): Integer; override;
+  class function DoCompare(constref ALeft, ARight : TAccountKey) : Integer; inline;
+end;
+
+TAccountKeyEqualityComparer = class(TEqualityComparer<TAccountKey>)
+  public
+    function Equals(constref ALeft, ARight: TAccountKey): Boolean; override;
+    function GetHashCode(constref AValue: TAccountKey): UInt32; override;
+    class function AreEqual(constref ALeft, ARight: TAccountKey): Boolean;
+    class function CalcHashCode(constref AValue: TAccountKey): UInt32;
+end;
+
 TAccountHelper = record helper for TAccount
   function GetAccountString : AnsiString;
   function GetInfoText(const ABank : TPCBank) : utf8string;
@@ -33,6 +49,42 @@ implementation
 uses
   UCommon, UMemory;
 
+{ TAccountKeyComparer }
+
+function TAccountKeyComparer.Compare(constref ALeft, ARight: T): Integer;
+begin
+  Result := TAccountKeyComparer.DoCompare(ALeft, ARight);
+end;
+
+class function TAccountKeyComparer.DoCompare(constref ALeft, ARight : TAccountKey) : Integer;
+begin
+  Result := BinStrComp(ALeft.x, ARight.x);
+  if Result = 0 then
+    Result := BinStrComp(ALeft.y, ARight.y);
+end;
+
+{ TAccountKeyEqualityComparer }
+
+function TAccountKeyEqualityComparer.Equals(constref ALeft, ARight: TAccountKey): Boolean;
+begin
+  Result := TAccountKeyEqualityComparer.AreEqual(ALeft, ARight);
+end;
+
+function TAccountKeyEqualityComparer.GetHashCode(constref AValue: TAccountKey): UInt32;
+begin
+  Result := TAccountKeyEqualityComparer.CalcHashCode(AValue);
+end;
+
+class function TAccountKeyEqualityComparer.AreEqual(constref ALeft, ARight: TAccountKey): Boolean;
+begin
+  Result := TAccountKeyComparer.DoCompare(ALeft, ARight) = 0;
+end;
+
+class function TAccountKeyEqualityComparer.CalcHashCode(constref AValue: TAccountKey): UInt32;
+begin
+  Result := TEqualityComparer<AnsiString>.Default.GetHashCode(IntToStr(AValue.EC_OpenSSL_NID) + AValue.x + AValue.y  );
+end;
+
 { TAccountHelper }
 
 function TAccountHelper.GetAccountString : AnsiString;

+ 70 - 24
src/core/UDataSources.pas

@@ -1,17 +1,18 @@
 unit UDataSources;
 
 {$mode delphi}
+{$modeswitch nestedprocvars}
 
 interface
 
 uses
-  Classes, SysUtils, UAccounts, UNode, UBlockchain, UCommon, UConst, UCommon.Data, Generics.Collections, Generics.Defaults, syncobjs;
+  Classes, SysUtils, UAccounts, UNode, UBlockchain, UCommon, UConst, UCommon.Data, UCommon.Collections, Generics.Collections, Generics.Defaults, syncobjs;
 
 type
 
-  { TUserAccountsDataSource }
+  { TAccountsDataSource }
 
-  TUserAccountsDataSource = class(TCustomDataSource<TAccount>)
+  TAccountsDataSource = class(TCustomDataSource<TAccount>)
     public type
       TOverview = record
         TotalPASC : UInt64;
@@ -19,13 +20,19 @@ type
       end;
     private
       FLastKnownUserAccounts : TArray<TAccount>;
+      FKeys : TSortedHashSet<TAccountKey>;
     protected
       FLastOverview : TOverview;
       function GetItemDisposePolicy : TItemDisposePolicy; override;
       function GetColumns : TTableColumns;  override;
+      function GetFilterKeys : TArray<TAccountKey>;
+      procedure SetFilterKeys (const AKeys : TArray<TAccountKey>);
     public
       property Overview : TOverview read FLastOverview;
-      property LastKnownUserAccounts : TArray<TAccount> read FLastKnownUserAccounts;
+      property LastFetchResult : TArray<TAccount> read FLastKnownUserAccounts;
+      property FilterKeys : TArray<TAccountKey> read GetFilterKeys write SetFilterKeys;
+      constructor Create(AOwner: TComponent); override;
+      destructor Destroy; override;
       function GetSearchCapabilities: TSearchCapabilities; override;
       function GetEntityKey(constref AItem: TAccount) : Variant; override;
       procedure FetchAll(const AContainer : TList<TAccount>); override;
@@ -92,21 +99,46 @@ type
 
 implementation
 
-uses UWallet, UUserInterface, UMemory, UCommon.Collections, math, UTime;
+uses
+  math, UCore, UWallet, UUserInterface, UMemory, UTime;
+
+{ TAccountsDataSource }
+
+constructor TAccountsDataSource.Create(AOwner: TComponent);
+begin
+  inherited Create(AOwner);
+  FKeys := TSortedHashSet<TAccountKey>.Create(TAccountKeyComparer.Create, TAccountKeyEqualityComparer.Create);
+end;
 
-{ TUserAccountsDataSource }
+destructor TAccountsDataSource.Destroy;
+begin
+  FKeys.Free;
+end;
 
-function TUserAccountsDataSource.GetItemDisposePolicy : TItemDisposePolicy;
+function TAccountsDataSource.GetFilterKeys : TArray<TAccountKey>;
+begin
+  Result := FKeys.ToArray;
+end;
+
+procedure TAccountsDataSource.SetFilterKeys (const AKeys : TArray<TAccountKey>);
+var i : Integer;
+begin
+  FKeys.Clear;
+  for i := Low(AKeys) to High(AKeys) do
+    FKeys.Add(AKeys[i]);
+end;
+
+function TAccountsDataSource.GetItemDisposePolicy : TItemDisposePolicy;
 begin
   Result := idpNone;
 end;
 
-function TUserAccountsDataSource.GetColumns : TTableColumns;
+function TAccountsDataSource.GetColumns : TTableColumns;
 begin
   Result := TTableColumns.Create('Account', 'Name', 'Balance');
 end;
 
-function TUserAccountsDataSource.GetSearchCapabilities: TSearchCapabilities;
+function TAccountsDataSource.GetSearchCapabilities: TSearchCapabilities;
 begin
   Result := TSearchCapabilities.Create(
     TSearchCapability.From('Account', SORTABLE_NUMERIC_FILTER),
@@ -115,34 +147,45 @@ begin
   );
 end;
 
-function TUserAccountsDataSource.GetEntityKey(constref AItem: TAccount) : Variant;
+function TAccountsDataSource.GetEntityKey(constref AItem: TAccount) : Variant;
 begin
   Result := AItem.account;
 end;
 
-procedure TUserAccountsDataSource.FetchAll(const AContainer : TList<TAccount>);
+procedure TAccountsDataSource.FetchAll(const AContainer : TList<TAccount>);
 var
-  i : integer;
+  i,j : integer;
   acc : TAccount;
   safeBox : TPCSafeBox;
-  keys : TOrderedAccountKeysList;
   GC : TDisposables;
+  left,right:TAccountKey;
 begin
   FLastOverview.TotalPASC := 0;
   FLastOverview.TotalPASA := 0;
-
-  keys := TWallet.Keys.AccountsKeyList;
   safeBox := TUserInterface.Node.Bank.SafeBox;
   safeBox.StartThreadSafe;
   try
-
-   // load user accounts
-   for i := 0 to safeBox.AccountsCount - 1 do begin
-     acc := safeBox.Account(i);
-     if keys.IndexOfAccountKey(acc.accountInfo.accountKey)>=0 then begin
-       AContainer.Add(acc);
+   if FKeys.Count = 0 then
+     for i := 0 to safeBox.AccountsCount - 1 do begin
+       // Load all accounts
+       AContainer.Add(safeBox.Account(i));
        FLastOverview.TotalPASC := FLastOverview.TotalPASC + acc.Balance;
        inc(FLastOverview.TotalPASA);
+     end
+   else begin
+     // load key-matching accounts
+     for i := 0 to safeBox.AccountsCount - 1 do begin
+       acc := safeBox.Account(i);
+       if FKeys.Contains(acc.accountInfo.accountKey) then begin
+         AContainer.Add(acc);
+         FLastOverview.TotalPASC := FLastOverview.TotalPASC + acc.Balance;
+         inc(FLastOverview.TotalPASA);
+       end else begin
+         for left in FKeys do begin
+           right := acc.accountInfo.accountKey;
+
+         end;
+       end;
      end;
    end;
   finally
@@ -151,7 +194,7 @@ begin
   FLastKnownUserAccounts := AContainer.ToArray;
 end;
 
-function TUserAccountsDataSource.GetItemField(constref AItem: TAccount; const AColumnName : utf8string) : Variant;
+function TAccountsDataSource.GetItemField(constref AItem: TAccount; const AColumnName : utf8string) : Variant;
 var
   index : Integer;
 begin
@@ -178,7 +221,7 @@ begin
    else raise Exception.Create(Format('Field not found [%s]', [AColumnName]));
 end;
 
-procedure TUserAccountsDataSource.DehydrateItem(constref AItem: TAccount; var ATableRow: Variant);
+procedure TAccountsDataSource.DehydrateItem(constref AItem: TAccount; var ATableRow: Variant);
 //var
 //  index : Integer;
 begin
@@ -260,7 +303,10 @@ end;
 
 function TOperationsDataSourceBase.GetEntityKey(constref AItem: TOperationResume) : Variant;
 begin
-  Result := TPCOperation.OperationHashAsHexa(AItem.OperationHash);
+  if AItem.valid then
+    Result := TPCOperation.OperationHashAsHexa(AItem.OperationHash)
+  else
+    Result := nil;
 end;
 
 function TOperationsDataSourceBase.GetItemField(constref AItem: TOperationResume; const AColumnName : utf8string) : Variant;

+ 1 - 0
src/gui/UCTRLWallet.lfm

@@ -107,6 +107,7 @@ object CTRLWallet: TCTRLWallet
             'Get my first account!'
           )
           OnChange = cbAccountsChange
+          Style = csDropDownList
           TabOrder = 0
           Text = 'Show All'
         end

+ 137 - 31
src/gui/UCTRLWallet.pas

@@ -8,7 +8,7 @@ interface
 
 uses
   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, Menus,
-  ExtCtrls, PairSplitter, Buttons, UVisualGrid, UCommon.UI,
+  ExtCtrls, PairSplitter, Buttons, UVisualGrid, UCommon.UI, Generics.Collections,
   UAccounts, UDataSources, UNode, UWIZSendPASC;
 
 type
@@ -28,7 +28,7 @@ type
     Label2: TLabel;
     lblTotalPASA: TLabel;
     lblTotalPASC: TLabel;
-    MenuItem1: TMenuItem;
+    miSep2: TMenuItem;
     miCopyOphash: TMenuItem;
     miOperationInfo: TMenuItem;
     miSendPASC: TMenuItem;
@@ -46,6 +46,7 @@ type
     procedure cbAccountsChange(Sender: TObject);
     procedure cmbDurationChange(Sender: TObject);
     procedure FormCreate(Sender: TObject);
+    procedure FormDestroy(Sender: TObject);
     procedure FormResize(Sender: TObject);
     procedure miAccountInfoClick(Sender: TObject);
     procedure miCopyOphashClick(Sender: TObject);
@@ -59,40 +60,35 @@ type
     FOperationsHistory: TCTRLWalletOperationsHistory;
     FAccountsGrid: TVisualGrid;
     FOperationsGrid: TVisualGrid;
-    FAccountsDataSource: TUserAccountsDataSource;
+    FAccountsDataSource: TAccountsDataSource;
     FOperationsDataSource: TAccountsOperationsDataSource;
     procedure SetAccountsMode(AMode: TCTRLWalletAccountsMode);
     procedure SetOperationsMode(AMode: TCTRLWalletOperationsMode);
     procedure SetOperationsHistory(AHistory: TCTRLWalletOperationsHistory);
+    procedure RefreshMyAccountsCombo;
   protected
     procedure ActivateFirstTime; override;
+    procedure OnPrivateKeysChanged(Sender: TObject);
     procedure OnNodeBlocksChanged(Sender: TObject);
     procedure OnNodeNewOperation(Sender: TObject);
     procedure OnAccountsUpdated(Sender: TObject);
-    procedure OnAccountsSelected(Sender: TObject;
-      constref ASelection: TVisualGridSelection);
-    procedure OnOperationSelected(Sender: TObject;
-      constref ASelection: TVisualGridSelection);
-    procedure OnAccountsGridColumnInitialize(Sender: TObject;
-      AColIndex: integer; AColumn: TVisualColumn);
-    procedure OnOperationsGridColumnInitialize(Sender: TObject;
-      AColIndex: integer; AColumn: TVisualColumn);
-    procedure OnPrepareAccountPopupMenu(Sender: TObject;
-      constref ASelection: TVisualGridSelection; out APopupMenu: TPopupMenu);
+    procedure OnAccountsSelected(Sender: TObject; constref ASelection: TVisualGridSelection);
+    procedure OnOperationSelected(Sender: TObject; constref ASelection: TVisualGridSelection);
+    procedure OnAccountsGridColumnInitialize(Sender: TObject; AColIndex: integer; AColumn: TVisualColumn);
+    procedure OnOperationsGridColumnInitialize(Sender: TObject; AColIndex: integer; AColumn: TVisualColumn);
+    procedure OnPrepareAccountPopupMenu(Sender: TObject; constref ASelection: TVisualGridSelection; out APopupMenu: TPopupMenu);
+    procedure OnPrepareOperationsPopupMenu(Sender: TObject; constref ASelection: TVisualGridSelection; out APopupMenu: TPopupMenu);
   public
-    property AccountsMode: TCTRLWalletAccountsMode
-      read FAccountsMode write SetAccountsMode;
-    property OperationsMode: TCTRLWalletOperationsMode
-      read FOperationsMode write SetOperationsMode;
-    property OperationsHistory: TCTRLWalletOperationsHistory
-      read FOperationsHistory write SetOperationsHistory;
+    property AccountsMode: TCTRLWalletAccountsMode read FAccountsMode write SetAccountsMode;
+    property OperationsMode: TCTRLWalletOperationsMode read FOperationsMode write SetOperationsMode;
+    property OperationsHistory: TCTRLWalletOperationsHistory read FOperationsHistory write SetOperationsHistory;
   end;
 
 implementation
 
 uses
-  UUserInterface, UBlockChain, UWallet,
-  UCommon, UMemory, Generics.Collections, UCommon.Collections;
+  UUserInterface, UBlockChain, UWallet, UCrypto, UCore,
+  UCommon, UMemory, Generics.Defaults, UCommon.Collections;
 
 {$R *.lfm}
 
@@ -106,9 +102,12 @@ begin
   FNodeNotifyEvents := TNodeNotifyEvents.Create(self);
   FNodeNotifyEvents.OnBlocksChanged := OnNodeBlocksChanged;
   FNodeNotifyEvents.OnOperationsChanged := OnNodeNewOperation;
+  TWallet.Keys.OnChanged.Add(OnPrivateKeysChanged);
 
-  // data sources
-  FAccountsDataSource := TUserAccountsDataSource.Create(Self);
+
+  // fields
+  FAccountsDataSource := TAccountsDataSource.Create(Self);
+  FAccountsDataSource.FilterKeys := TWallet.Keys.AccountsKeyList.ToArray;
   FOperationsDataSource := TAccountsOperationsDataSource.Create(Self);
 
   // grids
@@ -150,13 +149,17 @@ begin
   );
   FOperationsGrid.OnColumnInitialize := OnOperationsGridColumnInitialize;
   FOperationsGrid.OnSelection := OnOperationSelected;
-  FOperationsGrid.PopupMenu := mnuOperationsPopup;
+  FOperationsGrid.OnPreparePopupMenu := OnPrepareOperationsPopupMenu;
   FOperationsGrid.Caption.Alignment := taCenter;
   FOperationsGrid.Caption.Text := 'All Account Operations';
   FOperationsGrid.Caption.Visible := True;
 
+  // key combo
+  RefreshMyAccountsCombo;
+
+  // duration combo
   cmbDuration := TComboBox.Create(FOperationsGrid);
-  FOperationsGrid.WidgetControl := cmbDuration;
+  cmbDuration.ReadOnly:= true;
   cmbDuration.Items.BeginUpdate;
   try
     cmbDuration.AddItem('30 Days', TObject(woh30Days));
@@ -164,12 +167,17 @@ begin
   finally
     cmbDuration.Items.EndUpdate;
     cmbDuration.ItemIndex := 0;
-    ;
   end;
   cmbDuration.OnChange := cmbDurationChange;
+  FOperationsGrid.WidgetControl := cmbDuration;
 
 end;
 
+procedure TCTRLWallet.FormDestroy(Sender: TObject);
+begin
+  TWallet.Keys.OnChanged.Add(OnPrivateKeysChanged);
+end;
+
 procedure TCTRLWallet.FormResize(Sender: TObject);
 begin
   // Left hand panel is 50% the size up until a max size of 450
@@ -188,6 +196,69 @@ begin
   FOperationsGrid.InternalDrawGrid.ClearSelections;
 end;
 
+procedure TCTRLWallet.RefreshMyAccountsCombo;
+var
+  i : Integer;
+  selectFirst, selectLast : boolean;
+  last_key: TAccountKey;
+  key : TWalletKey;
+  str : AnsiString;
+begin
+  // determine current selection
+  if cbAccounts.ItemIndex >= 1 then begin
+    if cbAccounts.ItemIndex < cbAccounts.Items.Count - 1 then begin
+      last_key := TBox<TAccountKey>(cbAccounts.Items.Objects[cbAccounts.ItemIndex]).Value;
+      selectFirst := false;
+      selectLast := false;
+    end else begin
+      selectFirst := false;
+      selectLast := true;
+    end;
+  end else begin
+    selectFirst := true;
+    selectLast := false;
+  end;
+
+  // update combo items
+  cbAccounts.items.BeginUpdate;
+  Try
+    // free existing items
+    for i := 0 to cbAccounts.Items.Count - 1 do
+      cbAccounts.Items.Objects[i].Free;
+    cbAccounts.Items.Clear;
+    // add new items
+    For i:=0 to TWallet.Keys.Count-1 do begin
+      // get i'th key
+      key := TWallet.Keys.Key[i];
+      // fix name
+      if (key.Name='') then begin
+        str := 'Sha256=' + TCrypto.ToHexaString( TCrypto.DoSha256( TAccountComp.AccountKey2RawString( key.AccountKey ) ) );
+      end else begin
+        str := key.Name;
+      end;
+      if Not Assigned(key.PrivateKey) then str := str + '(*)';
+      cbAccounts.Items.AddObject(str, TBox<TAccountKey>.Create(key.AccountKey));
+    end;
+    cbAccounts.Items.InsertObject(0,'Show All', TBox<TAccountKey>.Create);
+    cbAccounts.Items.AddObject('Get An Account',TBox<TAccountKey>.Create);
+  Finally
+    cbAccounts.Items.EndUpdate;
+  End;
+  // re-select previous selection
+  if selectFirst then
+    cbAccounts.ItemIndex := 0
+  else if selectLast then
+    cbAccounts.ItemIndex := cbAccounts.Items.Count - 1
+  else begin
+    for i := 1 to cbAccounts.Items.Count - 2 do begin
+       if TAccountKeyEqualityComparer.AreEqual(TBox<TAccountKey>( cbAccounts.Items.Objects[i] ).Value, last_key) then begin
+         cbAccounts.ItemIndex := i;
+         exit;
+       end;
+    end;
+  end;
+end;
+
 procedure TCTRLWallet.OnAccountsGridColumnInitialize(Sender: TObject;
   AColIndex: integer; AColumn: TVisualColumn);
 begin
@@ -207,6 +278,7 @@ end;
 procedure TCTRLWallet.SetAccountsMode(AMode: TCTRLWalletAccountsMode);
 var sel1 : TVisualGridSelection; sel2 : TRect;
 begin
+  FAccountsMode:= AMode;
   paAccounts.RemoveAllControls(False);
   case AMode of
     wamMyAccounts:
@@ -242,10 +314,10 @@ begin
   case AMode of
     womAllAccounts:
     begin
-      FOperationsGrid.Caption.Text := 'All Accounts';
+      FOperationsGrid.Caption.Text := '';
       FOperationsDataSource.Accounts :=
         TListTool<TAccount, cardinal>.Transform(
-        FAccountsDataSource.LastKnownUserAccounts, GetAccNo);
+        FAccountsDataSource.LastFetchResult, GetAccNo);
     end;
     womSelectedAccounts:
     begin
@@ -271,6 +343,11 @@ begin
   FOperationsGrid.RefreshGrid;
 end;
 
+procedure TCTRLWallet.OnPrivateKeysChanged(Sender: TObject);
+begin
+  RefreshMyAccountsCombo;
+end;
+
 procedure TCTRLWallet.OnNodeBlocksChanged(Sender: TObject);
 begin
   FAccountsGrid.RefreshGrid;
@@ -340,8 +417,25 @@ begin
 end;
 
 procedure TCTRLWallet.cbAccountsChange(Sender: TObject);
+var
+  index : Integer;
+  sel : TBox<TAccountKey>;
 begin
-  AccountsMode := wamMyAccounts;
+  index := cbAccounts.ItemIndex;
+  if cbAccounts.ItemIndex < 0 then exit;
+  if index = 0 then
+    FAccountsDataSource.FilterKeys := TWallet.Keys.AccountsKeyList.ToArray
+  else if index = cbAccounts.Items.Count - 1 then begin
+    AccountsMode:= wamFirstAccount;
+    exit;
+  end else begin
+    sel := TBox<TAccountKey>(cbAccounts.Items.Objects[cbAccounts.ItemIndex]);
+    FAccountsDataSource.FilterKeys := TArray<TAccountKey>.Create(sel.Value);
+  end;
+  if Self.AccountsMode <> wamMyAccounts then
+    AccountsMode := wamMyAccounts
+  else
+    FAccountsGrid.RefreshGrid;
 end;
 
 procedure TCTRLWallet.cmbDurationChange(Sender: TObject);
@@ -358,8 +452,7 @@ begin
   end;
 end;
 
-procedure TCTRLWallet.OnPrepareAccountPopupMenu(Sender: TObject;
-  constref ASelection: TVisualGridSelection; out APopupMenu: TPopupMenu);
+procedure TCTRLWallet.OnPrepareAccountPopupMenu(Sender: TObject; constref ASelection: TVisualGridSelection; out APopupMenu: TPopupMenu);
 begin
   miSep1.Visible := ASelection.RowCount = 1;
   miAccountInfo.Visible := ASelection.RowCount = 1;
@@ -449,6 +542,19 @@ begin
   raise ENotImplemented.Create('Not Implemented');
 end;
 
+procedure TCTRLWallet.OnPrepareOperationsPopupMenu(Sender: TObject; constref ASelection: TVisualGridSelection; out APopupMenu: TPopupMenu);
+begin
+  if (ASelection.RowCount <> 1) OR ((ASelection.RowCount = 1) and (FOperationsGrid.SelectedRows[0].__KEY <> Variant(nil))) then begin
+    miSep2.Visible := true;
+    miOperationInfo.Visible := true;
+    APopupMenu := mnuOperationsPopup;
+  end else begin
+    miSep2.Visible := false;
+    miOperationInfo.Visible := false;
+    APopupMenu := nil; // is empty, so dont show
+  end;
+end;
+
 procedure TCTRLWallet.miCopyOphashClick(Sender: TObject);
 begin
   raise ENotImplemented.Create('Not Implemented');

+ 1 - 1
src/gui/UUserInterface.pas

@@ -161,7 +161,7 @@ implementation
 
 uses
   UFRMAbout, UFRMNodesIp, UFRMPascalCoinWalletConfig, UFRMPayloadDecoder, UFRMMemoText,
-  UOpenSSL, UFileStorage, UTime, UCommon, USettings, UCoreHelpers;
+  UOpenSSL, UFileStorage, UTime, UCommon, USettings, UCore;
 
 {%region UI Lifecyle}
 

+ 1 - 1
src/gui/wizards/UWIZSendPASC_Transaction.lfm

@@ -7,7 +7,7 @@ object WIZSendPASC_Transaction: TWIZSendPASC_Transaction
   Caption = 'WIZSendPASC_Transaction'
   ClientHeight = 253
   ClientWidth = 429
-  LCLVersion = '1.8.1.0'
+  LCLVersion = '1.8.2.0'
   Visible = False
   object gbTransaction: TGroupBox
     Left = 22

+ 2 - 2
src/gui/wizards/UWIZSendPASC_Transaction.pas

@@ -48,7 +48,7 @@ implementation
 {$R *.lfm}
 
 uses
-  UAccounts, UUserInterface;
+  UAccounts, UUserInterface, USettings;
 
 { TWIZSendPASC_Transaction }
 
@@ -133,7 +133,7 @@ begin
   begin
     edtAmt.Text := TAccountComp.FormatMoney(0);
   end;
-  edtOpFee.Text := TAccountComp.FormatMoney(0);
+  edtOpFee.Text := TAccountComp.FormatMoney(TSettings.DefaultFee);
 end;
 
 procedure TWIZSendPASC_Transaction.OnNext;

+ 4 - 8
src/libraries/sphere10/UCommon.Data.pas

@@ -316,8 +316,7 @@ begin
   FColumns.Add(AColumns, Result);
 end;
 
-function TTableRow.GetProperty(var Dest: TVarData;
-  const V: TVarData; const Name: string): Boolean;
+function TTableRow.GetProperty(var Dest: TVarData; const V: TVarData; const Name: string): Boolean;
 var
   LRow: TTableRowData absolute V;
 begin
@@ -325,8 +324,7 @@ begin
   Result := true;
 end;
 
-function TTableRow.SetProperty(var V: TVarData; const Name: string;
-  const Value: TVarData): Boolean;
+function TTableRow.SetProperty(var V: TVarData; const Name: string; const Value: TVarData): Boolean;
 var
   LRow: TTableRowData absolute V;
 begin
@@ -343,8 +341,7 @@ begin
   FillChar(V, SizeOf(V), #0);
 end;
 
-procedure TTableRow.Copy(var Dest: TVarData; const Source: TVarData;
-  const Indirect: Boolean);
+procedure TTableRow.Copy(var Dest: TVarData; const Source: TVarData; const Indirect: Boolean);
 var
   LDestRow: TTableRowData absolute Dest;
   LSourceRow: TTableRowData absolute Source;
@@ -361,8 +358,7 @@ begin
   end;
 end;
 
-function TTableRow.DoFunction(var Dest: TVarData; const V: TVarData;
-  const Name: string; const Arguments: TVarDataArray): Boolean;
+function TTableRow.DoFunction(var Dest: TVarData; const V: TVarData;  const Name: string; const Arguments: TVarDataArray): Boolean;
 var
   LRow: TTableRowData absolute V;
 begin

+ 1 - 1
src/pascalcoin_wallet.lpi

@@ -413,7 +413,7 @@
         <ResourceBaseClass Value="Form"/>
       </Unit72>
       <Unit73>
-        <Filename Value="core\UCoreHelpers.pas"/>
+        <Filename Value="core\UCore.pas"/>
         <IsPartOfProject Value="True"/>
       </Unit73>
     </Units>