Herman Schoenfeld преди 7 години
родител
ревизия
90c531d021

+ 5 - 1
src/core/UDataSources.pas

@@ -17,12 +17,15 @@ type
         TotalPASC : UInt64;
         TotalPASA : Cardinal;
       end;
+    private
+      FLastKnownUserAccounts : TArray<TAccount>;
     protected
       FLastOverview : TOverview;
       function GetItemDisposePolicy : TItemDisposePolicy; override;
       function GetColumns : TTableColumns;  override;
     public
       property Overview : TOverview read FLastOverview;
+      property LastKnownUserAccounts : TArray<TAccount> read FLastKnownUserAccounts;
       function GetSearchCapabilities: TSearchCapabilities; override;
       procedure FetchAll(const AContainer : TList<TAccount>); override;
       function GetItemField(constref AItem: TAccount; const AColumnName : utf8string) : Variant; override;
@@ -79,7 +82,7 @@ type
 
   { TDataSourceTool }
 
-  TDataSourcetool = class
+  TDataSourceTool = class
     class function OperationShortHash(const AOpHash : AnsiString) : AnsiString;
     class function OperationShortText(const OpType, OpSubType : DWord) : AnsiString;
     class function AccountKeyShortText(const AText : AnsiString) : AnsiString;
@@ -138,6 +141,7 @@ begin
   finally
    safeBox.EndThreadSave;
   end;
+  FLastKnownUserAccounts := AContainer.ToArray;
 end;
 
 function TUserAccountsDataSource.GetItemField(constref AItem: TAccount; const AColumnName : utf8string) : Variant;

+ 83 - 45
src/gui/UCTRLWallet.pas

@@ -2,19 +2,22 @@ unit UCTRLWallet;
 
 {$mode delphi}
 
+{$modeswitch nestedprocvars}
+
 interface
 
 uses
   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
-  ExtCtrls, PairSplitter, Buttons, UVisualGrid, UCommon.UI, UDataSources, UNode;
+  ExtCtrls, PairSplitter, Buttons, UVisualGrid, UCommon.UI,
+  UAccounts, UDataSources, UNode;
 
 type
 
   { TCTRLWallet }
 
-  TCTRLWalletAccountView = (wavAllAccounts, wavMyAccounts, wavFirstAccount);
-
-  TCTRLWalletDuration = (wd30Days, wdFullHistory);
+  TCTRLWalletAccountsMode = (wamMyAccounts, wamFirstAccount);
+  TCTRLWalletOperationsMode = (womUnknown, womSelectedAccounts, womAllAccounts);
+  TCTRLWalletOperationsHistory = (woh30Days, wohFullHistory);
 
   TCTRLWallet = class(TApplicationForm)
     cbAccounts: TComboBox;
@@ -36,14 +39,16 @@ type
     procedure FormResize(Sender: TObject);
   private
     FNodeNotifyEvents : TNodeNotifyEvents;
-    FAccountsView : TCTRLWalletAccountView;
-    FDuration : TCTRLWalletDuration;
+    FAccountsMode : TCTRLWalletAccountsMode;
+    FOperationsMode : TCTRLWalletOperationsMode;
+    FOperationsHistory : TCTRLWalletOperationsHistory;
     FAccountsGrid : TVisualGrid;
     FOperationsGrid : TVisualGrid;
     FAccountsDataSource : TUserAccountsDataSource;
     FOperationsDataSource : TAccountsOperationsDataSource;
-    procedure SetAccountsView(view: TCTRLWalletAccountView);
-    procedure SetDuration(const ADuration: TCTRLWalletDuration);
+    procedure SetAccountsMode(AMode: TCTRLWalletAccountsMode);
+    procedure SetOperationsMode(AMode: TCTRLWalletOperationsMode);
+    procedure SetOperationsHistory(AHistory: TCTRLWalletOperationsHistory);
   protected
     procedure ActivateFirstTime; override;
     procedure OnNodeBlocksChanged(Sender: TObject);
@@ -54,14 +59,15 @@ type
     procedure OnAccountsGridColumnInitialize(Sender: TObject; AColIndex:Integer; AColumn: TVisualColumn);
     procedure OnOperationsGridColumnInitialize(Sender: TObject; AColIndex:Integer; AColumn: TVisualColumn);
   public
-    property Duration : TCTRLWalletDuration read FDuration write SetDuration;
-    property AccountsView : TCTRLWalletAccountView read FAccountsView write SetAccountsView;
+    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, UAccounts, UBlockChain, UCommon, UAutoScope, Generics.Collections;
+  UUserInterface, UBlockChain, UCommon, UAutoScope, Generics.Collections, UCommon.Collections;
 
 {$R *.lfm}
 
@@ -85,7 +91,7 @@ begin
   FAccountsGrid.FetchDataInThread:= true;
   FAccountsGrid.AutoPageSize:= true;
   FAccountsGrid.SelectionType:= stMultiRow;
-  FAccountsGrid.Options := [vgoColAutoFill, vgoColSizing, vgoSortDirectionAllowNone];
+  FAccountsGrid.Options := [vgoColAutoFill, vgoColSizing, vgoAllowDeselect, vgoSortDirectionAllowNone];
   FAccountsGrid.DefaultColumnWidths := TArray<Integer>.Create(
     100,                   // Account
     CT_VISUALGRID_STRETCH, // Name
@@ -100,7 +106,7 @@ begin
   FOperationsGrid.FetchDataInThread:= true;
   FOperationsGrid.AutoPageSize:= true;
   FOperationsGrid.SelectionType:= stRow;
-  FOperationsGrid.Options := [vgoColAutoFill, vgoColSizing, vgoSortDirectionAllowNone];
+  FOperationsGrid.Options := [vgoColAutoFill, vgoAllowDeselect, vgoColSizing, vgoSortDirectionAllowNone];
   FOperationsGrid.DefaultColumnWidths := TArray<Integer>.Create(
     130,                   // Time
     CT_VISUALGRID_DEFAULT, // Block
@@ -122,17 +128,21 @@ begin
   FOperationsGrid.WidgetControl := cmbDuration;
   cmbDuration.Items.BeginUpdate;
   try
-    cmbDuration.AddItem('30 Days', TObject(wd30Days));
-    cmbDuration.AddItem('Maximum', TObject(wdFullHistory));
+    cmbDuration.AddItem('30 Days', TObject(woh30Days));
+    cmbDuration.AddItem('Maximum', TObject(wohFullHistory));
   finally
     cmbDuration.Items.EndUpdate;
     cmbDuration.ItemIndex:=0;;
   end;
   cmbDuration.OnChange:=cmbDurationChange;
 
-  AccountsView := wavMyAccounts;
+  // dock operations grid in panel
   paOperations.AddControlDockCenter(FOperationsGrid);
-  Duration := wd30Days;
+
+  // Configure grid states
+  AccountsMode := wamMyAccounts;
+  OperationsMode:= womUnknown;
+  OperationsHistory := woh30Days;
 end;
 
 procedure TCTRLWallet.FormResize(Sender: TObject);
@@ -160,28 +170,60 @@ begin
   end;
 end;
 
-procedure TCTRLWallet.SetAccountsView(view: TCTRLWalletAccountView);
+procedure TCTRLWallet.SetAccountsMode(AMode: TCTRLWalletAccountsMode);
 begin
   paAccounts.RemoveAllControls(false);
-  case view of
-     wavAllAccounts: raise Exception.Create('Not implemented');
-     wavMyAccounts: begin
+  case AMode of
+     wamMyAccounts: begin
        FOperationsGrid.DataSource := FOperationsDataSource;
        FAccountsGrid.DataSource := FAccountsDataSource;
        FAccountsGrid.Caption.Text := 'My Accounts';
        paAccounts.AddControlDockCenter(FAccountsGrid);
        FAccountsGrid.RefreshGrid;
      end;
-     wavFirstAccount: raise Exception.Create('Not implemented');
+     wamFirstAccount: raise Exception.Create('Not implemented');
+  end;
+end;
+
+procedure TCTRLWallet.SetOperationsMode(AMode: TCTRLWalletOperationsMode);
+
+  function GetAccNo (constref AAccount : TAccount) : Cardinal; overload;
+  begin
+    Result := AAccount.account;
+  end;
+
+  function GetAccNo(constref ARow : Variant) : Cardinal; overload;
+  begin
+    if NOT TAccountComp.AccountTxtNumberToAccountNumber( ARow.Account, Result ) then
+      raise Exception.Create('Internal Error: Unable to parse account number from table row');
+  end;
+
+begin
+  case AMode of
+     womUnknown: begin
+       FOperationsGrid.Caption.Text := '';
+       FOperationsDataSource.Accounts := TArrayTool<Cardinal>.Empty;
+     end;
+     womAllAccounts: begin
+       FOperationsGrid.Caption.Text := 'All Accounts';
+       FOperationsDataSource.Accounts := TListTool<TAccount, Cardinal>.Transform( FAccountsDataSource.LastKnownUserAccounts, GetAccNo );
+     end;
+     womSelectedAccounts: begin
+       FOperationsGrid.Caption.Text := 'Selected Accounts';
+       FOperationsDataSource.Accounts := TListTool<Variant, Cardinal>.Transform( FAccountsGrid.SelectedRows, GetAccNo);
+     end
+     else raise ENotSupportedException.Create(Format('AMode %d not supported', [Integer(AMode)]));
   end;
+  FOperationsGrid.RefreshGrid;
+  FOperationsMode:=AMode;
 end;
 
-procedure TCTRLWallet.SetDuration(const ADuration: TCTRLWalletDuration);
+procedure TCTRLWallet.SetOperationsHistory(AHistory: TCTRLWalletOperationsHistory);
 begin
-  FDuration:= ADuration;
-  case FDuration of
-    wd30Days: FOperationsDataSource.TimeSpan := TTimeSpan.FromDays(30);
-    wdFullHistory: FOperationsDataSource.TimeSpan := TTimeSpan.FromDays(10 * 365);
+  FOperationsHistory := AHistory;
+  case FOperationsHistory of
+    woh30Days: FOperationsDataSource.TimeSpan := TTimeSpan.FromDays(30);
+    wohFullHistory: FOperationsDataSource.TimeSpan := TTimeSpan.FromDays(10 * 365);
   end;
   FOperationsGrid.RefreshGrid;
 end;
@@ -189,13 +231,13 @@ end;
 procedure TCTRLWallet.OnNodeBlocksChanged(Sender: TObject);
 begin
   FAccountsGrid.RefreshGrid;
-  SetDuration(FDuration);
+  FOperationsGrid.RefreshGrid;
 end;
 
 procedure TCTRLWallet.OnNodeNewOperation(Sender: TObject);
 begin
   FAccountsGrid.RefreshGrid;
-  SetDuration(FDuration);
+  FOperationsGrid.RefreshGrid;
 end;
 
 procedure TCTRLWallet.OnAccountsUpdated(Sender: TObject);
@@ -213,11 +255,16 @@ var
 begin
   selectedAccounts := GC.AddObject( TList<Cardinal>.Create ) as TList<Cardinal>;
 
-  for row := ASelection.Row to (ASelection.Row + ASelection.RowCount - 1) do begin
-    if (TAccountComp.AccountTxtNumberToAccountNumber( FAccountsGrid.Rows[row].Account, acc)) then
-      selectedAccounts.Add(acc);
+  if ASelection.RowCount > 0 then begin
+    for row := ASelection.Row to (ASelection.Row + ASelection.RowCount - 1) do begin
+      if (TAccountComp.AccountTxtNumberToAccountNumber( FAccountsGrid.Rows[row].Account, acc)) then
+        selectedAccounts.Add(acc);
+    end;
+    FOperationsDataSource.Accounts := selectedAccounts.ToArray;
+  end else begin
+
+    TUserInterface.ShowInfo(Self, 'Deselect', 'Deselect');
   end;
-  FOperationsDataSource.Accounts := selectedAccounts.ToArray;
   FOperationsGrid.RefreshGrid;
 end;
 
@@ -238,29 +285,20 @@ end;
 
 procedure TCTRLWallet.cbAccountsChange(Sender: TObject);
 begin
-  case cbAccounts.ItemIndex of
-     0: AccountsView := wavAllAccounts;
-     1: AccountsView := wavMyAccounts;
-     2: AccountsView := wavFirstAccount;
-  end;
+  AccountsMode := wamMyAccounts;
 end;
 
 procedure TCTRLWallet.cmbDurationChange(Sender: TObject);
 var
   cmbDuration : TComboBox;
-  newDuration : TCTRLWalletDuration;
 begin
   cmbDuration := Sender as TComboBox;
   if not Assigned(cmbDuration) then
     exit;
 
   case cmbDuration.ItemIndex of
-     0: newDuration := wd30Days;
-     1: newDuration := wdFullHistory;
-  end;
-  if Duration <> newDuration then begin
-    Duration := newDuration;
-    FOperationsGrid.RefreshGrid;
+     0: OperationsHistory := woh30Days;
+     1: OperationsHistory := wohFullHistory;
   end;
 end;
 

+ 133 - 0
src/libraries/sphere10/UCommon.Collections.pas

@@ -64,10 +64,20 @@ type
 
   TGlobalPredicateFunc<T> = function (constref AVal : T) : boolean;
 
+  TNestedTransformFunc<T1, T2> = function (constref AItem : T1) : T2 is nested;
+
+  TObjectTransformFunc<T1, T2> = function (constref AItem : T1) : T2 of object;
+
+  TGlobalTransformFunc<T1, T2> = function (constref AItem : T1) : T2;
+
   IPredicate<T> = interface
     function Evaluate (constref AValue: T) : boolean;
   end;
 
+  ITransformer<T1, T2> = interface
+    function Transform(const AItem : T1) : T2;
+  end;
+
   TPredicateTool<T> = class
     private type
       __IPredicate_T = IPredicate<T>;
@@ -106,6 +116,18 @@ type
     class procedure DiposeItem(const AList: TList<T>; const index : SizeInt; const ADisposePolicy : TItemDisposePolicy);
   end;
 
+  TListTool<T1, T2> = class
+    public
+      class function Transform(const AArray : TArray<T1>; const ATransform : TNestedTransformFunc<T1, T2>) : TArray<T2>; overload;
+      class function Transform(const AArray : TArray<T1>; const ATransform : TObjectTransformFunc<T1, T2>) : TArray<T2>; overload;
+      class function Transform(const AArray : TArray<T1>; const ATransform : TGlobalTransformFunc<T1, T2>) : TArray<T2>; overload;
+      class function Transform(const AArray : TArray<T1>; const ATransformer : ITransformer<T1, T2>) : TArray<T2>; overload;
+      class function Transform(const AList : TList<T1>; const ATransform : TNestedTransformFunc<T1, T2>) : TArray<T2>; overload;
+      class function Transform(const AList : TList<T1>; const ATransform : TObjectTransformFunc<T1, T2>) : TArray<T2>; overload;
+      class function Transform(const AList : TList<T1>; const ATransform : TGlobalTransformFunc<T1, T2>) : TArray<T2>; overload;
+      class function Transform(const AList : TList<T1>; const ATransformer : ITransformer<T1, T2>) : TArray<T2>; overload;
+  end;
+
   { Private types (implementation only) - FPC Bug 'Global Generic template references static symtable' }
 
   { TNestedComparer }
@@ -216,6 +238,35 @@ type
      function Evaluate (constref AValue: T) : boolean;
   end;
 
+  { TNestedTransformer }
+
+  TNestedTransformer<T1, T2> = class (TInterfacedObject, ITransformer<T1, T2>)
+    private
+      FFunc : TNestedTransformFunc<T1, T2>;
+    public
+      constructor Create(const AFunc: TNestedTransformFunc<T1, T2>); overload;
+      function Transform(const AItem : T1) : T2;
+  end;
+
+  { TObjectTransformer }
+
+  TObjectTransformer<T1, T2> = class (TInterfacedObject, ITransformer<T1, T2>)
+    private
+      FFunc : TObjectTransformFunc<T1, T2>;
+    public
+      constructor Create(const AFunc: TObjectTransformFunc<T1, T2>); overload;
+      function Transform(const AItem : T1) : T2;
+  end;
+
+  { TGlobalTransformer }
+
+  TGlobalTransformer<T1, T2> = class (TInterfacedObject, ITransformer<T1, T2>)
+    private
+      FFunc : TGlobalTransformFunc<T1, T2>;
+    public
+      constructor Create(const AFunc: TGlobalTransformFunc<T1, T2>); overload;
+      function Transform(const AItem : T1) : T2;
+  end;
 
 implementation
 
@@ -586,6 +637,40 @@ end;
 
 {%endregion}
 
+{%region Transformers}
+
+constructor TNestedTransformer<T1, T2>.Create(const AFunc: TNestedTransformFunc<T1, T2>); overload;
+begin
+  FFunc := AFunc;
+end;
+
+function TNestedTransformer<T1, T2>.Transform(const AItem : T1) : T2;
+begin
+  Result := FFunc(AItem);
+end;
+
+constructor TObjectTransformer<T1, T2>.Create(const AFunc: TObjectTransformFunc<T1, T2>); overload;
+begin
+  FFunc := AFunc;
+end;
+
+function TObjectTransformer<T1, T2>.Transform(const AItem : T1) : T2;
+begin
+  Result := FFunc(AItem);
+end;
+
+constructor TGlobalTransformer<T1, T2>.Create(const AFunc: TGlobalTransformFunc<T1, T2>); overload;
+begin
+  FFunc := AFunc;
+end;
+
+function TGlobalTransformer<T1, T2>.Transform(const AItem : T1) : T2;
+begin
+  Result := FFunc(AItem);
+end;
+
+{%endregion}
+
 {%region TListTool}
 
 class function TListTool<T>.Copy(const AList: TList<T>; const AIndex, ACount : SizeInt) : TList<T>;
@@ -683,6 +768,54 @@ begin
   end;
 end;
 
+class function TListTool<T1, T2>.Transform(const AArray : TArray<T1>; const ATransform : TNestedTransformFunc<T1, T2>) : TArray<T2>;
+begin
+  Result := Transform(AArray, TNestedTransformer<T1, T2>.Create(ATransform));
+end;
+
+class function TListTool<T1, T2>.Transform(const AArray : TArray<T1>; const ATransform : TObjectTransformFunc<T1, T2>) : TArray<T2>;
+begin
+  Result := Transform(AArray, TObjectTransformer<T1, T2>.Create(ATransform));
+end;
+
+class function TListTool<T1, T2>.Transform(const AArray : TArray<T1>; const ATransform : TGlobalTransformFunc<T1, T2>) : TArray<T2>;
+begin
+  Result := Transform(AArray, TGlobalTransformer<T1, T2>.Create(ATransform));
+end;
+
+class function TListTool<T1, T2>.Transform(const AArray : TArray<T1>; const ATransformer : ITransformer<T1, T2>) : TArray<T2>;
+var
+  i : integer;
+begin
+  SetLength(Result, Length(AArray));
+  for i := Low(AArray) to High(AArray) do
+    Result[i] := ATransformer.Transform(AArray[i]);
+end;
+
+class function TListTool<T1, T2>.Transform(const AList : TList<T1>; const ATransform : TNestedTransformFunc<T1, T2>) : TArray<T2>;
+begin
+  Result := Transform(AList, TNestedTransformer<T1, T2>.Create(ATransform));
+end;
+
+class function TListTool<T1, T2>.Transform(const AList : TList<T1>; const ATransform : TObjectTransformFunc<T1, T2>) : TArray<T2>;
+begin
+  Result := Transform(AList, TObjectTransformer<T1, T2>.Create(ATransform));
+end;
+
+class function TListTool<T1, T2>.Transform(const AList : TList<T1>; const ATransform : TGlobalTransformFunc<T1, T2>) : TArray<T2>;
+begin
+  Result := Transform(AList, TGlobalTransformer<T1, T2>.Create(ATransform));
+end;
+
+class function TListTool<T1, T2>.Transform(const AList : TList<T1>; const ATransformer : ITransformer<T1, T2>) : TArray<T2>;
+var
+  i : integer;
+begin
+  SetLength(Result, AList.Count);
+  for i := 0 to AList.Count - 1 do
+    Result[i] := ATransformer.Transform(AList[i]);
+end;
+
 {%endregion}
 
 end.

+ 7 - 1
src/libraries/sphere10/UCommon.pas

@@ -261,10 +261,11 @@ type
     procedure Invoke(sender : TObject; const args: array of Pointer);
   end;
 
-   { TArrayTool }
+  { TArrayTool }
 
   TArrayTool<T> = class
     public
+      class function Empty : TArray<T>;
       class function Contains(const Values: TArray<T>; const Item: T; const Comparer: IEqualityComparer<T>; out ItemIndex: SizeInt): Boolean; overload; static;
       class function Contains(const Values: TArray<T>; const Item: T; out ItemIndex: SizeInt): Boolean; overload; static;
       class function Contains(const Values: TArray<T>; const Item: T) : Boolean; overload; static;
@@ -1129,6 +1130,11 @@ end;
 
 {%region TArrayTool}
 
+class function TArrayTool<T>.Empty : TArray<T>;
+begin
+  SetLength(Result, 0);
+end;
+
 class function TArrayTool<T>.Contains(const Values: TArray<T>; const Item: T; const Comparer: IEqualityComparer<T>; out ItemIndex: SizeInt): Boolean;
 var
   Index: SizeInt;

+ 17 - 0
src/libraries/sphere10/UVisualGrid.pas

@@ -249,6 +249,7 @@ type
     function GetRowCount: Integer; inline;
     function GetRows(ARow: Integer): Variant;
     function GetSelection: TVisualGridSelection;
+    function GetSelectedRows : TArray<Variant>;
     procedure ControlsEnable(AEnable: boolean);
     function GetCanvas: TCanvas;
     procedure SetCells(ACol, ARow: Integer; AValue: Variant);
@@ -332,6 +333,7 @@ type
     property Canvas: TCanvas read GetCanvas;
     property SelectionType: TSelectionType read FSelectionType write SetSelectionType;
     property Selection: TVisualGridSelection read GetSelection;
+    property SelectedRows : TArray<Variant> read GetSelectedRows;
     property SortMode: TSortMode read FSortMode write SetSortMode;
     property SearchMode : TSearchMode read FSearchMode write SetSearchMode;
 
@@ -1459,6 +1461,21 @@ begin
   end;
 end;
 
+function TCustomVisualGrid.GetSelectedRows : TArray<Variant>;
+var
+  sel : TVisualGridSelection;
+  selectedRows : TList<Variant>;
+  GC: TScoped;
+  row : Integer;
+begin
+  sel := GetSelection;
+  selectedRows := GC.AddObject( TList<Variant>.Create ) as TList<Variant>;
+  if sel.RowCount > 0 then
+    for row := sel.Row to (sel.Row + sel.RowCount - 1) do
+       selectedRows.Add(Self.Rows[row]);
+  result := selectedRows.ToArray;
+end;
+
 procedure TCustomVisualGrid.PageIndexEditingDone(Sender: TObject);
 var
   LPageIndex: Integer;

+ 0 - 1
src/pascalcoin_wallet.lpi

@@ -13,7 +13,6 @@
       <MainUnit Value="0"/>
       <Title Value="PascalCoin Wallet"/>
       <ResourceType Value="res"/>
-      <Icon Value="0"/>
     </General>
     <i18n>
       <EnableI18N LFM="False"/>