Browse Source

Revert Grids to Previous State.

Ugochukwu Mmaduekwe 7 years ago
parent
commit
b2130b1dde

+ 492 - 193
src/gui/UFRMAccountExplorer.lfm

@@ -1,229 +1,528 @@
 object FRMAccountExplorer: TFRMAccountExplorer
 object FRMAccountExplorer: TFRMAccountExplorer
-  Left = -7
-  Height = 459
-  Top = 2
-  Width = 926
-  ActiveControl = chkExploreMyAccounts
-  Caption = 'Account Explorer'
-  ClientHeight = 459
-  ClientWidth = 926
+  Left = 207
+  Height = 451
+  Top = 94
+  Width = 868
+  ActiveControl = cbMyPrivateKeys
+  Caption = 'Accounts Explorer'
+  ClientHeight = 451
+  ClientWidth = 868
+  FormStyle = fsMDIChild
+  Menu = meAccountExplorerMenu
   OnCreate = FormCreate
   OnCreate = FormCreate
+  OnDestroy = FormDestroy
   Position = poOwnerFormCenter
   Position = poOwnerFormCenter
   LCLVersion = '1.8.2.0'
   LCLVersion = '1.8.2.0'
   Visible = False
   Visible = False
-  object PairSplitter1: TPairSplitter
+  object Splitter1: TSplitter
+    Left = 380
+    Height = 365
+    Top = 66
+    Width = 5
+  end
+  object pnlMyAccountsTop: TPanel
     Left = 0
     Left = 0
-    Height = 459
+    Height = 66
     Top = 0
     Top = 0
-    Width = 926
-    Align = alClient
-    Position = 500
-    object PairSplitterSide1: TPairSplitterSide
-      Cursor = crArrow
+    Width = 868
+    Align = alTop
+    BevelOuter = bvNone
+    ClientHeight = 66
+    ClientWidth = 868
+    TabOrder = 0
+    object Label18: TLabel
+      Left = 11
+      Height = 15
+      Top = 40
+      Width = 69
+      Caption = 'Find account'
+      ParentColor = False
+    end
+    object cbMyPrivateKeys: TComboBox
+      Left = 308
+      Height = 23
+      Top = 5
+      Width = 411
+      ItemHeight = 15
+      OnChange = cbMyPrivateKeysChange
+      Style = csDropDownList
+      TabOrder = 0
+    end
+    object cbExploreMyAccounts: TCheckBox
+      Left = 11
+      Height = 19
+      Top = 9
+      Width = 255
+      Caption = 'Explore accounts with one of my Wallet Keys'
+      OnChange = cbExploreMyAccountsChange
+      TabOrder = 1
+    end
+    object ebFindAccountNumber: TEdit
+      Left = 95
+      Height = 23
+      Top = 33
+      Width = 83
+      OnChange = ebFindAccountNumberChange
+      OnExit = ebFindAccountNumberExit
+      TabOrder = 3
+    end
+    object bbChangeKeyName: TBitBtn
+      Left = 733
+      Height = 25
+      Top = 5
+      Width = 126
+      Caption = 'Change Key name'
+      OnClick = bbChangeKeyNameClick
+      TabOrder = 2
+    end
+    object cbFilterAccounts: TCheckBox
+      Left = 308
+      Height = 19
+      Top = 35
+      Width = 157
+      Caption = 'Filter accounts by balance'
+      OnChange = cbFilterAccountsChange
+      TabOrder = 4
+    end
+    object ebFilterAccountByBalanceMin: TEdit
+      Left = 472
+      Height = 23
+      Hint = 'Min balance'
+      Top = 33
+      Width = 83
+      OnExit = ebFilterAccountByBalanceMinExit
+      OnKeyPress = ebFilterAccountByBalanceMinKeyPress
+      TabOrder = 5
+    end
+    object ebFilterAccountByBalanceMax: TEdit
+      Left = 568
+      Height = 23
+      Hint = 'Max balance'
+      Top = 33
+      Width = 83
+      OnExit = ebFilterAccountByBalanceMinExit
+      OnKeyPress = ebFilterAccountByBalanceMinKeyPress
+      TabOrder = 6
+    end
+    object sbSearchAccount: TSpeedButton
+      Left = 184
+      Height = 23
+      Top = 33
+      Width = 24
+      Glyph.Data = {
+        36030000424D3803000000000000360000002800000010000000100000000100
+        18000000000000000000120B0000120B00000000000000000000FF00FF4A667C
+        BE9596FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
+        FFFF00FFFF00FFFF00FF6B9CC31E89E84B7AA3C89693FF00FFFF00FFFF00FFFF
+        00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF4BB4FE51B5FF
+        2089E94B7AA2C69592FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
+        FFFF00FFFF00FFFF00FFFF00FF51B7FE51B3FF1D87E64E7AA0CA9792FF00FFFF
+        00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+        51B7FE4EB2FF1F89E64E7BA2B99497FF00FFFF00FFFF00FFFF00FFFF00FFFF00
+        FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF52B8FE4BB1FF2787D95F6A76FF
+        00FFB0857FC09F94C09F96BC988EFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+        FF00FFFF00FF55BDFFB5D6EDBF9D92BB9B8CE7DAC2FFFFE3FFFFE5FDFADAD8C3
+        B3B58D85FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFCEA795FD
+        EEBEFFFFD8FFFFDAFFFFDBFFFFE6FFFFFBEADDDCAE837FFF00FFFF00FFFF00FF
+        FF00FFFF00FFFF00FFFF00FFC1A091FBDCA8FEF7D0FFFFDBFFFFE3FFFFF8FFFF
+        FDFFFFFDC6A99CFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFC1A091FEE3ACF1
+        C491FCF2CAFFFFDDFFFFE4FFFFF7FFFFF7FFFFE9EEE5CBB9948CFF00FFFF00FF
+        FF00FFFF00FFFF00FFC2A191FFE6AEEEB581F7DCAEFEFDD8FFFFDFFFFFE3FFFF
+        E4FFFFE0F3ECD2BB968EFF00FFFF00FFFF00FFFF00FFFF00FFBC978CFBE7B7F4
+        C791F2C994F8E5B9FEFCD8FFFFDDFFFFDCFFFFE0E2D2BAB68E86FF00FFFF00FF
+        FF00FFFF00FFFF00FFFF00FFD9C3A9FFFEE5F7DCB8F2C994F5D4A5FAE8BDFDF4
+        C9FDFBD6B69089FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFB58D85E8
+        DEDDFFFEF2F9D8A3F4C48CF9D49FFDEAB8D0B49FB89086FF00FFFF00FFFF00FF
+        FF00FFFF00FFFF00FFFF00FFFF00FFAD827FC9AA9EEFE0B7EFDFB2E7CEACB890
+        86B89086FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
+        00FFFF00FFBA968ABB988CB79188FF00FFFF00FFFF00FFFF00FF
+      }
+      OnClick = sbSearchAccountClick
+    end
+  end
+  object pnlAccounts: TPanel
+    Left = 0
+    Height = 365
+    Top = 66
+    Width = 380
+    Align = alLeft
+    BevelOuter = bvNone
+    ClientHeight = 365
+    ClientWidth = 380
+    TabOrder = 1
+    object dgAccounts: TDrawGrid
       Left = 0
       Left = 0
-      Height = 459
+      Height = 331
       Top = 0
       Top = 0
-      Width = 500
-      ClientWidth = 500
-      ClientHeight = 459
-      object GroupBox1: TGroupBox
-        Left = 8
-        Height = 89
-        Top = 8
-        Width = 484
-        Anchors = [akTop, akLeft, akRight]
-        Caption = 'Overview'
-        ClientHeight = 69
-        ClientWidth = 480
+      Width = 380
+      Align = alClient
+      ExtendedSelect = False
+      TabOrder = 0
+      TitleFont.Color = clWindowText
+      TitleFont.Height = -11
+      TitleFont.Name = 'Tahoma'
+      OnClick = dgAccountsClick
+    end
+    object pnlAccountsInfo: TPanel
+      Left = 0
+      Height = 34
+      Top = 331
+      Width = 380
+      Align = alBottom
+      BevelOuter = bvNone
+      ClientHeight = 34
+      ClientWidth = 380
+      TabOrder = 1
+      object Label17: TLabel
+        Left = 5
+        Height = 15
+        Top = 10
+        Width = 53
+        Caption = 'Accounts:'
+        ParentColor = False
+      end
+      object Label19: TLabel
+        Left = 136
+        Height = 15
+        Top = 10
+        Width = 44
+        Caption = 'Balance:'
+        ParentColor = False
+      end
+      object lblAccountsCount: TLabel
+        Left = 60
+        Height = 15
+        Top = 10
+        Width = 18
+        Caption = '000'
+        ParentColor = False
+      end
+      object lblAccountsBalance: TLabel
+        Left = 200
+        Height = 15
+        Top = 10
+        Width = 18
+        Caption = '000'
+        ParentColor = False
+      end
+      object bbAccountsRefresh: TBitBtn
+        Left = 302
+        Height = 25
+        Top = 6
+        Width = 75
+        Anchors = [akTop, akRight]
+        Caption = 'Refresh'
+        Glyph.Data = {
+          36030000424D3603000000000000360000002800000010000000100000000100
+          18000000000000030000120B0000120B00000000000000000000FF00FFFF00FF
+          C2A6A4C2A6A4C2A6A4C2A6A4C2A6A4C2A6A4C2A6A4C2A6A4C2A6A4C2A6A4C2A6
+          A4C2A6A4FF00FFFF00FFFF00FFFF00FFC2A6A4FEFCFBFEFCFBFEFCFBFEFCFBFE
+          FCFBFEFCFBFEFCFBFEFCFBFEFCFBFEFCFBC2A6A4FF00FFFF00FFFF00FFFF00FF
+          C2A6A4FEFCFBFEFCFBFEFCFBFEFCFBD8EBD6018A02018A02D8EBD6FEFCFBFEFC
+          FBC2A6A4FF00FFFF00FFFF00FFFF00FFC2A6A4FEFBF7FEFBF7018A02D8EAD201
+          8A02D8EAD2D8EAD2018A02FEFBF7FEFBF7C2A6A4FF00FFFF00FFFF00FFFF00FF
+          C2A6A4FEF9F4FEF9F4018A02018A02D8E8D0FEF9F4FEF9F4D8E8D0FEF9F4FEF9
+          F4C2A6A4FF00FFFF00FFFF00FFFF00FFC2A6A4FEF7F0FEF7F0018A02018A0201
+          8A02FEF7F0FEF7F0FEF7F0FEF7F0FEF7F0C2A6A4FF00FFFF00FFFF00FFFF00FF
+          C2A6A4FEF5ECFEF5ECFEF5ECFEF5ECFEF5EC018A02018A02018A02FEF5ECFEF5
+          ECC2A6A4FF00FFFF00FFFF00FFFF00FFC2A6A4FEF3E9FEF3E9D8E3C7FEF3E9FE
+          F3E9D8E3C7018A02018A02FEF3E9FEF3E9C2A6A4FF00FFFF00FFFF00FFFF00FF
+          C2A6A4FFF1E5FFF1E5018A02D9E2C3D9E2C3018A02D9E2C3018A02FFF1E5FFF1
+          E5C2A6A4FF00FFFF00FFFF00FFFF00FFC2A6A4FFF0E2FFF0E2D9E1C1018A0201
+          8A02D9E1C1DDCFC2DDCFC2DDCFC2DDCFC2C2A6A4FF00FFFF00FFFF00FFFF00FF
+          C2A6A4FFEEDEFFEEDEFFEEDEFFEEDEFFEEDEFFEEDEC5B5A9C3B4A8C2B3A7C1B2
+          A6C2A6A4FF00FFFF00FFFF00FFFF00FFC2A6A4FFECDAFFECDAFFECDAFFECDAFF
+          ECDAFFECDAB0A296B0A296B0A296B0A296C2A6A4FF00FFFF00FFFF00FFFF00FF
+          C2A6A4FFEAD7FFEAD7FFEAD7FFEAD7FFEAD7C9B9ACFBF8F4FBF8F4E6DAD9C2A6
+          A4FF00FFFF00FFFF00FFFF00FFFF00FFC2A6A4FFE8D3FFE8D3FFE8D3FFE8D3FF
+          E8D3C9B9ACFBF8F4DFCEC7C2A6A4FF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+          C2A6A4FFE6D0FFE6D0FFE6D0FFE6D0FFE6D0C9B9ACDFCEC7C2A6A4FF00FFFF00
+          FFFF00FFFF00FFFF00FFFF00FFFF00FFC2A6A4C2A6A4C2A6A4C2A6A4C2A6A4C2
+          A6A4C2A6A4C2A6A4FF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+        }
+        OnClick = bbAccountsRefreshClick
         TabOrder = 0
         TabOrder = 0
-        object Label1: TLabel
-          Left = 16
+      end
+    end
+  end
+  object pcAccountsOptions: TPageControl
+    Left = 385
+    Height = 365
+    Top = 66
+    Width = 483
+    ActivePage = tsMultiSelectAccounts
+    Align = alClient
+    TabIndex = 1
+    TabOrder = 2
+    object tsAccountOperations: TTabSheet
+      Caption = 'Operations of selected Account'
+      ClientHeight = 355
+      ClientWidth = 470
+      object dgAccountOperations: TDrawGrid
+        Left = 0
+        Height = 355
+        Top = 0
+        Width = 470
+        Align = alClient
+        ExtendedSelect = False
+        TabOrder = 0
+        TitleFont.Color = clWindowText
+        TitleFont.Height = -11
+        TitleFont.Name = 'Tahoma'
+        OnClick = dgAccountOperationsClick
+        OnDblClick = dgAccountOperationsClick
+      end
+    end
+    object tsMultiSelectAccounts: TTabSheet
+      Caption = 'Selected accounts for massive operations'
+      ClientHeight = 337
+      ClientWidth = 475
+      ImageIndex = 1
+      object dgSelectedAccounts: TDrawGrid
+        Left = 41
+        Height = 280
+        Top = 31
+        Width = 325
+        Align = alLeft
+        Anchors = [akTop, akLeft, akRight, akBottom]
+        ExtendedSelect = False
+        TabOrder = 0
+        TitleFont.Color = clWindowText
+        TitleFont.Height = -11
+        TitleFont.Name = 'Tahoma'
+      end
+      object pnlSelectedAccountsTop: TPanel
+        Left = 0
+        Height = 31
+        Top = 0
+        Width = 475
+        Align = alTop
+        BevelOuter = bvNone
+        ClientHeight = 31
+        ClientWidth = 475
+        Font.Color = clWindowText
+        Font.Height = -13
+        Font.Name = 'Tahoma'
+        Font.Style = [fsBold]
+        ParentFont = False
+        TabOrder = 1
+        object Label15: TLabel
+          Left = 41
+          Height = 16
+          Top = 4
+          Width = 361
+          Caption = 'Select multiple accounts to execute massive operations'
+          ParentColor = False
+        end
+      end
+      object pnlSelectedAccountsBottom: TPanel
+        Left = 0
+        Height = 26
+        Top = 311
+        Width = 475
+        Align = alBottom
+        BevelOuter = bvNone
+        ClientHeight = 26
+        ClientWidth = 475
+        TabOrder = 2
+        object Label20: TLabel
+          Left = 41
           Height = 15
           Height = 15
-          Top = 8
-          Width = 58
-          Caption = 'Total PASC'
-          Font.Style = [fsBold]
+          Top = 6
+          Width = 53
+          Caption = 'Accounts:'
           ParentColor = False
           ParentColor = False
-          ParentFont = False
         end
         end
-        object Label2: TLabel
-          Left = 16
+        object lblSelectedAccountsCount: TLabel
+          Left = 96
           Height = 15
           Height = 15
-          Top = 40
-          Width = 59
-          Caption = 'Total PASA'
-          Font.Style = [fsBold]
+          Top = 6
+          Width = 18
+          Caption = '000'
           ParentColor = False
           ParentColor = False
-          ParentFont = False
         end
         end
-        object lblTotalPASA: TLabel
-          Left = 360
+        object Label22: TLabel
+          Left = 156
           Height = 15
           Height = 15
-          Top = 40
-          Width = 108
-          Alignment = taRightJustify
-          Anchors = [akTop, akRight]
-          AutoSize = False
-          Caption = '0'
-          Font.Style = [fsBold]
+          Top = 6
+          Width = 97
+          Caption = 'Accounts Balance:'
           ParentColor = False
           ParentColor = False
-          ParentFont = False
         end
         end
-        object lblTotalPASC: TLabel
-          Left = 360
+        object lblSelectedAccountsBalance: TLabel
+          Left = 250
           Height = 15
           Height = 15
-          Top = 8
-          Width = 106
-          Alignment = taRightJustify
-          Anchors = [akTop, akRight]
-          AutoSize = False
-          Caption = '0'
-          Font.Style = [fsBold]
+          Top = 6
+          Width = 18
+          Caption = '000'
           ParentColor = False
           ParentColor = False
-          ParentFont = False
         end
         end
       end
       end
-      object gpAccounts: TGroupBox
-        Left = 8
-        Height = 344
-        Top = 104
-        Width = 484
-        Anchors = [akTop, akLeft, akRight, akBottom]
-        Caption = 'Accounts'
-        ClientHeight = 324
-        ClientWidth = 480
-        TabOrder = 1
-        object paAccounts: TPanel
-          Left = 8
-          Height = 240
-          Top = 80
-          Width = 460
-          Anchors = [akTop, akLeft, akRight, akBottom]
-          BorderSpacing.Around = 3
-          BevelOuter = bvNone
-          Caption = 'MY ACCOUNT PANEL'
-          ParentColor = False
-          TabOrder = 0
+      object pnlSelectedAccountsLeft: TPanel
+        Left = 0
+        Height = 280
+        Top = 31
+        Width = 41
+        Align = alLeft
+        BevelOuter = bvNone
+        ClientHeight = 280
+        ClientWidth = 41
+        TabOrder = 3
+        object sbSelectedAccountsAdd: TSpeedButton
+          Left = 2
+          Height = 31
+          Top = 0
+          Width = 33
+          Caption = '>'
+          OnClick = sbSelectedAccountsAddClick
         end
         end
-        object chkExploreMyAccounts: TCheckBox
-          Left = 8
-          Height = 19
-          Top = 8
-          Width = 243
-          Caption = 'Explore Only Accounts With Keys In Wallet'
-          Checked = True
-          OnChange = chkExploreMyAccountsChange
-          State = cbChecked
-          TabOrder = 1
+        object sbSelectedAccountsAddAll: TSpeedButton
+          Left = 2
+          Height = 31
+          Top = 37
+          Width = 33
+          Caption = '>>'
+          OnClick = sbSelectedAccountsAddAllClick
         end
         end
-        object cbAccounts: TComboBox
-          Left = 8
-          Height = 23
-          Top = 40
-          Width = 336
-          ItemHeight = 15
-          ItemIndex = 0
-          Items.Strings = (
-            'Show All'
-            'Show non-zero balances'
-            'Get my first account!'
-          )
-          OnChange = cbAccountsChange
-          Style = csDropDownList
-          TabOrder = 2
-          Text = 'Show All'
+        object sbSelectedAccountsDel: TSpeedButton
+          Left = 2
+          Height = 31
+          Top = 74
+          Width = 33
+          Caption = '<'
+          OnClick = sbSelectedAccountsDelClick
         end
         end
-        object btnChangeKeyName: TBitBtn
-          Left = 352
-          Height = 30
-          Top = 36
-          Width = 116
-          Caption = 'Change Key Name'
-          OnClick = btnChangeKeyNameClick
-          TabOrder = 3
+        object sbSelectedAccountsDelAll: TSpeedButton
+          Left = 2
+          Height = 31
+          Top = 111
+          Width = 33
+          Caption = '<<'
+          OnClick = sbSelectedAccountsDelAllClick
         end
         end
       end
       end
-    end
-    object PairSplitterSide2: TPairSplitterSide
-      Cursor = crArrow
-      Left = 505
-      Height = 459
-      Top = 0
-      Width = 421
-      ClientWidth = 421
-      ClientHeight = 459
-      object gpRecentOps: TGroupBox
-        Left = 8
-        Height = 440
-        Top = 8
-        Width = 411
-        Anchors = [akTop, akLeft, akRight, akBottom]
-        Caption = 'Recent Operations'
-        ClientHeight = 420
-        ClientWidth = 407
-        TabOrder = 0
-        object paOperations: TPanel
-          Left = 8
-          Height = 400
-          Top = 16
-          Width = 395
-          Anchors = [akTop, akLeft, akRight, akBottom]
-          BorderSpacing.Around = 3
-          BevelOuter = bvNone
-          Caption = 'OPERATIONS PANEL'
-          ParentColor = False
-          TabOrder = 0
-        end
+      object bbSelectedAccountsOperation: TBitBtn
+        Left = 372
+        Height = 61
+        Top = 31
+        Width = 75
+        Anchors = [akTop, akRight]
+        Caption = 'Operations'
+        Glyph.Data = {
+          F6060000424DF606000000000000360000002800000018000000180000000100
+          180000000000C0060000120B0000120B00000000000000000000FF00FFFF00FF
+          FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00
+          FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
+          00FFFF00FFFF00FF019ACF019ACF019ACF019ACFFF00FFFF00FFFF00FFFF00FF
+          FF00FFFF00FFFF00FFFF00FFFF00FFFF00FF0C8518FF00FFFF00FFFF00FFFF00
+          FFFF00FFFF00FFFF00FFFF00FF0D9FD18BD4EE6BD3F845C0ED28B0E0019ACF01
+          9ACF019ACF019ACFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF0C85180C8518
+          FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF069CD076C8E5A9E9FE6DD8
+          FF75DBFF77DCFF77DBFF63D1F930B3E3029BD0019ACF019ACF019ACF019ACFFF
+          00FF0C85181399220C8518FF00FFFF00FFFF00FFFF00FFFF00FFFF00FF019ACF
+          34AFD9BCE9F86ED8FF6FD8FE70D8FE70D8FE71D8FF0C85180C85180C85180C85
+          180C85180C85180C85180C85181DAC31139A220C8518FF00FFFF00FFFF00FFFF
+          00FFFF00FF019ACF1FA9D68FD3EB97E4FF6FD9FE71D9FE71D9FE71D9FE0C8518
+          57E38851DD7E4AD77443D0693BC95E34C1522BBA4725B33C1EAE33149B230C85
+          18FF00FFFF00FFFF00FFFF00FF019ACF31B1DC49B7DEBDEEFB71DDFE77DEFE77
+          DEFE77DEFE0C85185EE89059E48953DE804CD87645D16C3DCA6035C2542DBB49
+          26B53F1FAF35149B250C8518FF00FFFF00FFFF00FF019ACF52C2E71DA7D5ADE2
+          F38FE8FF7CE2FE7CE3FE7CE3FE0C851861EB955FE9925AE58B54DF824DD97846
+          D26D3ECB6237C4562FBD4C27B64021B037159B250C8518FF00FFFF00FF019ACF
+          60CAEF1FA8D85EC1E1C2E6ED8ACEE08FCFE18ECFE10C851861EB9561EB955FEA
+          935CE58D56E0844FDB7A48D47040CD6538C65931BF4D1DA3320C8518FF00FFFF
+          00FFFF00FF019ACF65CFF53EB7E52CA9D4C5EFF8ACF3FEA5F2FFA5F2FF0C8518
+          61EB9561EB9561EB9561EB945CE68E57E18650DC7C49D57242CE6727AD410C85
+          18FF00FFFF00FFFF00FFFF00FF019ACF69D1F855C4F32A9CC673CBE7D6FEFDB1
+          FBFDB2FBFD0C85180C85180C85180C85180C85180C85180C85180C851852DD7F
+          32B6500C851898FAFF019ACFFF00FFFF00FFFF00FF019ACF77D5FC5CC8FB748E
+          A224A8D5B9E7F3D5F5F9D5F6F9D6F6FADCFAFBCDFDFCB9FCFCAFFAFCB0FAFCB1
+          FAFC0C85183ABE5C0C85189FFCFFA4FFFF43C1E2019ACFFF00FFFF00FF019ACF
+          8BDBFF5FCDFFB7898973C3DD18A2D218A2D216A2D215A1D21AA4D391D7EBEBFE
+          FDDBFDFCC5FBFBC2FBFB0C85180C851883E4F3B6FDFFBAFFFFB5FCFD019ACFFF
+          00FFFF00FF019ACF99E2FF67D3FFB88989FEF5ECFDF3EBF0EFEAE5EBE8D6E5E6
+          A4D2E025A6D34DB9DDE5F8FBF5FDFCEBFCFB0C8518C4FBFF9CE4F2DAFEFFD9FE
+          FFE3FFFFADE9F5019ACFFF00FF019ACF9FE9FF70DCFFB88989FEF3E9FFF2E6FE
+          F3E9FEF3E9FEF3E9FEF3E9D4E4E439ADD422A5D49DD8ECF1F9FBEEEFEFE9FDFF
+          CEEEF7F8FFFFF7FFFFFEFFFFE9F9FD019ACFFF00FF019ACFA7EFFF76E5FFB889
+          89FFF2E5FFF0E2FFF2E5FFF2E5FFF2E5FFF2E5FFF2E5EAEBE38EC9DA44B0D501
+          9ACF019ACF019ACF019ACF019ACF019ACF019ACF019ACF019ACFFF00FF019ACF
+          ABF6FF7EEDFFB88989FFF0E2FFEFDFFFF0E2FFF0E2FFF0E2FFF0E2FFF0E2FEEE
+          E0FBECDEFAEBDEF6E6D9B8898993F7FF019ACFFF00FFFF00FFFF00FFFF00FFFF
+          00FFFF00FF019ACFC7FFFF82F5FFB88989FFEEDFFFECDBFFEEDFFFEEDFFFEEDF
+          FFEEDFF9E8D9DECCC1D9CABDCFBDB4C8B3ACB88989B5FFFF019ACFFF00FFFF00
+          FFFF00FFFF00FFFF00FFFF00FF019ACFA4E0F0A0FDFFB88989FFECDBFFEBD8FF
+          ECDBFFECDBFFECDBFFECDBF5E2D2C4ABA7C2A8A5BBA39FC2AFA9B88989019ACF
+          FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF019ACFECFFFFB889
+          89FFEBD8FFEAD5FFEBD8FFEBD8FFEBD8FFEBD8FFEBD8D9C8C5FEFEFDFEF6EFDE
+          C9C0B88989FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+          FF00FF019ACFB88989FFE9D5FFE8D3FFE9D5FFE9D5FFE9D5FFE9D5FFE9D5C6AD
+          A9FEF8F2E8D4CACD9999FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF
+          00FFFF00FFFF00FFFF00FFFF00FFB88989FFE7D1FFE7D0FFE7D1FFE7D1FFE7D1
+          FFE7D1E7CEBFD3BFB9E8D5CCCD9999FF00FFFF00FFFF00FFFF00FFFF00FFFF00
+          FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFB88989FFE6CFFFE6CFFF
+          E6CFFFE6CFFFE6CFFFE6CFD5BBB2E0CCC5CD9999FF00FFFF00FFFF00FFFF00FF
+          FF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFB889
+          89B88989B88989B88989B88989B88989B88989B88989B88989FF00FFFF00FFFF
+          00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FFFF00FF
+        }
+        Layout = blGlyphTop
+        OnClick = bbSelectedAccountsOperationClick
+        TabOrder = 4
       end
       end
     end
     end
   end
   end
-  object mnuAccountsPopup: TPopupMenu
-    left = 768
-    top = 64
-    object miSendPASC: TMenuItem
-      Caption = 'Send PASC'
-      OnClick = miSendPASCClick
-    end
-    object miChangeKey: TMenuItem
-      Caption = 'Change Key'
-      OnClick = miChangeKeyClick
-    end
-    object miAccountsMarket: TMenuItem
-      Caption = 'Account Market'
-      object miEnlistAccountsForSale: TMenuItem
-        Caption = 'Enlist Account(s) For Sale'
-        OnClick = miEnlistAccountsForSaleClick
+  object meAccountExplorerMenu: TMainMenu
+    left = 240
+    top = 16
+    object miTools: TMenuItem
+      Caption = 'Tools'
+      object miNewOperation: TMenuItem
+        Caption = 'New Operation'
+        OnClick = miNewOperationClick
       end
       end
-      object miDelistAccountsFromSale: TMenuItem
-        Caption = 'Delist Account(s) From Sale'
-        OnClick = miDelistAccountsFromSaleClick
+      object miDecodePayload: TMenuItem
+        Caption = 'Decode Payload'
+        OnClick = miDecodePayloadClick
+      end
+      object N1: TMenuItem
+        Caption = '-'
+      end
+      object miFindAccount: TMenuItem
+        Caption = 'Find account'
+        ShortCut = 16454
+      end
+      object miAccountInformation: TMenuItem
+        Caption = 'Account Information'
+        ShortCut = 112
+        OnClick = MiAccountInformationClick
+      end
+      object N2: TMenuItem
+        Caption = '-'
+      end
+      object miAddAccountToSelected: TMenuItem
+        Caption = 'Add account to selected'
+        ShortCut = 117
+        OnClick = miAddAccountToSelectedClick
+      end
+      object miRemoveAccountFromSelected: TMenuItem
+        Caption = 'Remove account from selected'
+        ShortCut = 118
+        OnClick = miRemoveAccountFromSelectedClick
+      end
+      object N3: TMenuItem
+        Caption = '-'
+      end
+      object miFindPreviousAccountWithHighBalance: TMenuItem
+        Caption = 'Find previous account with high balance'
+        ShortCut = 16498
+        OnClick = miFindPreviousAccountWithHighBalanceClick
+      end
+      object miFindNextAccountWithHighBalance: TMenuItem
+        Caption = 'Find next account with high balance'
+        ShortCut = 114
+        OnClick = miFindNextAccountWithHighBalanceClick
       end
       end
     end
     end
-    object miSep1: TMenuItem
-      Caption = '-'
-    end
-    object miAccountInfo: TMenuItem
-      Caption = 'Account Info'
-      OnClick = miAccountInfoClick
-    end
-  end
-  object mnuOperationsPopup: TPopupMenu
-    left = 896
-    top = 64
-    object miCopyOphash: TMenuItem
-      Caption = 'Copy OPHASH'
-      OnClick = miCopyOphashClick
-    end
-    object miSep2: TMenuItem
-      Caption = '-'
-    end
-    object miOperationInfo: TMenuItem
-      Caption = 'Operation Info'
-      OnClick = miOperationInfoClick
-    end
-  end
-  object mnuFirstAccountPopup: TPopupMenu
-    left = 1024
-    top = 64
   end
   end
 end
 end

+ 581 - 746
src/gui/UFRMAccountExplorer.pas

@@ -2,885 +2,720 @@ unit UFRMAccountExplorer;
 
 
 {$mode delphi}
 {$mode delphi}
 
 
-{$modeswitch nestedprocvars}
+{ Copyright (c) 2018 by Herman Schoenfeld
+
+  Distributed under the MIT software license, see the accompanying file LICENSE
+  or visit http://www.opensource.org/licenses/mit-license.php.
+
+  Acknowledgements:
+  - Albert Molina: portions of code copied from https://github.com/PascalCoin/PascalCoin/blob/master/Units/Forms/UFRMWallet.pas
+}
 
 
 interface
 interface
 
 
+{$I ..\config.inc}
+
 uses
 uses
-  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, Menus,
-  ExtCtrls, PairSplitter, Buttons, UVisualGrid, UCommon.UI, Generics.Collections,
-  UAccounts, UDataSources, UNode, UCoreObjects, UCoreUtils, UWIZSendPASC, UWIZChangeKey, UWIZEnlistAccountForSale;
+  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ComCtrls,
+  ExtCtrls, StdCtrls, Buttons, Grids, Menus, UCommon.UI,
+  UGridUtils, UNode, UAccounts, UBlockChain;
 
 
 type
 type
 
 
   { TFRMAccountExplorer }
   { TFRMAccountExplorer }
 
 
-  TFRMAccountExplorerAccountsMode = (wamMyAccounts, wamAllAccounts);
-  TFRMAccountExplorerOperationsMode = (womSelectedAccounts, womAllAccounts);
-  TFRMAccountExplorerOperationsHistory = (woh7Days, woh30Days, wohFullHistory);
-
   TFRMAccountExplorer = class(TApplicationForm)
   TFRMAccountExplorer = class(TApplicationForm)
-    btnChangeKeyName: TBitBtn;
-    cbAccounts: TComboBox;
-    chkExploreMyAccounts: TCheckBox;
-    gpAccounts: TGroupBox;
-    gpRecentOps: TGroupBox;
-    GroupBox1: TGroupBox;
-    Label1: TLabel;
-    Label2: TLabel;
-    lblTotalPASA: TLabel;
-    lblTotalPASC: TLabel;
-    miCopyOphash: TMenuItem;
-    miOperationInfo: TMenuItem;
-    miSendPASC: TMenuItem;
-    miChangeKey: TMenuItem;
-    miAccountsMarket: TMenuItem;
-    miEnlistAccountsForSale: TMenuItem;
-    miDelistAccountsFromSale: TMenuItem;
-    miAccountInfo: TMenuItem;
-    miSep1: TMenuItem;
-    miSep2: TMenuItem;
-    PairSplitter1: TPairSplitter;
-    PairSplitterSide1: TPairSplitterSide;
-    PairSplitterSide2: TPairSplitterSide;
-    paAccounts: TPanel;
-    paOperations: TPanel;
-    mnuAccountsPopup: TPopupMenu;
-    mnuOperationsPopup: TPopupMenu;
-    mnuFirstAccountPopup: TPopupMenu;
-    procedure btnChangeKeyNameClick(Sender: TObject);
-    procedure cbAccountsChange(Sender: TObject);
-    procedure chkExploreMyAccountsChange(Sender: TObject);
-    procedure cmbDurationChange(Sender: TObject);
+    bbAccountsRefresh: TBitBtn;
+    bbAccountsRefresh1: TBitBtn;
+    bbAccountsRefresh2: TBitBtn;
+    bbChangeKeyName: TBitBtn;
+    bbChangeKeyName1: TBitBtn;
+    bbChangeKeyName2: TBitBtn;
+    bbSelectedAccountsOperation: TBitBtn;
+    bbSelectedAccountsOperation1: TBitBtn;
+    bbSelectedAccountsOperation2: TBitBtn;
+    cbExploreMyAccounts: TCheckBox;
+    cbExploreMyAccounts1: TCheckBox;
+    cbExploreMyAccounts2: TCheckBox;
+    cbFilterAccounts: TCheckBox;
+    cbFilterAccounts1: TCheckBox;
+    cbFilterAccounts2: TCheckBox;
+    cbMyPrivateKeys: TComboBox;
+    cbMyPrivateKeys1: TComboBox;
+    cbMyPrivateKeys2: TComboBox;
+    dgAccountOperations: TDrawGrid;
+    dgAccountOperations1: TDrawGrid;
+    dgAccountOperations2: TDrawGrid;
+    dgAccounts: TDrawGrid;
+    dgAccounts1: TDrawGrid;
+    dgAccounts2: TDrawGrid;
+    dgSelectedAccounts: TDrawGrid;
+    dgSelectedAccounts1: TDrawGrid;
+    dgSelectedAccounts2: TDrawGrid;
+    ebFilterAccountByBalanceMax: TEdit;
+    ebFilterAccountByBalanceMax1: TEdit;
+    ebFilterAccountByBalanceMax2: TEdit;
+    ebFilterAccountByBalanceMin: TEdit;
+    ebFilterAccountByBalanceMin1: TEdit;
+    ebFilterAccountByBalanceMin2: TEdit;
+    ebFindAccountNumber: TEdit;
+    ebFindAccountNumber1: TEdit;
+    ebFindAccountNumber2: TEdit;
+    Label15: TLabel;
+    Label16: TLabel;
+    Label17: TLabel;
+    Label18: TLabel;
+    Label19: TLabel;
+    Label20: TLabel;
+    Label21: TLabel;
+    Label22: TLabel;
+    Label23: TLabel;
+    Label24: TLabel;
+    Label25: TLabel;
+    Label26: TLabel;
+    Label27: TLabel;
+    Label28: TLabel;
+    Label29: TLabel;
+    Label30: TLabel;
+    Label31: TLabel;
+    Label32: TLabel;
+    lblAccountsBalance: TLabel;
+    lblAccountsBalance1: TLabel;
+    lblAccountsBalance2: TLabel;
+    lblAccountsCount: TLabel;
+    lblAccountsCount1: TLabel;
+    lblAccountsCount2: TLabel;
+    lblSelectedAccountsBalance: TLabel;
+    lblSelectedAccountsBalance1: TLabel;
+    lblSelectedAccountsBalance2: TLabel;
+    lblSelectedAccountsCount: TLabel;
+    lblSelectedAccountsCount1: TLabel;
+    lblSelectedAccountsCount2: TLabel;
+    meAccountExplorerMenu : TMainMenu;
+    miDecodePayload: TMenuItem;
+    miAccountInformation: TMenuItem;
+    miAddAccountToSelected: TMenuItem;
+    miFindAccount: TMenuItem;
+    miFindNextAccountWithHighBalance: TMenuItem;
+    miFindPreviousAccountWithHighBalance: TMenuItem;
+    miNewOperation: TMenuItem;
+    miRemoveAccountFromSelected: TMenuItem;
+    miTools: TMenuItem;
+    N1: TMenuItem;
+    N2: TMenuItem;
+    N3: TMenuItem;
+    pcAccountsOptions: TPageControl;
+    pcAccountsOptions1: TPageControl;
+    pcAccountsOptions2: TPageControl;
+    pnlAccounts: TPanel;
+    pnlAccounts1: TPanel;
+    pnlAccounts2: TPanel;
+    pnlAccountsInfo: TPanel;
+    pnlAccountsInfo1: TPanel;
+    pnlAccountsInfo2: TPanel;
+    pnlMyAccountsTop: TPanel;
+    pnlMyAccountsTop1: TPanel;
+    pnlMyAccountsTop2: TPanel;
+    pnlSelectedAccountsBottom: TPanel;
+    pnlSelectedAccountsBottom1: TPanel;
+    pnlSelectedAccountsBottom2: TPanel;
+    pnlSelectedAccountsLeft: TPanel;
+    pnlSelectedAccountsLeft1: TPanel;
+    pnlSelectedAccountsLeft2: TPanel;
+    pnlSelectedAccountsTop: TPanel;
+    pnlSelectedAccountsTop1: TPanel;
+    pnlSelectedAccountsTop2: TPanel;
+    sbSearchAccount: TSpeedButton;
+    sbSearchAccount1: TSpeedButton;
+    sbSearchAccount2: TSpeedButton;
+    sbSelectedAccountsAdd: TSpeedButton;
+    sbSelectedAccountsAdd1: TSpeedButton;
+    sbSelectedAccountsAdd2: TSpeedButton;
+    sbSelectedAccountsAddAll: TSpeedButton;
+    sbSelectedAccountsAddAll1: TSpeedButton;
+    sbSelectedAccountsAddAll2: TSpeedButton;
+    sbSelectedAccountsDel: TSpeedButton;
+    sbSelectedAccountsDel1: TSpeedButton;
+    sbSelectedAccountsDel2: TSpeedButton;
+    sbSelectedAccountsDelAll: TSpeedButton;
+    sbSelectedAccountsDelAll1: TSpeedButton;
+    sbSelectedAccountsDelAll2: TSpeedButton;
+    Splitter1: TSplitter;
+    Splitter2: TSplitter;
+    Splitter3: TSplitter;
+    tsAccountOperations: TTabSheet;
+    tsAccountOperations1: TTabSheet;
+    tsAccountOperations2: TTabSheet;
+    tsMultiSelectAccounts: TTabSheet;
+    tsMultiSelectAccounts1: TTabSheet;
+    tsMultiSelectAccounts2: TTabSheet;
+    tsMyAccounts: TTabSheet;
+    tsMyAccounts1: TTabSheet;
+    tsMyAccounts2: TTabSheet;
+    procedure bbAccountsRefreshClick(Sender: TObject);
+    procedure bbChangeKeyNameClick(Sender: TObject);
+    procedure bbSelectedAccountsOperationClick(Sender: TObject);
+    procedure cbExploreMyAccountsChange(Sender: TObject);
+    procedure cbFilterAccountsChange(Sender: TObject);
+    procedure cbMyPrivateKeysChange(Sender: TObject);
+    procedure dgAccountOperationsClick(Sender: TObject);
+    procedure dgAccountsClick(Sender: TObject);
+    procedure ebFilterAccountByBalanceMinExit(Sender: TObject);
+    procedure ebFilterAccountByBalanceMinKeyPress(Sender: TObject; var Key: char);
+    procedure ebFindAccountNumberChange(Sender: TObject);
+    procedure ebFindAccountNumberExit(Sender: TObject);
     procedure FormCreate(Sender: TObject);
     procedure FormCreate(Sender: TObject);
     procedure FormDestroy(Sender: TObject);
     procedure FormDestroy(Sender: TObject);
-    procedure miAccountInfoClick(Sender: TObject);
-    procedure miChangeKeyClick(Sender: TObject);
-    procedure miCopyOphashClick(Sender: TObject);
-    procedure miOperationInfoClick(Sender: TObject);
-    procedure miSendPASCClick(Sender: TObject);
-    procedure miEnlistAccountsForSaleClick(Sender: TObject);
-    procedure miDelistAccountsFromSaleClick(Sender: TObject);
+    procedure miAccountInformationClick(Sender: TObject);
+    procedure miAddAccountToSelectedClick(Sender: TObject);
+    procedure miDecodePayloadClick(Sender: TObject);
+    procedure miFindNextAccountWithHighBalanceClick(Sender: TObject);
+    procedure miFindPreviousAccountWithHighBalanceClick(Sender: TObject);
+    procedure miNewOperationClick(Sender: TObject);
+    procedure miRemoveAccountFromSelectedClick(Sender: TObject);
+    procedure sbSearchAccountClick(Sender: TObject);
+    function DoUpdateAccountsFilter: Boolean;
+    procedure sbSelectedAccountsAddAllClick(Sender: TObject);
+    procedure sbSelectedAccountsAddClick(Sender: TObject);
+    procedure sbSelectedAccountsDelAllClick(Sender: TObject);
+    procedure sbSelectedAccountsDelClick(Sender: TObject);
+    procedure RefreshAccountsGrid(RefreshData : Boolean);
+    procedure RefreshMyKeysCombo;
+    procedure OnAccountsSelectedGridUpdated(Sender: TObject);
   private
   private
-    FNodeNotifyEvents: TNodeNotifyEvents;
-    FAccountsMode: TFRMAccountExplorerAccountsMode;
-    FOperationsMode: TFRMAccountExplorerOperationsMode;
-    FOperationsHistory: TFRMAccountExplorerOperationsHistory;
-    FAccountsGrid: TVisualGrid;
-    FOperationsGrid: TVisualGrid;
-    FAllAccountsDataSource: TAccountsDataSource;
-    FAccountsDataSource: TMyAccountsDataSource;
-    FOperationsDataSource: TAccountsOperationsDataSource;
-    procedure SetAccountsMode(AMode: TFRMAccountExplorerAccountsMode);
-    procedure SetOperationsMode(AMode: TFRMAccountExplorerOperationsMode);
-    procedure SetOperationsHistory(AHistory: TFRMAccountExplorerOperationsHistory);
-    procedure RefreshMyAccountsCombo;
-    procedure RefreshTotals;
-    procedure RefreshAccountsGrid;
-    procedure RefreshOperationsGrid;
-    function GetAccounts(const AccountNumbers: TArray<cardinal>): TArray<TAccount>;
-  protected
-    procedure ActivateFirstTime; override;
+    { private declarations }
+    FAccountsGrid : TAccountsGrid;
+    FAccountOperationsGrid : TOperationsGrid;
+    FAccountsSelectedGrid : TAccountsGrid;
+    FOrderedAccountsKeyList : TOrderedAccountKeysList;
+    FMinAccountBalance : Int64;
+    FMaxAccountBalance : Int64;
     procedure OnPrivateKeysChanged(Sender: TObject);
     procedure OnPrivateKeysChanged(Sender: TObject);
-    procedure OnUserAccountsChanged(Sender: TObject);
-    procedure OnNodeBlocksChanged(Sender: TObject);
-    procedure OnNodeNewOperation(Sender: TObject);
-    procedure OnAccountsSelected(Sender: TObject; constref ASelection: TVisualGridSelection);
-    procedure OnOperationSelected(Sender: TObject; constref ASelection: TVisualGridSelection);
-    procedure OnPrepareAccountPopupMenu(Sender: TObject; constref ASelection: TVisualGridSelection; out APopupMenu: TPopupMenu);
-    procedure OnPrepareOperationsPopupMenu(Sender: TObject; constref ASelection: TVisualGridSelection; out APopupMenu: TPopupMenu);
   public
   public
-    property AccountsMode: TFRMAccountExplorerAccountsMode read FAccountsMode write SetAccountsMode;
-    property OperationsMode: TFRMAccountExplorerOperationsMode read FOperationsMode write SetOperationsMode;
-    property OperationsHistory: TFRMAccountExplorerOperationsHistory read FOperationsHistory write SetOperationsHistory;
+    { public declarations }
+    procedure OnSelectedAccountChanged;
+    procedure Refresh;
   end;
   end;
 
 
 implementation
 implementation
 
 
-uses
-  UUserInterface, UCellRenderers, UBlockChain, UWallet, UCrypto,
-  UCommon, UMemory, Generics.Defaults, UCommon.Data, UCommon.Collections;
-
 {$R *.lfm}
 {$R *.lfm}
 
 
+uses UFRMAccountSelect, UConst, USettings, UFRMOperation,
+     UWallet, UCrypto, UFRMMemoText, UUserInterface, UCommon;
+
 { TFRMAccountExplorer }
 { TFRMAccountExplorer }
 
 
+{%region Form life-cycle}
+
 procedure TFRMAccountExplorer.FormCreate(Sender: TObject);
 procedure TFRMAccountExplorer.FormCreate(Sender: TObject);
-var
-  cmbDuration: TComboBox;
-begin
-  // event registrations
-  FNodeNotifyEvents := TNodeNotifyEvents.Create(self);
-  FNodeNotifyEvents.WatchKeys := TWallet.Keys.AccountsKeyList;
-  FNodeNotifyEvents.OnKeyActivity := OnUserAccountsChanged;
-  FNodeNotifyEvents.OnBlocksChanged := OnNodeBlocksChanged;
-  FNodeNotifyEvents.OnOperationsChanged := OnNodeNewOperation;
+begin
+  FMinAccountBalance := 0;
+  FMaxAccountBalance := CT_MaxWalletAmount;
+  FOrderedAccountsKeyList := Nil;
+  FAccountsGrid := TAccountsGrid.Create(Self);
+  FAccountsGrid.DrawGrid := dgAccounts;
+  FAccountsGrid.Node := TUserInterface.Node;
+  FAccountsGrid.AllowMultiSelect := True;
+  FAccountsSelectedGrid := TAccountsGrid.Create(Self);
+  FAccountsSelectedGrid.DrawGrid :=dgSelectedAccounts;
+  FAccountsSelectedGrid.Node := TUserInterface.Node;
+  FAccountsSelectedGrid.OnUpdated := OnAccountsSelectedGridUpdated;
+  FAccountOperationsGrid := TOperationsGrid.Create(Self);
+  FAccountOperationsGrid.DrawGrid := dgAccountOperations;
+  FAccountOperationsGrid.Node := TUserInterface.Node;
+  FAccountOperationsGrid.MustShowAlwaysAnAccount := true;
+  pcAccountsOptions.ActivePage := tsAccountOperations;
+
+  // Get account list from SafeBox
+  FOrderedAccountsKeyList := TOrderedAccountKeysList.Create(TUserInterface.Node.Bank.SafeBox,false);
+
+  // Subscribe to wallet events
   TWallet.Keys.OnChanged.Add(OnPrivateKeysChanged);
   TWallet.Keys.OnChanged.Add(OnPrivateKeysChanged);
-
-  // fields
-  FAllAccountsDataSource := TAccountsDataSource.Create(Self);
-  FAllAccountsDataSource.IncludePending := True;
-  FAccountsDataSource := TMyAccountsDataSource.Create(Self);
-  FOperationsDataSource := TAccountsOperationsDataSource.Create(Self);
-  FOperationsDataSource.Accounts := nil;
-  FOperationsHistory := woh7Days;
-  FOperationsMode := womAllAccounts;
-  FAccountsMode := wamAllAccounts;
-
-  // grids
-  FAccountsGrid := TVisualGrid.Create(Self);
-  FAccountsGrid.SortMode := smMultiColumn;
-  FAccountsGrid.FetchDataInThread := False;
-  FAccountsGrid.AutoPageSize := True;
-  FAccountsGrid.DeselectionType := dtDefault;
-  FAccountsGrid.SelectionType := stMultiRow;
-  FAccountsGrid.Options := [vgoColAutoFill, vgoColSizing, vgoSortDirectionAllowNone, vgoAutoHidePaging, vgoAutoHideSearchPanel];
-  with FAccountsGrid.AddColumn('Account') do
-  begin
-    Binding := 'AccountNumber';
-    SortBinding := 'AccountNumber';
-    DisplayBinding := 'Account';
-    Width := 100;
-    HeaderFontStyles := [fsBold];
-    DataFontStyles := [fsBold];
-    Filters := SORTABLE_NUMERIC_FILTER;
-  end;
-  with FAccountsGrid.AddColumn('Name') do
-  begin
-    Width := 100;
-    HeaderAlignment := taCenter;
-    Filters := SORTABLE_TEXT_FILTER;
-  end;
-  with FAccountsGrid.AddColumn('Balance') do
-  begin
-    Binding := 'BalanceDecimal';
-    SortBinding := 'Balance';
-    DisplayBinding := 'Balance';
-    Width := 100;
-    HeaderAlignment := taRightJustify;
-    DataAlignment := taRightJustify;
-    Renderer := TCellRenderers.PASC;
-    Filters := SORTABLE_NUMERIC_FILTER;
-  end;
-  with FAccountsGrid.AddColumn('N Op.') do
-  begin
-    Binding := 'NumberOfOperations';
-    Width := 50;
-    HeaderAlignment := taRightJustify;
-    DataAlignment := taRightJustify;
-    Filters := SORTABLE_NUMERIC_FILTER;
-  end;
-  with FAccountsGrid.AddColumn('Type') do
-  begin
-    Binding := 'Type';
-    Width := 50;
-    HeaderAlignment := taRightJustify;
-    DataAlignment := taRightJustify;
-    Filters := SORTABLE_NUMERIC_FILTER;
-  end;
-  with FAccountsGrid.AddColumn('Price') do
-  begin
-    Binding := 'Price';
-    Width := 100;
-    HeaderAlignment := taRightJustify;
-    DataAlignment := taRightJustify;
-    Renderer := TCellRenderers.PASC_CheckPendingBalance;
-    Filters := SORTABLE_NUMERIC_FILTER;
-  end;
-
-  FAccountsGrid.OnSelection := OnAccountsSelected;
-  FAccountsGrid.OnPreparePopupMenu := OnPrepareAccountPopupMenu;
-
-  FOperationsGrid := TVisualGrid.Create(Self);
-  FOperationsGrid.SortMode := smMultiColumn;
-  FOperationsGrid.FetchDataInThread := True;
-  FOperationsGrid.AutoPageSize := True;
-  FOperationsGrid.DeselectionType := dtDefault;
-  FOperationsGrid.SelectionType := stRow;
-  FOperationsGrid.Options := [vgoColAutoFill, vgoColSizing, vgoSortDirectionAllowNone, vgoAutoHidePaging, vgoAutoHideSearchPanel];
-  with FOperationsGrid.AddColumn('Time') do
-  begin
-    SortBinding := 'UnixTime';
-    DisplayBinding := 'UnixTime';
-    Renderer := TCellRenderers.OperationTime;
-    Width := 130;
-    Filters := SORTABLE_NUMERIC_FILTER;
-  end;
-  with FOperationsGrid.AddColumn('Block') do
-  begin
-    Binding := 'BlockLocation';
-    SortBinding := 'BlockLocationSortable';
-    AutoWidth := True;
-    Filters := SORTABLE_TEXT_FILTER;
-  end;
-  with FOperationsGrid.AddColumn('Account') do
-  begin
-    Binding := 'AccountNumber';
-    DisplayBinding := 'Account';
-    Width := 100;
-    Filters := SORTABLE_NUMERIC_FILTER;
-  end;
-  with FOperationsGrid.AddColumn('Type') do
-  begin
-    Sanitizer := TCellRenderers.OperationTypeSanitizer;
-    Width := 150;
-    Filters := SORTABLE_NUMERIC_FILTER;
-  end;
-  with FOperationsGrid.AddColumn('Amount') do
-  begin
-    Binding := 'AmountDecimal';
-    SortBinding := 'Amount';
-    DisplayBinding := 'Amount';
-    Width := 150;
-    HeaderAlignment := taRightJustify;
-    Renderer := TCellRenderers.PASC_CheckPendingBalance;
-    Filters := SORTABLE_NUMERIC_FILTER;
-  end;
-  with FOperationsGrid.AddColumn('Fee') do
-  begin
-    Binding := 'FeeDecimal';
-    SortBinding := 'Fee';
-    DisplayBinding := 'Fee';
-    AutoWidth := True;
-    HeaderAlignment := taRightJustify;
-    DataAlignment := taRightJustify;
-    Renderer := TCellRenderers.PASC_CheckPendingBalance;
-    Filters := SORTABLE_NUMERIC_FILTER;
-  end;
-  with FOperationsGrid.AddColumn('Balance') do
-  begin
-    Binding := 'BalanceDecimal';
-    SortBinding := 'Balance';
-    DisplayBinding := 'Balance';
-    Width := 100;
-    HeaderAlignment := taRightJustify;
-    DataAlignment := taRightJustify;
-    Renderer := TCellRenderers.PASC_CheckPendingBalance;
-    Filters := SORTABLE_NUMERIC_FILTER;
-  end;
-  with FOperationsGrid.AddColumn('Payload') do
-  begin
-    AutoWidth := True;
-    Renderer := TCellRenderers.Payload;
-    Filters := SORTABLE_TEXT_FILTER;
-  end;
-  with FOperationsGrid.AddColumn('OPHASH') do
-  begin
-    Width := 80;
-    Renderer := TCellRenderers.OPHASH;
-    Filters := SORTABLE_TEXT_FILTER;
-  end;
-  with FOperationsGrid.AddColumn('Description') do
-  begin
-    StretchedToFill := True;
-    Filters := SORTABLE_TEXT_FILTER;
-  end;
-  FOperationsGrid.OnSelection := OnOperationSelected;
-  FOperationsGrid.OnPreparePopupMenu := OnPrepareOperationsPopupMenu;
-  FOperationsGrid.Caption.Alignment := taCenter;
-  //FOperationsGrid.Caption.Text := 'All Account Operations';
-  FOperationsGrid.Caption.Text := '';
-  FOperationsGrid.Caption.Visible := True;
-
-  // key combo
-  RefreshMyAccountsCombo;
-
-  // duration combo
-  cmbDuration := TComboBox.Create(FOperationsGrid);
-  cmbDuration.ReadOnly := True;
-  cmbDuration.Items.BeginUpdate;
-  try
-    cmbDuration.AddItem('7 Days', TObject(woh7Days));
-    cmbDuration.AddItem('30 Days', TObject(woh30Days));
-    cmbDuration.AddItem('Maximum', TObject(wohFullHistory));
-  finally
-    cmbDuration.Items.EndUpdate;
-    cmbDuration.ItemIndex := 0;
-  end;
-  cmbDuration.OnChange := cmbDurationChange;
-  FOperationsGrid.WidgetControl := cmbDuration;
-
-  // Add datasources to grid
-  chkExploreMyAccountsChange(Self);
-  FOperationsGrid.DataSource := FOperationsDataSource;
-
-  // Add grid to panels
-  paAccounts.AddControlDockCenter(FAccountsGrid);
-  paOperations.AddControlDockCenter(FOperationsGrid);
+  Refresh;
 end;
 end;
 
 
 procedure TFRMAccountExplorer.FormDestroy(Sender: TObject);
 procedure TFRMAccountExplorer.FormDestroy(Sender: TObject);
 begin
 begin
-  TWallet.Keys.OnChanged.Add(OnPrivateKeysChanged);
+  // Unsubscribe from wallet events
+  TWallet.Keys.OnChanged.Remove(OnPrivateKeysChanged);
+
+  // Nullify fields
+  FAccountOperationsGrid.Node := Nil;
+  FAccountsGrid.Node := Nil;
+  FAccountsSelectedGrid.Node := Nil;
+  FAccountsGrid.Node := Nil;
+
+  // Note: grids themselves are collected with Self (TComponent dependency)
 end;
 end;
 
 
-procedure TFRMAccountExplorer.ActivateFirstTime;
+{%endregion}
+
+{%region Form methods}
+
+procedure TFRMAccountExplorer.Refresh;
 begin
 begin
-  RefreshTotals;
+  RefreshAccountsGrid(true);
+  RefreshMyKeysCombo;
 end;
 end;
 
 
-procedure TFRMAccountExplorer.RefreshTotals;
+{%endregion}
 
 
-  function GetAllAccountsKey(): TArray<TAccountKey>;
-  var
-    LAccount: TAccount;
-    LAccounts: TList<TAccount>;
-    LAccountsKey: TList<TAccountKey>;
-    LGC: TDisposables;
-  begin
-    LAccounts := LGC.AddObject(TList<TAccount>.Create) as TList<TAccount>;
-    FAllAccountsDataSource.FetchAll(LAccounts);
-    LAccountsKey := LGC.AddObject(TList<TAccountKey>.Create) as TList<TAccountKey>;
-    for LAccount in LAccounts do
-      LAccountsKey.Add(LAccount.accountInfo.accountKey);
-    Result := LAccountsKey.ToArray;
-  end;
+{%region For auxillary methods}
 
 
-var
-  LBalance: TBalanceSummary;
-  LIdx: integer;
-begin
-  case FAccountsMode of
-    wamMyAccounts:
-    begin
-      if (cbAccounts.ItemIndex = 0) then
-        LBalance := TWallet.Keys.AccountsKeyList.GetBalance(True)
-      else
-      begin
-        LIdx := TWallet.Keys.IndexOfAccountKey(TBox<TAccountKey>(
-          cbAccounts.Items.Objects[cbAccounts.ItemIndex]).Value);
-
-        if (LIdx < 0) or (LIdx >= TWallet.Keys.Count) then
-        begin
-          ShowMessage('You Must Select a Valid Key');
-          Exit;
+procedure TFRMAccountExplorer.RefreshAccountsGrid(RefreshData : Boolean);
+Var accl : TOrderedCardinalList;
+  l : TOrderedCardinalList;
+  i,j,k : Integer;
+  c  : Cardinal;
+  applyfilter : Boolean;
+  acc : TAccount;
+begin
+  If Not Assigned(FOrderedAccountsKeyList) Then exit;
+  if Not RefreshData then begin
+    dgAccounts.Invalidate;
+    exit;
+  end;
+  applyfilter := (cbFilterAccounts.Checked) and ((FMinAccountBalance>0) Or (FMaxAccountBalance<CT_MaxWalletAmount));
+  FAccountsGrid.ShowAllAccounts := (Not cbExploreMyAccounts.Checked) And (not applyfilter);
+  if Not FAccountsGrid.ShowAllAccounts then begin
+    accl := FAccountsGrid.LockAccountsList;
+    Try
+      accl.Clear;
+      if cbExploreMyAccounts.Checked then begin
+        if cbMyPrivateKeys.ItemIndex<0 then exit;
+        if cbMyPrivateKeys.ItemIndex=0 then begin
+          // All keys in the wallet
+          for i := 0 to TWallet.Keys.Count - 1 do begin
+            j := FOrderedAccountsKeyList.IndexOfAccountKey(TWallet.Keys[i].AccountKey);
+            if (j>=0) then begin
+              l := FOrderedAccountsKeyList.AccountKeyList[j];
+              for k := 0 to l.Count - 1 do begin
+                if applyfilter then begin
+                  acc := TUserInterface.Node.Bank.SafeBox.Account(l.Get(k));
+                  if (acc.balance>=FMinAccountBalance) And (acc.balance<=FMaxAccountBalance) then accl.Add(acc.account);
+                end else accl.Add(l.Get(k));
+              end;
+            end;
+          end;
+        end else begin
+          i := PtrInt(cbMyPrivateKeys.Items.Objects[cbMyPrivateKeys.ItemIndex]);
+          if (i>=0) And (i<TWallet.Keys.Count) then begin
+            j := FOrderedAccountsKeyList.IndexOfAccountKey(TWallet.Keys[i].AccountKey);
+            if (j>=0) then begin
+              l := FOrderedAccountsKeyList.AccountKeyList[j];
+              for k := 0 to l.Count - 1 do begin
+                if applyfilter then begin
+                  acc := TUserInterface.Node.Bank.SafeBox.Account(l.Get(k));
+                  if (acc.balance>=FMinAccountBalance) And (acc.balance<=FMaxAccountBalance) then accl.Add(acc.account);
+                end else accl.Add(l.Get(k));
+              end;
+            end;
+          end;
+        end;
+      end else begin
+        // There is a filter... check every account...
+        c := 0;
+        while (c<TUserInterface.Node.Bank.SafeBox.AccountsCount) do begin
+          acc := TUserInterface.Node.Bank.SafeBox.Account(c);
+          if (acc.balance>=FMinAccountBalance) And (acc.balance<=FMaxAccountBalance) then accl.Add(acc.account);
+          inc(c);
         end;
         end;
-        LBalance := TWallet.Keys.Key[LIdx].AccountKey.GetBalance(True);
       end;
       end;
+    Finally
+      FAccountsGrid.UnlockAccountsList;
+    End;
+    lblAccountsCount.Caption := inttostr(accl.Count);
+  end else begin
+    lblAccountsCount.Caption := inttostr(TUserInterface.Node.Bank.AccountsCount);
+  end;
+  bbChangeKeyName.Enabled := cbExploreMyAccounts.Checked;
+  // Show Totals:
+  lblAccountsBalance.Caption := TAccountComp.FormatMoney(FAccountsGrid.AccountsBalance);
+  OnSelectedAccountChanged;
+end;
 
 
-      lblTotalPASC.Caption := TAccountComp.FormatMoney(LBalance.TotalPASC);
-      lblTotalPASA.Caption := Format('%d', [LBalance.TotalPASA]);
-    end;
-    wamAllAccounts:
-    begin
-      LBalance := TNode.Node.Bank.SafeBox.GetBalance(GetAllAccountsKey, True);
-      lblTotalPASC.Caption := TAccountComp.FormatMoney(LBalance.TotalPASC);
-      lblTotalPASA.Caption := Format('%d', [LBalance.TotalPASA]);
+procedure TFRMAccountExplorer.RefreshMyKeysCombo;
+Var i,last_i : Integer;
+  wk : TWalletKey;
+  s : AnsiString;
+begin
+  cbMyPrivateKeys.Enabled := cbExploreMyAccounts.Checked;
+  if (cbMyPrivateKeys.ItemIndex>=0) then last_i := PtrInt(cbMyPrivateKeys.Items.Objects[cbMyPrivateKeys.ItemIndex])
+  else last_i := -1;
+  cbMyPrivateKeys.items.BeginUpdate;
+  Try
+    cbMyPrivateKeys.Items.Clear;
+    For i:=0 to TWallet.Keys.Count-1 do begin
+      wk := TWallet.Keys.Key[i];
+      if assigned(FOrderedAccountsKeyList) then begin
+        FOrderedAccountsKeyList.AddAccountKey(wk.AccountKey);
+      end;
+      if (wk.Name='') then begin
+        s := 'Sha256='+TCrypto.ToHexaString( TCrypto.DoSha256( TAccountComp.AccountKey2RawString(wk.AccountKey) ) );
+      end else begin
+        s := wk.Name;
+      end;
+      if Not Assigned(wk.PrivateKey) then s := s + '(*)';
+      cbMyPrivateKeys.Items.AddObject(s,TObject(i));
     end;
     end;
-  end;
+    cbMyPrivateKeys.Sorted := true;
+    cbMyPrivateKeys.Sorted := false;
+    cbMyPrivateKeys.Items.InsertObject(0,'(All my private keys)',TObject(-1));
+  Finally
+    cbMyPrivateKeys.Items.EndUpdate;
+  End;
+  last_i := cbMyPrivateKeys.Items.IndexOfObject(TObject(last_i));
+  if last_i<0 then last_i := 0;
+  if cbMyPrivateKeys.Items.Count>last_i then cbMyPrivateKeys.ItemIndex := last_i
+  else if cbMyPrivateKeys.Items.Count>=0 then cbMyPrivateKeys.ItemIndex := 0;
 end;
 end;
 
 
-procedure TFRMAccountExplorer.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;
+function TFRMAccountExplorer.DoUpdateAccountsFilter: Boolean;
+Var bmin,bmax:Int64;
+  doupd : Boolean;
+begin
+  If Not TAccountComp.TxtToMoney(ebFilterAccountByBalanceMin.Text,bmin) then bmin := 0;
+  If not TAccountComp.TxtToMoney(ebFilterAccountByBalanceMax.Text,bmax) then bmax := CT_MaxWalletAmount;
+  if (bmax<bmin) or (bmax=0) then bmax := CT_MaxWalletAmount;
+  if bmin>bmax then bmin := 0;
+  doupd := (bmin<>FMinAccountBalance) Or (bmax<>FMaxAccountBalance);
+  FMinAccountBalance := bmin;
+  FMaxAccountBalance := bmax;
+  if bmin>0 then
+    ebFilterAccountByBalanceMin.Text:=TAccountComp.FormatMoney(bmin)
+  else ebFilterAccountByBalanceMin.Text := '';
+  if bmax<CT_MaxWalletAmount then
+    ebFilterAccountByBalanceMax.Text := TAccountComp.FormatMoney(bmax)
+  else ebFilterAccountByBalanceMax.Text := '';
+  if cbFilterAccounts.Checked then begin
+    ebFilterAccountByBalanceMin.ParentFont := true;
+    ebFilterAccountByBalanceMax.ParentFont := true;
+  end else begin
+    ebFilterAccountByBalanceMin.font.Color := clDkGray;
+    ebFilterAccountByBalanceMax.font.Color := clDkGray;
+  end;
+  if doupd then RefreshAccountsGrid(true);
+  Result := doupd;
+  //end;
+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
-        str := 'Sha256=' + TCrypto.ToHexaString(TCrypto.DoSha256(
-          TAccountComp.AccountKey2RawString(key.AccountKey)))
-      else
-        str := key.Name;
-      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);
-  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
-    for i := 1 to cbAccounts.Items.Count - 2 do
-      if TAccountKeyEqualityComparer.AreEqual(TBox<TAccountKey>(cbAccounts.Items.Objects[i]).Value, last_key) then
-      begin
-        cbAccounts.ItemIndex := i;
-        exit;
-      end;
+{%endregion}
+
+{%region Event Handlers: Blockchain }
+
+procedure TFRMAccountExplorer.OnPrivateKeysChanged(Sender: TObject);
+begin
+  Refresh;
 end;
 end;
 
 
-procedure TFRMAccountExplorer.RefreshAccountsGrid;
+procedure TFRMAccountExplorer.OnSelectedAccountChanged;
+Var accn : Int64;
+begin
+  accn := FAccountsGrid.AccountNumber(dgAccounts.Row);
+  FAccountOperationsGrid.AccountNumber := accn;
+end;
 
 
-  function GetAccountKey(constref AAccount: TAccount): TAccountKey;
-  begin
-    Result := AAccount.accountInfo.accountKey;
-  end;
+{%endregion}
 
 
-  function GetAllAccounts(): TArray<TAccount>;
-  var
-    LAccounts: TList<TAccount>;
-    LGC: TDisposables;
-  begin
-    LAccounts := LGC.AddObject(TList<TAccount>.Create) as TList<TAccount>;
-    FAllAccountsDataSource.FetchAll(LAccounts);
-    Result := LAccounts.ToArray;
-  end;
+{%region Event Handlers: Combo Boxes}
 
 
-var
-  index: integer;
-  sel: TBox<TAccountKey>;
-begin
-
-  case Self.AccountsMode of
-    wamMyAccounts:
-    begin
-      cbAccounts.Enabled := True;
-      btnChangeKeyName.Enabled := True;
-      if cbAccounts.ItemIndex = cbAccounts.Items.Count - 1 then
-        exit; // not a key
-      index := cbAccounts.ItemIndex;
-      if index = 0 then
-      begin
-        gpAccounts.Caption := 'My Accounts';
-        FAccountsDataSource.FilterKeys := TWallet.Keys.AccountsKeyList.ToArray;
-      end
-      else
-      begin
-        sel := TBox<TAccountKey>(cbAccounts.Items.Objects[cbAccounts.ItemIndex]);
-        gpAccounts.Caption := Format('%s Accounts', [TWallet.Keys[TWallet.Keys.IndexOfAccountKey(sel.Value)].Name]);
-        FAccountsDataSource.FilterKeys := TArray<TAccountKey>.Create(sel.Value);
-      end;
-    end;
+procedure TFRMAccountExplorer.cbExploreMyAccountsChange(Sender: TObject);
+begin
+    RefreshAccountsGrid(true);
+    RefreshMyKeysCombo;
+    OnSelectedAccountChanged;
+end;
 
 
-    wamAllAccounts:
-    begin
-      cbAccounts.Enabled := False;
-      btnChangeKeyName.Enabled := False;
-      gpAccounts.Caption := 'All Accounts';
-      FAllAccountsDataSource.FilterKeys := TListTool<TAccount, TAccountKey>.Transform(GetAllAccounts, GetAccountKey);
-    end;
-  end;
-  RefreshTotals;
-  FAccountsGrid.RefreshGrid;
+procedure TFRMAccountExplorer.cbFilterAccountsChange(Sender: TObject);
+begin
+  If not DoUpdateAccountsFilter then RefreshAccountsGrid(true);
 end;
 end;
 
 
-procedure TFRMAccountExplorer.RefreshOperationsGrid;
+procedure TFRMAccountExplorer.cbMyPrivateKeysChange(Sender: TObject);
+begin
+  RefreshAccountsGrid(true);
+end;
 
 
-  function GetAccNo(constref AAccount: TAccount): cardinal; overload;
-  begin
-    Result := AAccount.account;
-  end;
+{%endregion}
 
 
-  function GetAccNo(constref ARow: variant): cardinal; overload;
-  begin
-    Result := ARow.__KEY;
-  end;
+{%region Event Handlers: Buttons}
 
 
-  function GetAllAccounts(): TArray<TAccount>;
-  var
-    LAccounts: TList<TAccount>;
-    LGC: TDisposables;
-  begin
-    LAccounts := LGC.AddObject(TList<TAccount>.Create) as TList<TAccount>;
-    FAllAccountsDataSource.FetchAll(LAccounts);
-    Result := LAccounts.ToArray;
+procedure TFRMAccountExplorer.bbChangeKeyNameClick(Sender: TObject);
+var i : Integer;
+  nameString : String;
+begin
+  if (cbMyPrivateKeys.ItemIndex<0) then  exit;
+  i := PtrInt(cbMyPrivateKeys.Items.Objects[cbMyPrivateKeys.ItemIndex]);
+  if (i<0) Or (i>=TWallet.Keys.Count) then raise Exception.Create('Must select a Key');
+  name := TWallet.Keys.Key[i].Name;
+  if InputQuery('Change Key name','Input new name',nameString) then begin
+    TWallet.Keys.SetName(i,name);
   end;
   end;
+end;
 
 
+procedure TFRMAccountExplorer.bbAccountsRefreshClick(Sender: TObject);
 begin
 begin
-  case FOperationsMode of
-    womAllAccounts:
-    begin
-      FOperationsGrid.Caption.Text := '';
-      FOperationsDataSource.Accounts := nil;
-    end;
-    womSelectedAccounts:
-    begin
-      FOperationsGrid.Caption.Text := 'Selected Account Operations';
-      FOperationsDataSource.Accounts := TListTool<variant, cardinal>.Transform(FAccountsGrid.SelectedRows, GetAccNo);
-    end
-    else
-      raise ENotSupportedException.Create(Format('AMode %d not supported', [integer(FOperationsMode)]));
-  end;
-  FOperationsGrid.RefreshGrid;
+  RefreshAccountsGrid(true);
 end;
 end;
 
 
-function TFRMAccountExplorer.GetAccounts(const AccountNumbers: TArray<cardinal>): TArray<TAccount>;
-var
-  acc: TAccount;
-  safeBox: TPCSafeBox;
-  keys: TOrderedAccountKeysList;
-  LContainer: Generics.Collections.TList<TAccount>;
-  i: integer;
+procedure TFRMAccountExplorer.sbSelectedAccountsAddAllClick(Sender: TObject);
+Var lsource,ltarget : TOrderedCardinalList;
+  i : Integer;
 begin
 begin
-  LContainer := Generics.Collections.TList<TAccount>.Create();
-  keys := TWallet.keys.AccountsKeyList;
-  safeBox := TUserInterface.Node.Bank.safeBox;
-  safeBox.StartThreadSafe;
-  try
-    LContainer.Clear;
-    try
-      // load selected user accounts
-      for i := Low(AccountNumbers) to High(AccountNumbers) do
-      begin
-        acc := safeBox.Account(AccountNumbers[i]);
-        if keys.IndexOfAccountKey(acc.accountInfo.accountKey) >= 0 then
-          LContainer.Add(acc);
+  lsource := FAccountsGrid.LockAccountsList;
+  Try
+    ltarget := FAccountsSelectedGrid.LockAccountsList;
+    Try
+      for i := 0 to lsource.Count-1 do begin
+        if TWallet.Keys.IndexOfAccountKey(TUserInterface.Node.Bank.SafeBox.Account(lsource.Get(i)).accountInfo.accountKey)<0 then raise Exception.Create(Format('You cannot operate with account %d because private key not found in your wallet',[lsource.Get(i)]));
+        ltarget.Add(lsource.Get(i));
       end;
       end;
-    finally
-      safeBox.EndThreadSave;
-    end;
-    Result := LContainer.ToArray;
-  finally
-    LContainer.Free;
-  end;
+    Finally
+      FAccountsSelectedGrid.UnlockAccountsList;
+    End;
+  Finally
+    FAccountsGrid.UnlockAccountsList;
+  End;
 end;
 end;
 
 
-procedure TFRMAccountExplorer.SetAccountsMode(AMode: TFRMAccountExplorerAccountsMode);
+procedure TFRMAccountExplorer.sbSelectedAccountsAddClick(Sender: TObject);
+Var l, selected : TOrderedCardinalList;
+  an : Int64;
+  i : Integer;
 begin
 begin
-  if FAccountsMode = AMode then
-    exit;
-
-  FUILock.Acquire;
-  try
-    FAccountsMode := AMode;
-    paAccounts.RemoveAllControls(False);
-    // reset account combo
-    cbAccounts.OnChange := nil; // disable event
-    cbAccounts.ItemIndex := 0;
-    cbAccounts.OnChange := cbAccountsChange; // re-enable event
-    // ensure on accounts panel
-    if FAccountsGrid.Parent <> paAccounts then
-    begin
-      paAccounts.RemoveAllControls(False);
-      paAccounts.AddControlDockCenter(FAccountsGrid);
+  an := FAccountsGrid.AccountNumber(dgAccounts.Row);
+  if (an<0) then raise Exception.Create('No account selected');
+  if TWallet.Keys.IndexOfAccountKey(TUserInterface.Node.Bank.SafeBox.Account(an).accountInfo.accountkey)<0 then
+    raise Exception.Create(Format('You cannot add %s account because private key not found in your wallet.'#10+#10+'You''re not the owner!',
+      [TAccountComp.AccountNumberToAccountTxtNumber(an)]));
+  // Add
+  l := FAccountsSelectedGrid.LockAccountsList;
+  selected := TOrderedCardinalList.Create;
+  Try
+    FAccountsGrid.SelectedAccounts(selected);
+    for i := 0 to selected.Count-1 do begin
+      l.Add(selected.Get(i));
     end;
     end;
-    case AMode of
-
-      wamMyAccounts:
-        FAccountsGrid.DataSource := FAccountsDataSource;
+  Finally
+    selected.Free;
+    FAccountsSelectedGrid.UnlockAccountsList;
+  End;
+end;
 
 
-      wamAllAccounts:
-        FAccountsGrid.DataSource := FAllAccountsDataSource;
-    end;
-    // Refresh grid
-    FAccountsGrid.ClearSelection();
-    RefreshAccountsGrid;
+procedure TFRMAccountExplorer.sbSelectedAccountsDelAllClick(Sender: TObject);
+Var l : TOrderedCardinalList;
+begin
+  l := FAccountsSelectedGrid.LockAccountsList;
+  try
+    l.Clear;
   finally
   finally
-    FUILock.Release;
+    FAccountsSelectedGrid.UnlockAccountsList;
   end;
   end;
 end;
 end;
 
 
-procedure TFRMAccountExplorer.SetOperationsMode(AMode: TFRMAccountExplorerOperationsMode);
+procedure TFRMAccountExplorer.sbSelectedAccountsDelClick(Sender: TObject);
+Var an : Int64;
+  l : TOrderedCardinalList;
 begin
 begin
-  if FOperationsMode = AMode then
-    exit;
-  FUILock.Acquire;
+  l := FAccountsSelectedGrid.LockAccountsList;
   try
   try
-    FOperationsMode := AMode;
-    RefreshOperationsGrid;
+    an := FAccountsSelectedGrid.AccountNumber(dgSelectedAccounts.Row);
+    if an>=0 then l.Remove(an);
   finally
   finally
-    FUILock.Release;
+    FAccountsSelectedGrid.UnlockAccountsList;
   end;
   end;
 end;
 end;
 
 
-procedure TFRMAccountExplorer.SetOperationsHistory(AHistory: TFRMAccountExplorerOperationsHistory);
+procedure TFRMAccountExplorer.bbSelectedAccountsOperationClick(Sender: TObject);
+var l : TOrderedCardinalList;
 begin
 begin
-  FOperationsHistory := AHistory;
-  case FOperationsHistory of
-    woh7Days: FOperationsDataSource.TimeSpan := TTimeSpan.FromDays(7);
-    woh30Days: FOperationsDataSource.TimeSpan := TTimeSpan.FromDays(30);
-    wohFullHistory: FOperationsDataSource.TimeSpan := TTimeSpan.FromDays(10 * 365);
+  TUserInterface.CheckNodeIsReady;
+  if FAccountsSelectedGrid.AccountsCount<=0 then raise Exception.Create('Must select at least 1 account');
+  try
+    l := FAccountsSelectedGrid.LockAccountsList;
+    TUserInterface.ShowNewOperationDialog(Self, l, TSettings.DefaultFee);
+  finally
+    FAccountsSelectedGrid.UnlockAccountsList;
   end;
   end;
-  FOperationsGrid.RefreshGrid;
 end;
 end;
 
 
-procedure TFRMAccountExplorer.OnPrivateKeysChanged(Sender: TObject);
+procedure TFRMAccountExplorer.sbSearchAccountClick(Sender: TObject);
+Var F : TFRMAccountSelect;
 begin
 begin
-  RefreshMyAccountsCombo;
+  F := TFRMAccountSelect.Create(Self);
+  try
+    F.Node := TUserInterface.Node;
+    F.WalletKeys := TWallet.Keys;
+    F.ShowModal;
+  finally
+    F.Free;
+  end;
 end;
 end;
 
 
-procedure TFRMAccountExplorer.OnUserAccountsChanged(Sender: TObject);
-begin
-  //  if NOT TUserInterface.Node.HasBestKnownBlockchainTip then
-  //    exit; // node syncing
+{%endregion}
 
 
-  RefreshTotals;
-  FAccountsGrid.RefreshGrid;
-  FOperationsGrid.RefreshGrid;
-end;
+{%region Event Handlers: Text Boxes}
 
 
-procedure TFRMAccountExplorer.OnNodeBlocksChanged(Sender: TObject);
+procedure TFRMAccountExplorer.ebFilterAccountByBalanceMinExit(Sender: TObject);
 begin
 begin
-  // TODO: play block sound chime
-  RefreshTotals;
-  FAccountsGrid.RefreshGrid;
-  FOperationsGrid.RefreshGrid;
+  DoUpdateAccountsFilter;
 end;
 end;
 
 
-procedure TFRMAccountExplorer.OnNodeNewOperation(Sender: TObject);
+procedure TFRMAccountExplorer.ebFilterAccountByBalanceMinKeyPress(Sender: TObject; var Key: char);
 begin
 begin
-  // TODO: play operation sound tick
-  RefreshTotals;
-  FAccountsGrid.RefreshGrid;
-  FOperationsGrid.RefreshGrid;
+  if key=#13 then DoUpdateAccountsFilter;
 end;
 end;
 
 
-procedure TFRMAccountExplorer.OnAccountsSelected(Sender: TObject; constref ASelection: TVisualGridSelection);
+procedure TFRMAccountExplorer.ebFindAccountNumberChange(Sender: TObject);
+Var an : Cardinal =0;
 begin
 begin
-  if ASelection.Page >= 0 then
-  begin
-    if OperationsMode <> womSelectedAccounts then
-      OperationsMode := womSelectedAccounts
-    else
-      RefreshOperationsGrid; // already viewing selected accounts, add to visible set
-  end
-  else
-    OperationsMode := womAllAccounts;
-end;
-
-procedure TFRMAccountExplorer.OnOperationSelected(Sender: TObject; constref ASelection: TVisualGridSelection);
-var
-  row: longint;
-  v: variant;
-  ophash: ansistring;
-begin
-  if ASelection.Page < 0 then
-    exit;
-  row := ASelection.Row;
-  if (row >= 0) and (row < FOperationsGrid.RowCount) then
-  begin
-    v := FOperationsGrid.Rows[row];
-    ophash := FOperationsGrid.Rows[row].OPHASH;
-    if TPCOperation.IsValidOperationHash(ophash) then
-    begin
-      TUserInterface.ShowOperationInfoDialog(self, ophash);
-      FOperationsGrid.ClearSelection(True);
+  if Trim(ebFindAccountNumber.Text)='' then begin
+    ebFindAccountNumber.Color := clWindow;
+    ebFindAccountNumber.Font.Color := clDkGray;
+  end else if TAccountComp.AccountTxtNumberToAccountNumber(ebFindAccountNumber.Text,an) then begin
+    ebFindAccountNumber.Color := clWindow;
+    if FAccountsGrid.MoveRowToAccount(an) then begin
+      ebFindAccountNumber.Font.Color := clWindowText;
+    end else begin
+      ebFindAccountNumber.Font.Color := clRed;
     end;
     end;
+  end else begin
+    // Invalid value
+    ebFindAccountNumber.Color := clRed;
+    ebFindAccountNumber.Font.Color := clWindowText;
   end;
   end;
 end;
 end;
 
 
-procedure TFRMAccountExplorer.cbAccountsChange(Sender: TObject);
+procedure TFRMAccountExplorer.ebFindAccountNumberExit(Sender: TObject);
 begin
 begin
-  if cbAccounts.ItemIndex < 0 then
-    exit;
-  FAccountsGrid.ClearSelection();
-  RefreshAccountsGrid;
-  if FOperationsMode <> womAllAccounts then
-    RefreshOperationsGrid;
+  ebFindAccountNumber.Text := '';
 end;
 end;
 
 
-procedure TFRMAccountExplorer.btnChangeKeyNameClick(Sender: TObject);
-var
-  LIdx, LCurrentIndex: integer;
-  LNewName: string;
-begin
-  if (cbAccounts.ItemIndex <= 0) then
-  begin
-    ShowMessage('You Must Select a Valid Key');
-    Exit;
-  end;
-  LIdx := TWallet.Keys.IndexOfAccountKey(TBox<TAccountKey>(
-    cbAccounts.Items.Objects[cbAccounts.ItemIndex]).Value);
+{%endregion}
 
 
-  if (LIdx < 0) or (LIdx >= TWallet.Keys.Count) then
-  begin
-    ShowMessage('You Must Select a Valid Key');
-    Exit;
-  end;
+{%region Event Handlers: Data Grid}
 
 
-  LCurrentIndex := cbAccounts.ItemIndex;
-  if InputQuery('Change Key Name', 'Input New Name', LNewName) then
-  begin
-    TWallet.Keys.SetName(LIdx, LNewName);
-    cbAccounts.ItemIndex := LCurrentIndex;
-    cbAccountsChange(Self);
-  end;
+procedure TFRMAccountExplorer.dgAccountOperationsClick(Sender: TObject);
+begin
+  TUserInterface.ShowOperationInfoDialog(Self, FAccountOperationsGrid.SelectedOperation);
 end;
 end;
 
 
-procedure TFRMAccountExplorer.chkExploreMyAccountsChange(Sender: TObject);
+procedure TFRMAccountExplorer.dgAccountsClick(Sender: TObject);
 begin
 begin
-  if chkExploreMyAccounts.Checked then
-  begin
-    FAccountsMode := wamMyAccounts;
-    FAccountsGrid.DataSource := FAccountsDataSource;
-  end
-  else
-  begin
-    FAccountsMode := wamAllAccounts;
-    FAccountsGrid.DataSource := FAllAccountsDataSource;
-  end;
-  RefreshAccountsGrid;
+  OnSelectedAccountChanged;
 end;
 end;
 
 
-procedure TFRMAccountExplorer.cmbDurationChange(Sender: TObject);
-var
-  cmbDuration: TComboBox;
+procedure TFRMAccountExplorer.OnAccountsSelectedGridUpdated(Sender: TObject);
 begin
 begin
-  cmbDuration := Sender as TComboBox;
-  if not Assigned(cmbDuration) then
-    exit;
-
-  case cmbDuration.ItemIndex of
-    0: OperationsHistory := woh7Days;
-    1: OperationsHistory := woh30Days;
-    2: OperationsHistory := wohFullHistory;
-  end;
+  lblSelectedAccountsCount.Caption := Inttostr(FAccountsSelectedGrid.AccountsCount);
+  lblSelectedAccountsBalance.Caption := TAccountComp.FormatMoney( FAccountsSelectedGrid.AccountsBalance );
 end;
 end;
 
 
-procedure TFRMAccountExplorer.OnPrepareAccountPopupMenu(Sender: TObject; constref ASelection: TVisualGridSelection; out APopupMenu: TPopupMenu);
-var
-  accNo: cardinal;
-  account: TAccount;
-begin
-  miSep1.Visible := ASelection.RowCount = 1;
-  miAccountInfo.Visible := ASelection.RowCount = 1;
-  miSendPASC.Visible := IIF(FAccountsMode = wamMyAccounts, True, False);
-  miChangeKey.Visible := IIF(FAccountsMode = wamMyAccounts, True, False);
-  miAccountsMarket.Visible := IIF(FAccountsMode = wamMyAccounts, True, False);
-  miSendPASC.Caption := IIF(ASelection.RowCount = 1, 'Send PASC', 'Send All PASC');
-  miChangeKey.Caption := IIF(ASelection.RowCount = 1, 'Change Key', 'Change All Key');
-  miEnlistAccountsForSale.Caption := IIF(ASelection.RowCount = 1, 'Enlist Account For Sale', 'Enlist All Account For Sale');
-  miDelistAccountsFromSale.Caption := IIF(ASelection.RowCount = 1, 'Delist Account From Sale', 'Delist All Account From Sale');
-  if ASelection.RowCount = 1 then
-  begin
-    if not TAccountComp.AccountTxtNumberToAccountNumber(FAccountsGrid.Rows[ASelection.Row].Account, accNo) then
-      raise Exception.Create('Error Parsing Account Number From Grid');
-    account := TNode.Node.Operations.SafeBoxTransaction.Account(accNo);
-    miEnlistAccountsForSale.Visible := IIF(TAccountComp.IsAccountForSale(account.accountInfo), False, True);
-    miDelistAccountsFromSale.Visible := not miEnlistAccountsForSale.Visible;
-  end;
-  APopupMenu := mnuAccountsPopup;
-end;
+{%endregion}
 
 
-procedure TFRMAccountExplorer.miAccountInfoClick(Sender: TObject);
-begin
-  if FAccountsGrid.Selection.RowCount <> 1 then
-    exit;
-  TUserInterface.ShowAccountInfoDialog(Self, FAccountsGrid.SelectedRows[0].__KEY);
-end;
+{%region Events Handlers: Menu Items}
 
 
-procedure TFRMAccountExplorer.miSendPASCClick(Sender: TObject);
-var
-  Scoped: TDisposables;
-  wiz: TWIZSendPASCWizard;
-  model: TExecuteOperationsModel;
-  AccountNumbersWithoutChecksum: TArray<cardinal>;
+procedure TFRMAccountExplorer.miNewOperationClick(Sender: TObject);
+var targetAccounts : TOrderedCardinalList;
+begin
+  targetAccounts := TOrderedCardinalList.Create;
+  try
+    If FAccountsGrid.SelectedAccounts(targetAccounts) = 0
+      then raise Exception.Create('No row selected');
 
 
-  function GetAccNoWithoutChecksum(constref ARow: variant): cardinal;
-  begin
-    Result := ARow.__KEY;
+    TUserInterface.ShowNewOperationDialog(Self, targetAccounts, TSettings.DefaultFee);
+  finally
+     targetAccounts.Free;
   end;
   end;
+end;
 
 
+procedure TFRMAccountExplorer.miFindPreviousAccountWithHighBalanceClick(Sender: TObject);
+Var an  : Cardinal;
+  an64 : Int64;
+  start : TAccount;
 begin
 begin
-  wiz := Scoped.AddObject(TWIZSendPASCWizard.Create(nil)) as TWIZSendPASCWizard;
-  model := TExecuteOperationsModel.Create(wiz, omtSendPasc);
-  AccountNumbersWithoutChecksum := TListTool<variant, cardinal>.Transform(FAccountsGrid.SelectedRows, GetAccNoWithoutChecksum);
-  model.Account.SelectedAccounts := GetAccounts(AccountNumbersWithoutChecksum);
-  wiz.Start(model);
+    an64 := FAccountsGrid.AccountNumber(dgAccounts.Row);
+    if an64<0 then an := TUserInterface.Node.Bank.SafeBox.AccountsCount-1
+    else an := an64;
+    If an>= TUserInterface.Node.Bank.SafeBox.AccountsCount then exit;
+    start := TUserInterface.Node.Bank.SafeBox.Account(an);
+    while (an>0)  do begin
+      if TUserInterface.Node.Bank.SafeBox.Account(an).balance>start.balance then break
+      else dec(an);
+    end;
+    if (TUserInterface.Node.Bank.SafeBox.Account(an).balance>start.balance) then FAccountsGrid.MoveRowToAccount(an)
+    else raise Exception.Create('Not found any account lower than '+TAccountComp.AccountNumberToAccountTxtNumber(start.account)+' with balance higher than '+
+      TAccountComp.FormatMoney(start.balance));
 end;
 end;
 
 
-procedure TFRMAccountExplorer.miChangeKeyClick(Sender: TObject);
-var
-  Scoped: TDisposables;
-  wiz: TWIZChangeKeyWizard;
-  model: TExecuteOperationsModel;
-  AccountNumbersWithoutChecksum: TArray<cardinal>;
-
-  function GetAccNoWithoutChecksum(constref ARow: variant): cardinal;
-  begin
-    Result := ARow.__KEY;
-  end;
-
+procedure TFRMAccountExplorer.miFindNextAccountWithHighBalanceClick(Sender: TObject);
+Var an  : Cardinal;
+  an64 : Int64;
+  start : TAccount;
 begin
 begin
-  wiz := Scoped.AddObject(TWIZChangeKeyWizard.Create(nil)) as TWIZChangeKeyWizard;
-  model := TExecuteOperationsModel.Create(wiz, omtChangeKey);
-  AccountNumbersWithoutChecksum := TListTool<variant, cardinal>.Transform(FAccountsGrid.SelectedRows, GetAccNoWithoutChecksum);
-  model.Account.SelectedAccounts := GetAccounts(AccountNumbersWithoutChecksum);
-  wiz.Start(model);
+  an64 := FAccountsGrid.AccountNumber(dgAccounts.Row);
+  if an64<0 then an := 0
+  else an := an64;
+  If an>=TUserInterface.Node.Bank.SafeBox.AccountsCount then exit;
+  start := TUserInterface.Node.Bank.SafeBox.Account(an);
+  while (an<TUserInterface.Node.Bank.SafeBox.AccountsCount)  do begin
+    if TUserInterface.Node.Bank.SafeBox.Account(an).balance>start.balance then break
+    else inc(an);
+  end;
+  if (an<TUserInterface.Node.Bank.SafeBox.AccountsCount) then FAccountsGrid.MoveRowToAccount(an)
+  else raise Exception.Create('Not found any account higher than '+TAccountComp.AccountNumberToAccountTxtNumber(start.account)+' with balance higher than '+
+    TAccountComp.FormatMoney(start.balance));
 end;
 end;
 
 
-procedure TFRMAccountExplorer.miEnlistAccountsForSaleClick(Sender: TObject);
-var
-  Scoped: TDisposables;
-  wiz: TWIZEnlistAccountForSaleWizard;
-  model: TExecuteOperationsModel;
-  AccountNumbersWithoutChecksum: TArray<cardinal>;
+procedure TFRMAccountExplorer.miAccountInformationClick(Sender: TObject);
+Var F : TFRMMemoText;
+  accn : Int64 =-1;
+  acc : TAccount;
+  i : Integer;
+  opr : TOperationResume;
+begin
+  accn := -1;
+  opr := CT_TOperationResume_NUL;
+  accn := FAccountsGrid.AccountNumber(dgAccounts.Row);
+  if accn<0 then
+    raise Exception.Create('Select an account');
+
+  if accn >= TUserInterface.Node.Bank.AccountsCount then
+    raise Exception.Create('Account not found');
+
+  acc := TUserInterface.Node.Operations.SafeBoxTransaction.Account(accn);
 
 
-  function GetAccNoWithoutChecksum(constref ARow: variant): cardinal;
-  begin
-    Result := ARow.__KEY;
+  i := FAccountOperationsGrid.DrawGrid.Row;
+  if (i>0) and (i<=FAccountOperationsGrid.OperationsResume.Count) then begin
+    opr := FAccountOperationsGrid.OperationsResume.OperationResume[i-1];
   end;
   end;
 
 
-begin
-  wiz := Scoped.AddObject(TWIZEnlistAccountForSaleWizard.Create(nil)) as TWIZEnlistAccountForSaleWizard;
-  model := TExecuteOperationsModel.Create(wiz, omtEnlistAccountForSale);
-  AccountNumbersWithoutChecksum := TListTool<variant, cardinal>.Transform(FAccountsGrid.SelectedRows, GetAccNoWithoutChecksum);
-  model.Account.SelectedAccounts := GetAccounts(AccountNumbersWithoutChecksum);
-  wiz.Start(model);
+  If opr.valid then
+    TUserInterface.ShowAccountOperationInfoDialog(Self, acc, opr)
+  else
+    TUserInterface.ShowAccountInfoDialog(Self, acc);
 end;
 end;
 
 
-procedure TFRMAccountExplorer.miDelistAccountsFromSaleClick(Sender: TObject);
+procedure TFRMAccountExplorer.miAddAccountToSelectedClick(Sender: TObject);
 begin
 begin
-  raise ENotImplemented.Create('not yet implemented.');
+   // in memory for not exit program - Application.Exit - auto free mem not need control free manual for this send Self!
+  pcAccountsOptions.ActivePage := tsMultiSelectAccounts;
+  sbSelectedAccountsAddClick(Sender);
 end;
 end;
 
 
-procedure TFRMAccountExplorer.OnPrepareOperationsPopupMenu(Sender: TObject; constref ASelection: TVisualGridSelection; out APopupMenu: TPopupMenu);
+procedure TFRMAccountExplorer.miDecodePayloadClick(Sender: TObject);
 begin
 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;
+  TUserInterface.ShowOperationInfoDialog(Self, FAccountOperationsGrid.SelectedOperation.OperationHash);
 end;
 end;
 
 
-procedure TFRMAccountExplorer.miCopyOphashClick(Sender: TObject);
+procedure TFRMAccountExplorer.miRemoveAccountFromSelectedClick(Sender: TObject);
 begin
 begin
-  raise ENotImplemented.Create('Not Implemented');
+  Self.pcAccountsOptions.ActivePage := Self.tsMultiSelectAccounts;
+  Self.sbSelectedAccountsDelClick(Sender);
 end;
 end;
 
 
-procedure TFRMAccountExplorer.miOperationInfoClick(Sender: TObject);
-begin
-  if FOperationsGrid.Selection.RowCount = 0 then
-    exit;
-  TUserInterface.ShowOperationInfoDialog(Self, FOperationsGrid.SelectedRows[0].__KEY);
-end;
+{%endregion}
 
 
 end.
 end.
+

+ 35 - 49
src/gui/UFRMBlockExplorer.lfm

@@ -1,84 +1,70 @@
 object FRMBlockExplorer: TFRMBlockExplorer
 object FRMBlockExplorer: TFRMBlockExplorer
-  Left = 190
-  Height = 424
-  Top = 287
+  Left = 87
+  Height = 444
+  Top = 135
   Width = 864
   Width = 864
-  ActiveControl = ebBlockChainBlockStart
   Caption = 'Block Explorer'
   Caption = 'Block Explorer'
   ClientHeight = 424
   ClientHeight = 424
   ClientWidth = 864
   ClientWidth = 864
   Menu = BlockExplorerMenu
   Menu = BlockExplorerMenu
   OnCreate = FormCreate
   OnCreate = FormCreate
-  Position = poMainFormCenter
-  Visible = False
-  object Panel1: TPanel
+  OnDestroy = FormDestroy
+  Position = poOwnerFormCenter
+  LCLVersion = '1.6.4.0'
+  object Panel2: TPanel
     Left = 0
     Left = 0
-    Height = 56
+    Height = 41
     Top = 0
     Top = 0
     Width = 864
     Width = 864
     Align = alTop
     Align = alTop
     BevelOuter = bvNone
     BevelOuter = bvNone
-    ClientHeight = 56
+    ClientHeight = 41
     ClientWidth = 864
     ClientWidth = 864
     TabOrder = 0
     TabOrder = 0
-    object Label2: TLabel
-      Left = 16
+    object Label9: TLabel
+      Left = 11
       Height = 15
       Height = 15
       Top = 10
       Top = 10
       Width = 112
       Width = 112
       Caption = 'Filter by blocks range'
       Caption = 'Filter by blocks range'
       ParentColor = False
       ParentColor = False
     end
     end
+    object ebBlockChainBlockEnd: TEdit
+      Left = 185
+      Height = 23
+      Top = 7
+      Width = 57
+      OnExit = ebBlockChainBlockStartExit
+      OnKeyPress = ebBlockChainBlockStartKeyPress
+      TabOrder = 0
+    end
   end
   end
-  object ebBlockChainBlockStart: TEdit
-    Left = 16
-    Height = 23
-    Top = 32
-    Width = 57
-    OnExit = ebBlockChainBlockExit
-    OnKeyPress = ebBlockChainBlockStartKeyPress
+  object dgBlockChainExplorer: TDrawGrid
+    Left = 0
+    Height = 383
+    Top = 41
+    Width = 864
+    Align = alClient
+    ExtendedSelect = False
     TabOrder = 1
     TabOrder = 1
-    TextHint = 'From'
+    TitleFont.Color = clWindowText
+    TitleFont.Height = -11
+    TitleFont.Name = 'Tahoma'
   end
   end
-  object ebBlockChainBlockEnd: TEdit
-    Left = 104
+  object ebBlockChainBlockStart: TEdit
+    Left = 125
     Height = 23
     Height = 23
-    Top = 32
+    Top = 7
     Width = 57
     Width = 57
-    OnExit = ebBlockChainBlockExit
+    OnExit = ebBlockChainBlockStartExit
     OnKeyPress = ebBlockChainBlockStartKeyPress
     OnKeyPress = ebBlockChainBlockStartKeyPress
     TabOrder = 2
     TabOrder = 2
-    TextHint = 'To'
-  end
-  object grpBlockExplorer: TGroupBox
-    Left = 16
-    Height = 376
-    Top = 72
-    Width = 840
-    Anchors = [akTop, akLeft, akRight, akBottom]
-    Caption = 'All Blocks'
-    ClientHeight = 356
-    ClientWidth = 836
-    TabOrder = 3
-    object paGrid: TPanel
-      Left = 8
-      Height = 310
-      Top = 16
-      Width = 824
-      Anchors = [akTop, akLeft, akRight, akBottom]
-      BevelOuter = bvNone
-      Caption = 'Block Panel'
-      TabOrder = 0
-    end
   end
   end
   object BlockExplorerMenu: TMainMenu
   object BlockExplorerMenu: TMainMenu
     left = 560
     left = 560
+    top = 8
     object miTools: TMenuItem
     object miTools: TMenuItem
       Caption = 'Tools'
       Caption = 'Tools'
-      object miDecodePayload: TMenuItem
-        Caption = 'Decode Payload'
-        ShortCut = 113
-      end
     end
     end
   end
   end
 end
 end

+ 43 - 264
src/gui/UFRMBlockExplorer.pas

@@ -2,6 +2,8 @@ unit UFRMBlockExplorer;
 
 
 {$mode delphi}
 {$mode delphi}
 
 
+interface
+
 { Copyright (c) 2018 by Herman Schoenfeld
 { Copyright (c) 2018 by Herman Schoenfeld
 
 
   Distributed under the MIT software license, see the accompanying file LICENSE
   Distributed under the MIT software license, see the accompanying file LICENSE
@@ -12,303 +14,80 @@ unit UFRMBlockExplorer;
 }
 }
 
 
 
 
-interface
-
 {$I ..\config.inc}
 {$I ..\config.inc}
 
 
 uses
 uses
-  LCLIntf, LCLType, SysUtils, Controls, Forms, Dialogs, ExtCtrls, StdCtrls, Grids, Menus, Classes,
-  UCommon.UI, UConst, UDataSources, UNode, UVisualGrid, UCellRenderers, UCommon.Data, UCoreUtils;
+  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls,
+  StdCtrls, Grids, Menus, UCommon.UI, UGridUtils;
 
 
 type
 type
 
 
   { TFRMBlockExplorer }
   { TFRMBlockExplorer }
 
 
   TFRMBlockExplorer = class(TApplicationForm)
   TFRMBlockExplorer = class(TApplicationForm)
+    dgBlockChainExplorer: TDrawGrid;
     ebBlockChainBlockEnd: TEdit;
     ebBlockChainBlockEnd: TEdit;
     ebBlockChainBlockStart: TEdit;
     ebBlockChainBlockStart: TEdit;
-    grpBlockExplorer: TGroupBox;
-    Label2: TLabel;
+    Label9: TLabel;
     BlockExplorerMenu: TMainMenu;
     BlockExplorerMenu: TMainMenu;
-    miDecodePayload: TMenuItem;
     miTools: TMenuItem;
     miTools: TMenuItem;
-    Panel1: TPanel;
-    paGrid: TPanel;
-    procedure ebBlockChainBlockExit(Sender: TObject);
-    procedure ebBlockChainBlockStartKeyPress(Sender: TObject; var Key: char);
+    Panel2: TPanel;
+    procedure ebBlockChainBlockStartExit(Sender: TObject);
+    procedure ebBlockChainBlockStartKeyPress(Sender: TObject;
+      var Key: Char);
     procedure FormCreate(Sender: TObject);
     procedure FormCreate(Sender: TObject);
-
-  protected
-    procedure OnNodeNewAccount(Sender: TObject);
+    procedure FormDestroy(Sender:TObject);
   private
   private
-    FMaxBlocks: integer;
-    { private declarations }
-    FUpdating: boolean;
-    FBlockStart, FBlockEnd: int64;
-    FNodeNotifyEvents: TNodeNotifyEvents;
-    FBlockChainGrid: TVisualGrid;
-    FBlockChainDataSource: TBlockChainDataSource;
-
-    FHashRateAs: TShowHashRateAs;
-    FHashRateAverageBlocksCount: integer;
+    FUpdating : boolean;
+    FBlockChainGrid : TBlockChainGrid;
 
 
-    procedure SetMaxBlocks(AValue: integer);
-    procedure UpdateVisualGridUI();
-    procedure SetBlocks(AStart, AEnd: int64);
   public
   public
     { public declarations }
     { public declarations }
-    property MaxBlocks: integer read FMaxBlocks write SetMaxBlocks;
   end;
   end;
 
 
-implementation
-
-{$r *.lfm}
-
-uses UUserInterface, UMemory, UFRMPayloadDecoder, UBlockChain, UWallet, Generics.Collections;
-
-procedure TFRMBlockExplorer.FormCreate(Sender: TObject);
-begin
-
-  // event registrations
-  FNodeNotifyEvents := TNodeNotifyEvents.Create(self);
-  FNodeNotifyEvents.OnBlocksChanged := OnNodeNewAccount;
-
-  FUpdating := False;
-  FBlockStart := -1;
-  FBlockEnd := -1;
-  FMaxBlocks := 300;
-  FHashRateAverageBlocksCount := 50;
-  FHashRateAs:={$IFDEF PRODUCTION}hr_Giga{$ELSE}hr_Mega{$ENDIF};
-
-  UpdateVisualGridUI();
-
-end;
-
-procedure TFRMBlockExplorer.OnNodeNewAccount(Sender: TObject);
-begin
-  UpdateVisualGridUI(); //main
-end;
-
-procedure TFRMBlockExplorer.UpdateVisualGridUI();
 var
 var
-  LNode: TNode;
-  LStart, LEnd: int64;
-  LHashType: string;
-begin
-  LNode := FNodeNotifyEvents.Node;
-  if FBlockEnd < 0 then
-  begin
-    if LNode.Bank.BlocksCount > 0 then
-      LEnd := LNode.Bank.BlocksCount - 1
-    else
-      LEnd := 0;
-  end
-  else
-    LEnd := FBlockEnd;
-  if FBlockStart < 0 then
-  begin
-    if (LEnd > MaxBlocks) then
-      LStart := LEnd - MaxBlocks
-    else
-      LStart := 0;
-  end
-  else
-    LStart := FBlockStart;
-  if LStart < 0 then
-    LStart := 0;
-  if LEnd >= LNode.Bank.BlocksCount then
-    LEnd := LNode.Bank.BlocksCount;
-  // fields
-  FBlockChainDataSource := TBlockChainDataSource.Create(Self);
-
-  FBlockChainDataSource.HashRateAs := FHashRateAs;
-  FBlockChainDataSource.HashRateAverageBlocksCount := FHashRateAverageBlocksCount;
-
-  FBlockChainDataSource.StartBlock := LStart;
-  FBlockChainDataSource.EndBlock := LEnd;
-
-  FBlockChainGrid := TVisualGrid.Create(Self);
-  FBlockChainGrid.SortMode := smMultiColumn;
-  FBlockChainGrid.FetchDataInThread := True;
-  FBlockChainGrid.AutoPageSize := True;
-  FBlockChainGrid.DeselectionType := dtDefault;
-  FBlockChainGrid.SelectionType := stRow;
-  FBlockChainGrid.Options := [vgoColAutoFill, vgoColSizing, vgoSortDirectionAllowNone, vgoAutoHidePaging, vgoAutoHideSearchPanel];
+  FRMBlockExplorer: TFRMBlockExplorer = nil;
 
 
-  with FBlockChainGrid.AddColumn('Block') do
-  begin
-    AutoWidth := True;
-    Filters := SORTABLE_TEXT_FILTER;
-  end;
-  with FBlockChainGrid.AddColumn('Time') do
-  begin
-    SortBinding := 'UnixTime';
-    DisplayBinding := 'UnixTime';
-    Renderer := TCellRenderers.OperationTime;
-    Width := 130;
-    Filters := SORTABLE_NUMERIC_FILTER;
-  end;
-  with FBlockChainGrid.AddColumn('Ops') do
-  begin
-   // Sanitizer := TCellRenderers.OperationTypeSanitizer;
-    Width := 50;
-    Filters := SORTABLE_NUMERIC_FILTER;
-  end;
-  with FBlockChainGrid.AddColumn('Volume') do
-  begin
-    Width := 100;
-    HeaderAlignment := taRightJustify;
-    DataAlignment := taRightJustify;
-   // Renderer := TCellRenderers.PASC_CheckPendingBalance;
-    Filters := SORTABLE_NUMERIC_FILTER;
-  end;
-  with FBlockChainGrid.AddColumn('Reward') do
-  begin
-    Width := 100;
-    HeaderAlignment := taRightJustify;
-    DataAlignment := taRightJustify;
-    Renderer := TCellRenderers.PASC_CheckPendingBalance;
-    Filters := SORTABLE_NUMERIC_FILTER;
-  end;
-  with FBlockChainGrid.AddColumn('Fee') do
-  begin
-    Binding := 'FeeDecimal';
-    SortBinding := 'Fee';
-    DisplayBinding := 'Fee';
-    AutoWidth := True;
-    HeaderAlignment := taRightJustify;
-    DataAlignment := taRightJustify;
-    Renderer := TCellRenderers.PASC_CheckPendingBalance;
-    Filters := SORTABLE_NUMERIC_FILTER;
-  end;
-  with FBlockChainGrid.AddColumn('Target') do
-  begin
-    Width := 100;
-   // Renderer := TCellRenderers.Payload;
-    Filters := SORTABLE_TEXT_FILTER;
-  end;
-  case FBlockChainDataSource.HashRateAs of
-    hr_Kilo: LHashType := 'Kh/s';
-    hr_Mega: LHashType := 'Mh/s';
-    hr_Giga: LHashType := 'Gh/s';
-    hr_Tera: LHashType := 'Th/s';
-    else
-      LHashType := '?h/s';
-  end;
-
-  with FBlockChainGrid.AddColumn(LHashType) do
-  begin
-    Width := 100;
-   // Renderer := TCellRenderers.Payload;
-    Filters := SORTABLE_TEXT_FILTER;
-  end;
-
-  with FBlockChainGrid.AddColumn('Miner Payload') do
-  begin
-    Binding := 'MinerPayload';
-    Width := 200;
-    Renderer := TCellRenderers.Payload;
-    Filters := SORTABLE_TEXT_FILTER;
-  end;
-
-  with FBlockChainGrid.AddColumn('Proof Of Work') do
-  begin
-    Binding := 'POW';
-    Width := 200;
-   // Renderer := TCellRenderers.Payload;
-    Filters := SORTABLE_TEXT_FILTER;
-  end;
-
-  with FBlockChainGrid.AddColumn('SafeBox Hash') do
-  begin
-    Binding := 'SBH';
-    Width := 200;
-   // Renderer := TCellRenderers.Payload;
-    Filters := SORTABLE_TEXT_FILTER;
-  end;
-
-  with FBlockChainGrid.AddColumn('Protocol') do
-  begin
-    Width := 100;
-   // Renderer := TCellRenderers.Payload;
-    Filters := SORTABLE_TEXT_FILTER;
-  end;
-
-  with FBlockChainGrid.AddColumn('Deviation') do
-  begin
-    Width := 100;
-   // Renderer := TCellRenderers.Payload;
-    Filters := SORTABLE_TEXT_FILTER;
-  end;
-
-  with FBlockChainGrid.AddColumn('Time Average') do
-  begin
-    AutoWidth := True;
-    Binding := 'TimeAverage';
-   // Renderer := TCellRenderers.Payload;
-    Filters := SORTABLE_TEXT_FILTER;
-  end;
-
-  FBlockChainGrid.Caption.Alignment := taCenter;
-  FBlockChainGrid.Caption.Text := 'All Blocks';
-  FBlockChainGrid.Caption.Visible := True;
-
-  // Add datasources to grid
-  FBlockChainGrid.DataSource := FBlockChainDataSource;
-
-  // Add grid to panels
-  paGrid.AddControlDockCenter(FBlockChainGrid);
-end;
+implementation
+uses UFRMMainForm, UUserInterface;
 
 
-procedure TFRMBlockExplorer.SetMaxBlocks(AValue: integer);
+{$R *.lfm}
+procedure TFRMBlockExplorer.ebBlockChainBlockStartExit(Sender: TObject);
+var bstart,bend : Int64;
 begin
 begin
-  if FMaxBlocks = AValue then
-    Exit;
-  FMaxBlocks := AValue;
-  if (FMaxBlocks <= 0) or (FMaxBlocks > 500) then
-    FMaxBlocks := 300;
-  UpdateVisualGridUI();
+  If not FUpdating then
+  Try
+    FUpdating := True;
+    bstart := StrToInt64Def(ebBlockChainBlockStart.Text,-1);
+    bend := StrToInt64Def(ebBlockChainBlockEnd.Text,-1);
+    FBlockChainGrid.SetBlocks(bstart,bend);
+    if FBlockChainGrid.BlockStart>=0 then
+      ebBlockChainBlockStart.Text := Inttostr(FBlockChainGrid.BlockStart) else ebBlockChainBlockStart.Text := '';
+    if FBlockChainGrid.BlockEnd>=0 then
+      ebBlockChainBlockEnd.Text := Inttostr(FBlockChainGrid.BlockEnd) else ebBlockChainBlockEnd.Text := '';
+  Finally
+    FUpdating := false;
+  End;
 end;
 end;
 
 
-procedure TFRMBlockExplorer.SetBlocks(AStart, AEnd: int64);
+procedure TFRMBlockExplorer.ebBlockChainBlockStartKeyPress(Sender: TObject;
+  var Key: Char);
 begin
 begin
-  if (AStart = FBlockStart) and (AEnd = FBlockEnd) then
-    Exit;
-  FBlockStart := AStart;
-  FBlockEnd := AEnd;
-  if (FBlockEnd > 0) and (FBlockStart > FBlockEnd) then
-    FBlockStart := -1;
-  UpdateVisualGridUI();
+  if key=#13 then  ebBlockChainBlockStartExit(Nil);
 end;
 end;
 
 
-procedure TFRMBlockExplorer.ebBlockChainBlockExit(Sender: TObject);
-var
-  LStart, LEnd: int64;
+procedure TFRMBlockExplorer.FormCreate(Sender: TObject);
 begin
 begin
-  if not FUpdating then
-    try
-      FUpdating := True;// move to finally
-      LStart := StrToInt64Def(ebBlockChainBlockStart.Text, -1);
-      if LStart >= 0 then
-        ebBlockChainBlockStart.Text := IntToStr(LStart)
-      else
-        ebBlockChainBlockStart.Text := '';
-      LEnd := StrToInt64Def(ebBlockChainBlockEnd.Text, -1);
-      if LEnd >= 0 then
-        ebBlockChainBlockEnd.Text := IntToStr(LEnd)
-      else
-        ebBlockChainBlockEnd.Text := '';
-      SetBlocks(LStart, LEnd);
-    finally
-      FUpdating := False;
-    end;
+  FBlockChainGrid := TBlockChainGrid.Create(Self);
+  FBlockChainGrid.DrawGrid := dgBlockChainExplorer;
+  FBlockChainGrid.Node := TUserInterface.Node;
+  FBlockChainGrid.ShowTimeAverageColumns:={$IFDEF SHOW_AVERAGE_TIME_STATS}True;{$ELSE}False;{$ENDIF}
+  FUpdating := false;
 end;
 end;
 
 
-procedure TFRMBlockExplorer.ebBlockChainBlockStartKeyPress(Sender: TObject; var Key: char);
-
+procedure TFRMBlockExplorer.FormDestroy(Sender:TObject);
 begin
 begin
-  if Key = #13 then
-    ebBlockChainBlockExit(nil);
+  FreeAndNil(FBlockChainGrid);
 end;
 end;
 
 
 end.
 end.

+ 61 - 60
src/gui/UFRMOperationExplorer.lfm

@@ -1,76 +1,77 @@
 object FRMOperationExplorer: TFRMOperationExplorer
 object FRMOperationExplorer: TFRMOperationExplorer
-  Left = -7
-  Height = 459
-  Top = 2
-  Width = 926
-  Caption = 'Operation Explorer'
-  ClientHeight = 459
-  ClientWidth = 926
-  Menu = OperationExplorerMenu
+  Left = 190
+  Height = 444
+  Top = 287
+  Width = 864
+  Caption = 'Operations Explorer'
+  ClientHeight = 424
+  ClientWidth = 864
+  Menu = OperationsExplorerMenu
   OnCreate = FormCreate
   OnCreate = FormCreate
-  Position = poOwnerFormCenter
-  Visible = False
-  object gpFilter: TGroupBox
-    Left = 8
-    Height = 65
-    Top = 16
-    Width = 904
-    Anchors = [akTop, akLeft, akRight]
-    Caption = 'Filter By Block Range'
-    ClientHeight = 45
-    ClientWidth = 900
+  OnDestroy = FormDestroy
+  LCLVersion = '1.6.4.0'
+  object dgOperationsExplorer: TDrawGrid
+    Left = 0
+    Height = 383
+    Top = 41
+    Width = 864
+    Align = alClient
+    ExtendedSelect = False
     TabOrder = 0
     TabOrder = 0
-    object ebFilterOperationsStartBlock: TEdit
-      Left = 8
-      Height = 23
-      Top = 8
-      Width = 57
-      TabOrder = 0
-      TextHint = 'From'
-    end
-    object ebFilterOperationsEndBlock: TEdit
-      Left = 96
-      Height = 23
-      Top = 8
-      Width = 57
-      TabOrder = 1
-      TextHint = 'To'
-    end
+    TitleFont.Color = clWindowText
+    TitleFont.Height = -11
+    TitleFont.Name = 'Tahoma'
+    OnClick = dgOperationsExplorerClick
   end
   end
-  object gpRecentOps: TGroupBox
-    Left = 8
-    Height = 354
-    Top = 96
-    Width = 904
-    Anchors = [akTop, akLeft, akRight, akBottom]
-    Caption = 'All Operations'
-    ClientHeight = 334
-    ClientWidth = 900
+  object Panel1: TPanel
+    Left = 0
+    Height = 41
+    Top = 0
+    Width = 864
+    Align = alTop
+    BevelOuter = bvNone
+    ClientHeight = 41
+    ClientWidth = 864
     TabOrder = 1
     TabOrder = 1
-    object paOperations: TPanel
-      Left = 8
-      Height = 314
-      Top = 8
-      Width = 888
-      Anchors = [akTop, akLeft, akRight, akBottom]
-      BorderSpacing.Around = 3
-      BevelOuter = bvNone
-      Caption = 'OPERATIONS PANEL'
+    object Label2: TLabel
+      Left = 11
+      Height = 15
+      Top = 10
+      Width = 112
+      Caption = 'Filter by blocks range'
       ParentColor = False
       ParentColor = False
-      TabOrder = 0
     end
     end
   end
   end
-  object OperationExplorerMenu: TMainMenu
-    left = 728
-    top = 32
+  object ebFilterOperationsStartBlock: TEdit
+    Left = 125
+    Height = 23
+    Top = 7
+    Width = 57
+    OnExit = ebFilterOperationsAccountExit
+    OnKeyPress = ebFilterOperationsAccountKeyPress
+    TabOrder = 2
+  end
+  object ebFilterOperationsEndBlock: TEdit
+    Left = 185
+    Height = 23
+    Top = 7
+    Width = 57
+    OnExit = ebFilterOperationsAccountExit
+    OnKeyPress = ebFilterOperationsAccountKeyPress
+    TabOrder = 3
+  end
+  object OperationsExplorerMenu: TMainMenu
+    left = 560
     object miTools: TMenuItem
     object miTools: TMenuItem
       Caption = 'Tools'
       Caption = 'Tools'
-      object miFindOperationByHash: TMenuItem
-        Caption = 'Find Operation By Hash'
-        OnClick = miFindOperationByHashClick
+      object miFindOperationByOpHash: TMenuItem
+        Caption = 'Find Operation by OpHash'
+        ShortCut = 116
+        OnClick = miFindOperationByOpHashClick
       end
       end
       object miDecodePayload: TMenuItem
       object miDecodePayload: TMenuItem
         Caption = 'Decode Payload'
         Caption = 'Decode Payload'
+        ShortCut = 113
         OnClick = miDecodePayloadClick
         OnClick = miDecodePayloadClick
       end
       end
     end
     end

+ 63 - 248
src/gui/UFRMOperationExplorer.pas

@@ -2,199 +2,74 @@ unit UFRMOperationExplorer;
 
 
 {$mode delphi}
 {$mode delphi}
 
 
-{$modeswitch nestedprocvars}
+{ Copyright (c) 2018 by Herman Schoenfeld
+
+  Distributed under the MIT software license, see the accompanying file LICENSE
+  or visit http://www.opensource.org/licenses/mit-license.php.
+
+  Acknowledgements:
+  - Albert Molina: portions of code copied from https://github.com/PascalCoin/PascalCoin/blob/master/Units/Forms/UFRMWallet.pas
+}
+
 
 
 interface
 interface
 
 
+{$I ..\config.inc}
+
 uses
 uses
-  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, Menus,
-  ExtCtrls, Buttons, UVisualGrid, UCommon.UI, Generics.Collections,
-  UAccounts, UDataSources, UNode;
+    LCLIntf, LCLType, SysUtils, Controls, Forms, Dialogs, ExtCtrls, StdCtrls, Grids, Menus, Classes,
+    UCommon.UI, UGridUtils, UConst;
 
 
 type
 type
 
 
   { TFRMOperationExplorer }
   { TFRMOperationExplorer }
 
 
   TFRMOperationExplorer = class(TApplicationForm)
   TFRMOperationExplorer = class(TApplicationForm)
+    dgOperationsExplorer: TDrawGrid;
     ebFilterOperationsEndBlock: TEdit;
     ebFilterOperationsEndBlock: TEdit;
     ebFilterOperationsStartBlock: TEdit;
     ebFilterOperationsStartBlock: TEdit;
-    gpRecentOps: TGroupBox;
-    gpFilter: TGroupBox;
-    miFindOperationByHash: TMenuItem;
+    Label2: TLabel;
+    OperationsExplorerMenu: TMainMenu;
     miDecodePayload: TMenuItem;
     miDecodePayload: TMenuItem;
+    miFindOperationByOpHash: TMenuItem;
     miTools: TMenuItem;
     miTools: TMenuItem;
-    OperationExplorerMenu: TMainMenu;
-    paOperations: TPanel;
+    Panel1: TPanel;
+    procedure dgOperationsExplorerClick(Sender: TObject);
     procedure ebFilterOperationsAccountExit(Sender: TObject);
     procedure ebFilterOperationsAccountExit(Sender: TObject);
-    procedure ebFilterOperationsAccountKeyPress(Sender: TObject; var Key: char);
+    procedure ebFilterOperationsAccountKeyPress(Sender: TObject; var Key: Char);
     procedure FormCreate(Sender: TObject);
     procedure FormCreate(Sender: TObject);
+    procedure FormDestroy(Sender: TObject);
     procedure miDecodePayloadClick(Sender: TObject);
     procedure miDecodePayloadClick(Sender: TObject);
-    procedure miFindOperationByHashClick(Sender: TObject);
+    procedure miFindOperationByOpHashClick(Sender: TObject);
+
   private
   private
-    FMaxBlocks: integer;
-    FUpdating: boolean;
-    FBlockStart, FBlockEnd: int64;
-    FNodeNotifyEvents: TNodeNotifyEvents;
-    FOperationsGrid: TVisualGrid;
-    FOperationsDataSource: TOperationsDataSource;
-    procedure RefreshOperationsGrid;
-    procedure SetBlocks(AStart, AEnd: int64);
-    procedure SetMaxBlocks(AValue: integer);
-  protected
-    procedure OnNodeBlocksChanged(Sender: TObject);
-    procedure OnNodeNewOperation(Sender: TObject);
-    procedure OnOperationSelected(Sender: TObject; constref ASelection: TVisualGridSelection);
+    { private declarations }
+    FUpdating : boolean;
+    FOperationsExplorerGrid : TOperationsGrid;
   public
   public
     { public declarations }
     { public declarations }
-    property MaxBlocks: integer read FMaxBlocks write SetMaxBlocks;
   end;
   end;
 
 
 implementation
 implementation
 
 
-uses
-  UUserInterface, UCellRenderers, UBlockChain, UWallet, UCrypto,
-  UCommon, UMemory, Generics.Defaults, UCommon.Data, UCommon.Collections;
-
-{$R *.lfm}
+{$r *.lfm}
 
 
-{ TFRMOperationExplorer }
+uses UUserInterface, UFRMPayloadDecoder, UBlockChain;
 
 
-procedure TFRMOperationExplorer.ebFilterOperationsAccountExit(Sender: TObject);
-var
-  LStart, LEnd: int64;
+procedure TFRMOperationExplorer.FormCreate(Sender: TObject);
 begin
 begin
-  if not FUpdating then
-    try
-      FUpdating := True;// move to finally
-      LStart := StrToInt64Def(ebFilterOperationsStartBlock.Text, -1);
-      if LStart >= 0 then
-        ebFilterOperationsStartBlock.Text := IntToStr(LStart)
-      else
-        ebFilterOperationsStartBlock.Text := '';
-      LEnd := StrToInt64Def(ebFilterOperationsEndBlock.Text, -1);
-      if LEnd >= 0 then
-        ebFilterOperationsEndBlock.Text := IntToStr(LEnd)
-      else
-        ebFilterOperationsEndBlock.Text := '';
-      SetBlocks(LStart, LEnd);
-    finally
-      FUpdating := False;
-    end;
+  FOperationsExplorerGrid := TOperationsGrid.Create(Self);
+  FOperationsExplorerGrid.Node := TUserInterface.Node;
+  FOperationsExplorerGrid.DrawGrid := dgOperationsExplorer;
+  FOperationsExplorerGrid.AccountNumber := -1;
+  FOperationsExplorerGrid.PendingOperations := False;
+  FUpdating := false;
 end;
 end;
 
 
-procedure TFRMOperationExplorer.ebFilterOperationsAccountKeyPress(Sender: TObject; var Key: char);
+procedure TFRMOperationExplorer.FormDestroy(Sender: TObject);
 begin
 begin
-  if Key = #13 then
-    ebFilterOperationsAccountExit(nil);
-end;
-
-procedure TFRMOperationExplorer.FormCreate(Sender: TObject);
-begin
-
-  FUpdating := False;
-  FBlockStart := -1;
-  FBlockEnd := -1;
-  FMaxBlocks := 300;
-  // event registrations
-  FNodeNotifyEvents := TNodeNotifyEvents.Create(self);
-  FNodeNotifyEvents.OnBlocksChanged := OnNodeBlocksChanged;
-  FNodeNotifyEvents.OnOperationsChanged := OnNodeNewOperation;
-
-  // fields
-  FOperationsDataSource := TOperationsDataSource.Create(Self);
-
-  // grids
-  FOperationsGrid := TVisualGrid.Create(Self);
-  FOperationsGrid.SortMode := smMultiColumn;
-  FOperationsGrid.FetchDataInThread := True;
-  FOperationsGrid.AutoPageSize := True;
-  FOperationsGrid.DeselectionType := dtDefault;
-  FOperationsGrid.SelectionType := stRow;
-  FOperationsGrid.Options := [vgoColAutoFill, vgoColSizing, vgoSortDirectionAllowNone, vgoAutoHidePaging, vgoAutoHideSearchPanel];
-
-  with FOperationsGrid.AddColumn('Time') do
-  begin
-    SortBinding := 'UnixTime';
-    DisplayBinding := 'UnixTime';
-    Renderer := TCellRenderers.OperationTime;
-    Width := 130;
-    Filters := SORTABLE_NUMERIC_FILTER;
-  end;
-  with FOperationsGrid.AddColumn('Block') do
-  begin
-    Binding := 'BlockLocation';
-    SortBinding := 'BlockLocationSortable';
-    Width := 100;
-    HeaderAlignment := taRightJustify;
-    DataAlignment := taRightJustify;
-    Filters := SORTABLE_TEXT_FILTER;
-  end;
-  with FOperationsGrid.AddColumn('Account') do
-  begin
-    Binding := 'AccountNumber';
-    DisplayBinding := 'Account';
-    Width := 100;
-    HeaderAlignment := taRightJustify;
-    DataAlignment := taRightJustify;
-    Filters := SORTABLE_NUMERIC_FILTER;
-  end;
-  with FOperationsGrid.AddColumn('Type') do
-  begin
-    Sanitizer := TCellRenderers.OperationTypeSanitizer;
-    Width := 150;
-    Filters := SORTABLE_NUMERIC_FILTER;
-  end;
-  with FOperationsGrid.AddColumn('Amount') do
-  begin
-    Binding := 'AmountDecimal';
-    SortBinding := 'Amount';
-    DisplayBinding := 'Amount';
-    Width := 100;
-    HeaderAlignment := taRightJustify;
-    DataAlignment := taRightJustify;
-    Renderer := TCellRenderers.PASC_CheckPendingBalance;
-    Filters := SORTABLE_NUMERIC_FILTER;
-  end;
-  with FOperationsGrid.AddColumn('Fee') do
-  begin
-    Binding := 'FeeDecimal';
-    SortBinding := 'Fee';
-    DisplayBinding := 'Fee';
-    Width := 100;
-    HeaderAlignment := taRightJustify;
-    DataAlignment := taRightJustify;
-    Renderer := TCellRenderers.PASC_CheckPendingBalance;
-    Filters := SORTABLE_NUMERIC_FILTER;
-  end;
-  with FOperationsGrid.AddColumn('Balance') do
-  begin
-    Binding := 'BalanceDecimal';
-    SortBinding := 'Balance';
-    DisplayBinding := 'Balance';
-    Width := 100;
-    HeaderAlignment := taRightJustify;
-    DataAlignment := taRightJustify;
-    Renderer := TCellRenderers.PASC_CheckPendingBalance;
-    Filters := SORTABLE_NUMERIC_FILTER;
-  end;
-  with FOperationsGrid.AddColumn('Payload') do
-  begin
-    AutoWidth := True;
-    Renderer := TCellRenderers.Payload;
-    Filters := SORTABLE_TEXT_FILTER;
-  end;
-
-  FOperationsGrid.OnSelection := OnOperationSelected;
-  FOperationsGrid.Caption.Alignment := taCenter;
-  FOperationsGrid.Caption.Text := 'All Operations';
-  FOperationsGrid.Caption.Text := '';
-  FOperationsGrid.Caption.Visible := True;
-
-  // Add datasources to grid
-  FOperationsGrid.DataSource := FOperationsDataSource;
-
-  // Add grid to panels
-  paOperations.AddControlDockCenter(FOperationsGrid);
+  FOperationsExplorerGrid.Node := Nil;
+  // Note: grids themselves are collected with Self (TComponent dependency)
 end;
 end;
 
 
 procedure TFRMOperationExplorer.miDecodePayloadClick(Sender: TObject);
 procedure TFRMOperationExplorer.miDecodePayloadClick(Sender: TObject);
@@ -202,103 +77,43 @@ begin
   TUserInterface.ShowOperationInfoDialog(Self, '');
   TUserInterface.ShowOperationInfoDialog(Self, '');
 end;
 end;
 
 
-procedure TFRMOperationExplorer.miFindOperationByHashClick(Sender: TObject);
-var
-  LOpHash: string;
-begin
-  if not InputQuery('Search operation by OpHash', 'Insert Operation Hash value (OpHash)', LOpHash) then
-    Exit;
-
-  TUserInterface.ShowOperationInfoDialog(Self, LOpHash);
-end;
-
-procedure TFRMOperationExplorer.RefreshOperationsGrid;
+procedure TFRMOperationExplorer.miFindOperationByOpHashClick(Sender: TObject);
 var
 var
-  LNode: TNode;
-  LStart, LEnd: int64;
+  ophash : String;
 begin
 begin
-  LNode := FNodeNotifyEvents.Node;
-  if FBlockEnd < 0 then
-  begin
-    if LNode.Bank.BlocksCount > 0 then
-      LEnd := LNode.Bank.BlocksCount - 1
-    else
-      LEnd := 0;
-  end
-  else
-    LEnd := FBlockEnd;
-  if FBlockStart < 0 then
-  begin
-    if (LEnd > MaxBlocks) then
-      LStart := LEnd - MaxBlocks
-    else
-      LStart := 0;
-  end
-  else
-    LStart := FBlockStart;
-  if LStart < 0 then
-    LStart := 0;
-  if LEnd >= LNode.Bank.BlocksCount then
-    LEnd := LNode.Bank.BlocksCount;
+  if Not InputQuery('Search operation by OpHash','Insert Operation Hash value (OpHash)',ophash)
+    then exit;
 
 
-  FOperationsDataSource.StartBlock := LStart;
-  FOperationsDataSource.EndBlock := LEnd;
-
-  FOperationsGrid.RefreshGrid;
-end;
-
-procedure TFRMOperationExplorer.SetBlocks(AStart, AEnd: int64);
-begin
-  if (AStart = FBlockStart) and (AEnd = FBlockEnd) then
-    Exit;
-  FBlockStart := AStart;
-  FBlockEnd := AEnd;
-  if (FBlockEnd > 0) and (FBlockStart > FBlockEnd) then
-    FBlockStart := -1;
-  RefreshOperationsGrid;
+  TUserInterface.ShowOperationInfoDialog(Self, ophash);
 end;
 end;
 
 
-procedure TFRMOperationExplorer.SetMaxBlocks(AValue: integer);
-begin
-  if FMaxBlocks = AValue then
-    Exit;
-  FMaxBlocks := AValue;
-  if (FMaxBlocks <= 0) or (FMaxBlocks > 500) then
-    FMaxBlocks := 300;
-  RefreshOperationsGrid;
-end;
-
-procedure TFRMOperationExplorer.OnNodeBlocksChanged(Sender: TObject);
+procedure TFRMOperationExplorer.ebFilterOperationsAccountExit(Sender: TObject);
+Var bstart,bend : Int64;
 begin
 begin
-  // TODO: play block sound chime
-  RefreshOperationsGrid;
+  If not FUpdating then
+  Try
+    FUpdating := True;// move to finally
+    bstart := StrToInt64Def(ebFilterOperationsStartBlock.Text,-1);
+    if bstart>=0 then ebFilterOperationsStartBlock.Text := Inttostr(bstart) else ebFilterOperationsStartBlock.Text := '';
+    bend := StrToInt64Def(ebFilterOperationsEndBlock.Text,-1);
+    if bend>=0 then ebFilterOperationsEndBlock.Text := Inttostr(bend) else ebFilterOperationsEndBlock.Text := '';
+      FOperationsExplorerGrid.SetBlocks(bstart,bend);
+  Finally
+
+
+    FUpdating := false;
+  End;
 end;
 end;
 
 
-procedure TFRMOperationExplorer.OnNodeNewOperation(Sender: TObject);
+procedure TFRMOperationExplorer.dgOperationsExplorerClick(Sender: TObject);
 begin
 begin
-  // TODO: play operation sound tick
-  RefreshOperationsGrid;
+  TUserInterface.ShowOperationInfoDialog(Self, FOperationsExplorerGrid.SelectedOperation);
 end;
 end;
 
 
-procedure TFRMOperationExplorer.OnOperationSelected(Sender: TObject; constref ASelection: TVisualGridSelection);
-var
-  row: longint;
-  v: variant;
-  ophash: ansistring;
+procedure TFRMOperationExplorer.ebFilterOperationsAccountKeyPress(Sender: TObject; var Key: Char);
 begin
 begin
-  if ASelection.Page < 0 then
-    exit;
-  row := ASelection.Row;
-  if (row >= 0) and (row < FOperationsGrid.RowCount) then
-  begin
-    v := FOperationsGrid.Rows[row];
-    ophash := FOperationsGrid.Rows[row].OPHASH;
-    if TPCOperation.IsValidOperationHash(ophash) then
-    begin
-      TUserInterface.ShowOperationInfoDialog(self, ophash);
-      FOperationsGrid.ClearSelection(True);
-    end;
-  end;
+  if key=#13 then  ebFilterOperationsAccountExit(Nil);
 end;
 end;
 
 
 end.
 end.
+

+ 2 - 2
src/gui/UUserInterface.pas

@@ -866,7 +866,7 @@ begin
   FUILock.Acquire;
   FUILock.Acquire;
   Try
   Try
     if Assigned(FAccountExplorer) then
     if Assigned(FAccountExplorer) then
-     // FAccountExplorer.RefreshAccountsGrid(true);
+      FAccountExplorer.RefreshAccountsGrid(true);
   finally
   finally
     FUILock.Release;
     FUILock.Release;
   end;
   end;
@@ -878,7 +878,7 @@ begin
   try
   try
     try
     try
       if Assigned(FAccountExplorer) then
       if Assigned(FAccountExplorer) then
-       // FAccountExplorer.RefreshAccountsGrid(false);
+        FAccountExplorer.RefreshAccountsGrid(false);
       FMainForm.SyncControl.UpdateBlockChainState;
       FMainForm.SyncControl.UpdateBlockChainState;
     except
     except
       On E:Exception do begin
       On E:Exception do begin