Icom ID-51A log file viewer and concatenater

Applications, Games, Tools, User libs and useful stuff coded in PureBasic
User avatar
Fangbeast
PureBasic Protozoa
PureBasic Protozoa
Posts: 4790
Joined: Fri Apr 25, 2003 3:08 pm
Location: Not Sydney!!! (Bad water, no goats)

Icom ID-51A log file viewer and concatenater

Post by Fangbeast »

Just got into digital radio in the amateur bands and was surprised (and very glad) to see just how many log files the radio produced for me, full of useful information.

Just as well, since I only have a short pigtail connecting to some RG213AU cable and I have to hold the cable and the radio in each hand and try to transmit at the same time!!!

Anyway, I needed a simple application to load in all the callsigns found, 'caller' and 'called' in a small list and all the actual data in the main list when a callsign is clicked on (it's an ongoing design) and to be able to dump the entire concatenated list to disk when I wanted it. And to be able to search it all.

I find it very useful to relate all the data with my actual QSO's when I couldn't write down contacts by hand.

Might be useful to somebody, who knows....

Code: Select all

;- Window Constants

Enumeration 1
  #Window_ID51LogLister
EndEnumeration

#WindowIndex = #PB_Compiler_EnumerationValue

;- Gadget Constants

Enumeration 1
  ; Window_ID51LogLister
  #MenuBar_ID51LogLister_Files
  #MenuBar_ID51LogLister_Setdirectory
  #MenuBar_ID51LogLister_Getlogfiles
  #MenuBar_ID51LogLister_Savemasterlog
  #MenuBar_ID51LogLister_Exitprogram

  #Gadget_ID51LogLister_Callsigns
  #Gadget_ID51LogLister_fSeparator1
  #Gadget_ID51LogLister_lLoglist
  #Gadget_ID51LogLister_fSeparator2
  #Gadget_ID51LogLister_cControl
  #Gadget_ID51LogLister_fSeparator4
  #Gadget_ID51LogLister_cStatusbar
  #Gadget_ID51LogLister_Setdirectory
  #Gadget_ID51LogLister_Getlogfiles
  #Gadget_ID51LogLister_Savemasterlog
  #Gadget_ID51LogLister_fSeparator3
  #Gadget_ID51LogLister_Directory
  #Gadget_ID51LogLister_LgetDirectory
  #Gadget_ID51LogLister_Searchbox
  #Gadget_ID51LogLister_lSearchbox
  #Gadget_ID51LogLister_ExitProgram
  #Gadget_ID51LogLister_Messages
  #Gadget_ID51LogLister_Current
  #Gadget_ID51LogLister_Lines
EndEnumeration

#GadgetIndex = #PB_Compiler_EnumerationValue

;- MenuBar Constants
Enumeration 1
  #MenuBar_ID51LogLister
EndEnumeration

#MenuBarIndex = #PB_Compiler_EnumerationValue

Procedure.i Window_ID51LogLister()
  If OpenWindow(#Window_ID51LogLister,58,75,1000,760,"Parse and display Icom D-Star CSV log file lists",#PB_Window_SystemMenu|#PB_Window_ScreenCentered|#PB_Window_Invisible)
      SetWindowColor(#Window_ID51LogLister,$E0E0E0)
    CreateImageMenu(#MenuBar_ID51LogLister,WindowID(#Window_ID51LogLister))
      MenuTitle("Files menu")
      MenuItem(#MenuBar_ID51LogLister_Setdirectory,"Set directory")
      MenuItem(#MenuBar_ID51LogLister_Getlogfiles,"Get log files")
      MenuItem(#MenuBar_ID51LogLister_Savemasterlog,"Save master log")
      MenuBar()
      MenuItem(#MenuBar_ID51LogLister_Exitprogram,"Exit this program")
      ListIconGadget(#Gadget_ID51LogLister_Callsigns,5,5,130,600,"Callsigns",126,#PB_ListIcon_FullRowSelect|#PB_ListIcon_AlwaysShowSelection)
        SetGadgetColor(#Gadget_ID51LogLister_Callsigns,#PB_Gadget_BackColor,$E0E0E0)
        SetGadgetFont(#Gadget_ID51LogLister_Callsigns,LoadFont(#Gadget_ID51LogLister_Callsigns,"Comic Sans MS",10,0))
      FrameGadget(#Gadget_ID51LogLister_fSeparator1,140,5,5,600,"",#PB_Frame_Double)
      ListIconGadget(#Gadget_ID51LogLister_lLoglist,150,5,845,600,"Details",0,#PB_ListIcon_FullRowSelect|#PB_ListIcon_AlwaysShowSelection)
        SetGadgetColor(#Gadget_ID51LogLister_lLoglist,#PB_Gadget_BackColor,$E0E0E0)
        SetGadgetFont(#Gadget_ID51LogLister_lLoglist,LoadFont(#Gadget_ID51LogLister_lLoglist,"Comic Sans MS",10,0))
      FrameGadget(#Gadget_ID51LogLister_fSeparator2,5,610,990,5,"",#PB_Frame_Double)
      ContainerGadget(#Gadget_ID51LogLister_cControl,5,620,990,80,#PB_Container_Flat|#PB_Container_BorderLess)
        SetGadgetColor(#Gadget_ID51LogLister_cControl,#PB_Gadget_BackColor,$E0E0E0)
      ButtonGadget(#Gadget_ID51LogLister_Setdirectory,5,5,135,22,"Set log directory",#PB_Button_MultiLine)
        SetGadgetFont(#Gadget_ID51LogLister_Setdirectory,LoadFont(#Gadget_ID51LogLister_Setdirectory,"Comic Sans MS",10,0))
      ButtonGadget(#Gadget_ID51LogLister_Getlogfiles,5,28,135,22,"Get log files",#PB_Button_MultiLine)
        SetGadgetFont(#Gadget_ID51LogLister_Getlogfiles,LoadFont(#Gadget_ID51LogLister_Getlogfiles,"Comic Sans MS",10,0))
      ButtonGadget(#Gadget_ID51LogLister_Savemasterlog,5,51,135,22,"Save master log",#PB_Button_MultiLine)
        SetGadgetFont(#Gadget_ID51LogLister_Savemasterlog,LoadFont(#Gadget_ID51LogLister_Savemasterlog,"Comic Sans MS",10,0))
      FrameGadget(#Gadget_ID51LogLister_fSeparator3,145,5,5,70,"",#PB_Frame_Double)
      StringGadget(#Gadget_ID51LogLister_Directory,155,5,735,25,"",#PB_String_ReadOnly|#PB_String_BorderLess)
        SetGadgetColor(#Gadget_ID51LogLister_Directory,#PB_Gadget_BackColor,$E0E0E0)
        SetGadgetFont(#Gadget_ID51LogLister_Directory,LoadFont(#Gadget_ID51LogLister_Directory,"Comic Sans MS",10,0))
      TextGadget(#Gadget_ID51LogLister_LgetDirectory,155,30,735,15," Current directory to be catalogued...")
        SetGadgetColor(#Gadget_ID51LogLister_LgetDirectory,#PB_Gadget_BackColor,$E0E0E0)
        SetGadgetFont(#Gadget_ID51LogLister_LgetDirectory,LoadFont(#Gadget_ID51LogLister_LgetDirectory,"Comic Sans MS",8,0))
      StringGadget(#Gadget_ID51LogLister_Searchbox,705,50,185,20,"",#PB_String_BorderLess)
        SetGadgetColor(#Gadget_ID51LogLister_Searchbox,#PB_Gadget_BackColor,$D4D4D4)
        SetGadgetFont(#Gadget_ID51LogLister_Searchbox,LoadFont(#Gadget_ID51LogLister_Searchbox,"Comic Sans MS",10,0))
      TextGadget(#Gadget_ID51LogLister_lSearchbox,555,55,150,15,"Search for items in here --->")
        SetGadgetColor(#Gadget_ID51LogLister_lSearchbox,#PB_Gadget_BackColor,$E0E0E0)
        SetGadgetFont(#Gadget_ID51LogLister_lSearchbox,LoadFont(#Gadget_ID51LogLister_lSearchbox,"Comic Sans MS",8,0))
      ButtonGadget(#Gadget_ID51LogLister_ExitProgram,895,5,90,70,"Exit this  program",#PB_Button_MultiLine)
        SetGadgetFont(#Gadget_ID51LogLister_ExitProgram,LoadFont(#Gadget_ID51LogLister_ExitProgram,"Comic Sans MS",10,0))
      CloseGadgetList()
      FrameGadget(#Gadget_ID51LogLister_fSeparator4,5,705,990,5,"",#PB_Frame_Double)
      ContainerGadget(#Gadget_ID51LogLister_cStatusbar,5,715,990,20,#PB_Container_Flat|#PB_Container_BorderLess)
        SetGadgetColor(#Gadget_ID51LogLister_cStatusbar,#PB_Gadget_BackColor,$E0E0E0)
      StringGadget(#Gadget_ID51LogLister_Messages,0,0,780,20,"",#PB_String_ReadOnly|#PB_String_BorderLess)
        SetGadgetColor(#Gadget_ID51LogLister_Messages,#PB_Gadget_BackColor,$E0E0E0)
        SetGadgetFont(#Gadget_ID51LogLister_Messages,LoadFont(#Gadget_ID51LogLister_Messages,"Comic Sans MS",8,0))
      StringGadget(#Gadget_ID51LogLister_Current,785,0,100,20,"",#PB_String_ReadOnly|#PB_String_BorderLess)
        SetGadgetColor(#Gadget_ID51LogLister_Current,#PB_Gadget_BackColor,$E0E0E0)
        SetGadgetFont(#Gadget_ID51LogLister_Current,LoadFont(#Gadget_ID51LogLister_Current,"Comic Sans MS",8,0))
      StringGadget(#Gadget_ID51LogLister_Lines,890,0,100,20,"",#PB_String_ReadOnly|#PB_String_BorderLess)
        SetGadgetColor(#Gadget_ID51LogLister_Lines,#PB_Gadget_BackColor,$E0E0E0)
        SetGadgetFont(#Gadget_ID51LogLister_Lines,LoadFont(#Gadget_ID51LogLister_Lines,"Comic Sans MS",8,0))
      CloseGadgetList()
      HideWindow(#Window_ID51LogLister,0)
    ProcedureReturn WindowID(#Window_ID51LogLister)
  EndIf
EndProcedure

#EmptyString  = ""

Structure ProgramData
  QuitValue.i
  ListColumns.i
  CsvDirectory.s
  CurrentDirectory.s
  ConfigFileName.s
  MasterLogFileName.s
  
  SearchCueFont.i                                                                                   ; Searchbox cue font
  SearchNormalFont.i                                                                                ; Searchbox normal font
  SearchCueText.s                                                                                   ; Search box prompt text
EndStructure

DataSection
  ListColumnNames:
  Data.s "Frequency"            ;  1
  Data.s "Mode"                 ;  2
  Data.s "Caller"               ;  3
  Data.s "/"                    ;  4
  Data.s "Called"               ;  5
  Data.s "Rx RPT1"              ;  6
  Data.s "Rx RPT2"              ;  7
  Data.s "Message"              ;  8
  Data.s "Status"               ;  9
  Data.s "Received date"        ; 10
  Data.s "BK"                   ; 11
  Data.s "EMR"                  ; 12
  Data.s "Latitude"             ; 13
  Data.s "Longitude"            ; 14
  Data.s "Altitude"             ; 15
  Data.s "SSID"                 ; 16
  Data.s "D-PRS Symbol"         ; 17
  Data.s "Course"               ; 18
  Data.s "Speed"                ; 19
  Data.s "Power"                ; 20
  Data.s "Height"               ; 21
  Data.s "Gain"                 ; 22
  Data.s "Directivity"          ; 23
  Data.s "Object/Item Name"     ; 24
  Data.s "Data Type"            ; 25
  Data.s "Temperature"          ; 26
  Data.s "Rainfall"             ; 27
  Data.s "Rainfall (24 Hours)"  ; 28
  Data.s "Rainfall (Midnight)"  ; 29
  Data.s "Wind Direction"       ; 20
  Data.s "Wind Speed"           ; 21
  Data.s "Gust Speed"           ; 22
  Data.s "Barometric"           ; 23
  Data.s "Humidity"             ; 24
  Data.s "GPS Time Stamp"       ; 25
  Data.s "GPS Message"          ; 26
  Data.s "_END_"                ; 
EndDataSection

Global Program.ProgramData
Global NewList Callsigns.s()
Global NewList Logdetails.s()

Program\CurrentDirectory  = GetCurrentDirectory()
Program\ConfigFileName    = Program\CurrentDirectory  + "ID-51 log parser.config"
Program\MasterLogFileName = Program\CurrentDirectory  + "ID-51 master log file.log"

; Setup the search box cue fonts

Program\SearchCueFont       = LoadFont(#PB_Any,   "Georgia",       10, #PB_Font_Italic)             ; Empty search cue font
Program\SearchNormalFont    = LoadFont(#PB_Any,   "Comic Sans MS", 10, 0)                           ; Filled cue box font
Program\SearchCueText       = Space(256)                                                            ; Set the cue text buffer

PokeS(@Program\SearchCueText, "Search string here...", -1, #PB_Unicode)                             ; Fill the buffer with the cue text

; 

Enumeration #GadgetIndex
  #Shortcut_ID51LogLister_SearchCalsigns
EndEnumeration

; 

Declare   CheckDuplicateCallsign(CallSign.s)                                                                  ; 
Declare   ExportMasterLogFile()                                                                               ; 
Declare   GetCallsignLog()                                                                                    ; 
Declare   LoadConfigFile()                                                                                    ; 
Declare   SaveConfigFile()                                                                                    ; 
Declare   SearchCallsignLog()                                                                                 ; 
Declare   ProcessLogFiles()                                                                                   ; 
Declare   ProcessCurrentLogFile(LogFileNames.s)                                                               ; 
Declare   SetInfoBarArea(FieldName.s, FieldStatus.s, MessageContent.s = "0", ModuleName.s = #EmptyString)     ; 

; ; 
; 
; XIncludeFile "ID-51 Log parser_Constants.pb"                                                        ; Visual designer created constants
; XIncludeFile "ID-51 Log parser_Windows.pb"                                                          ; Visual designer created windows
; XIncludeFile "ID-51 Log parser_MyConstants.pb"                                                      ; My personal constants
; XIncludeFile "ID-51 Log parser_MyDeclarations.pb"                                                   ; My procedural declarations
; 
; ; 
; 
; XIncludeFile "Modules\_CheckDuplicateCallsign.pbi"                                                  ; 
; XIncludeFile "Modules\_ExportMasterLogFile.pbi"                                                     ; 
; XIncludeFile "Modules\_GetCallsignLog.pbi"                                                          ; 
; XIncludeFile "Modules\_LoadConfigFile.pbi"                                                          ; 
; XIncludeFile "Modules\_SaveConfigFile.pbi"                                                          ; 
; XIncludeFile "Modules\_SearchCallsignLog.pbi"                                                       ; 
; XIncludeFile "Modules\_ProcessLogFiles.pbi"                                                         ; 
; XIncludeFile "Modules\_ProcessCurrentLogFile.pbi"                                                   ; 
; XIncludeFile "Modules\_SetInfoBarArea.pbi"                                                          ; Send messages and error reports to the fake status bar area

; 

Procedure CheckDuplicateCallsign(CallSign.s)
  If CallSign.s <> "" And CallSign.s <> "Caller" And CallSign.s <> "Called" And CallSign.s <> "       I"
    ForEach Callsigns.s()
      If Callsigns.s() = CallSign.s
        FoundFlag.i = 1
      EndIf
    Next
    If FoundFlag.i = 0
      AddElement(Callsigns.s())
      Callsigns.s() = CallSign.s
      AddGadgetItem(#Gadget_ID51LogLister_Callsigns, -1, CallSign.s)
    EndIf
  EndIf
EndProcedure

; 

Procedure ExportMasterLogFile()
  ListHandle.i      = SendMessage_(GadgetID(#Gadget_ID51LogLister_lLoglist), #LVM_GETHEADER, 0, 0)  ; : Debug "Got handle to the List:  "         + Str(ListHandle.i)
  NumberOfColumns.i = SendMessage_(ListHandle.i, #HDM_GETITEMCOUNT, 0, 0)                           ; : Debug "Got number of columns in List: "   + Str(NumberOfColumns.i)
  SortList(Logdetails.s(), #PB_Sort_Ascending | #PB_Sort_NoCase)
  MasterLogFile.i   = CreateFile(#PB_Any, Program\MasterLogFileName)                                ; : Debug "Created master output file:  "     + Str(MasterLogFile.i)
  If MasterLogFile.i <> 0
    ForEach (Logdetails.s())
      WriteStringN(MasterLogFile.i, Logdetails.s())
    Next
    CloseFile(MasterLogFile.i)
    SetInfoBarArea("Headings", "Info", "Master log file created in program directory", "ExportMasterLogFile")
  Else
    SetInfoBarArea("Headings", "Warn", "Could not create the master log file", "ExportMasterLogFile")
  EndIf
EndProcedure

; 

Procedure GetCallsignLog()
  CurrentLine.i = GetGadgetState(#Gadget_ID51LogLister_Callsigns)
  If CurrentLine.i <> -1
    ClearGadgetItems(#Gadget_ID51LogLister_lLoglist)
    CurrentCallsign.s = GetGadgetItemText(#Gadget_ID51LogLister_Callsigns, CurrentLine.i, 0)
    SetInfoBarArea("Record", "",  CurrentCallsign.s, "GetCallsignLog")
    ForEach Logdetails.s()
      If FindString(Logdetails.s(), CurrentCallsign.s) <> 0
        AddGadgetItem(#Gadget_ID51LogLister_lLoglist, -1, ReplaceString(Logdetails.s(), ",", #LF$))        
      EndIf
    Next
    For WidthSet.i = 0 To Program\ListColumns - 1
      SendMessage_(GadgetID(#Gadget_ID51LogLister_lLoglist), #LVM_SETCOLUMNWIDTH, WidthSet.i, #LVSCW_AUTOSIZE)
    Next WidthSet.i
    SetInfoBarArea("Headings", "Info", "Finished resizing columns to fit Data", "GetCallsignLog")
    SetInfoBarArea("Callsigns", "",         Str(CountGadgetItems(#Gadget_ID51LogLister_lLoglist)),  "GetCallsignLog")
  Else
    SetInfoBarArea("Headings", "Warn", "Nothing to resize, no data found", "GetCallsignLog")
  EndIf
EndProcedure

; 

Procedure LoadConfigFile()
  If FileSize(Program\ConfigFileName) <> -1
    ConfigFileHandle.i = ReadFile(#PB_Any, Program\ConfigFileName)
    If ConfigFileHandle.i <> 0
      Program\CsvDirectory = ReadString(ConfigFileHandle.i)
      If Program\CsvDirectory <> ""
        SetGadgetText(#Gadget_ID51LogLister_Directory, Program\CsvDirectory)
        SetInfoBarArea("Headings", "Info", "Catalogue directory name was set", "LoadConfigFile")
      Else
        SetInfoBarArea("Headings", "Error", "Could not set the catalogue directory name", "LoadConfigFile")
      EndIf
      CloseFile(ConfigFileHandle.i)
    Else
      SetInfoBarArea("Headings", "Error", "Could not open the program config file", "LoadConfigFile")
    EndIf
  Else
    SaveConfigFile()
  EndIf
EndProcedure

; 

Procedure SaveConfigFile()
  Program\CsvDirectory = PathRequester("CSV log path", "")
  If Program\CsvDirectory
    SetGadgetText(#Gadget_ID51LogLister_Directory, Program\CsvDirectory)
    ConfigFileHandle.i = CreateFile(#PB_Any, Program\ConfigFileName)
    If ConfigFileHandle.i <> 0
      WriteStringN(ConfigFileHandle.i, Program\CsvDirectory)
      SetInfoBarArea("Headings", "Info", "Config file created in program directory", "SaveConfigFile")
    Else
      SetInfoBarArea("Headings", "Error", "Could not create config file in program directory", "SaveConfigFile")
    EndIf
  Else
    SetInfoBarArea("Headings", "Warn", "User decided not to change catalogue path", "SaveConfigFile")
  EndIf
EndProcedure

; 

Procedure SearchCallsignLog()
  If ListSize(Logdetails.s())
    CurrentText.s = GetGadgetText(#Gadget_ID51LogLister_Searchbox)
    If CurrentText.s <> ""
      ClearGadgetItems(#Gadget_ID51LogLister_lLoglist)
      SetGadgetText(#Gadget_ID51LogLister_Searchbox, "")
      ForEach Logdetails.s()
        If FindString(Logdetails.s(), CurrentText.s, 1, #PB_String_NoCase) <> 0
          AddGadgetItem(#Gadget_ID51LogLister_lLoglist, -1, ReplaceString(Logdetails.s(), ",", #LF$))        
        EndIf
      Next
      For WidthSet.i = 0 To Program\ListColumns - 1
        SendMessage_(GadgetID(#Gadget_ID51LogLister_lLoglist), #LVM_SETCOLUMNWIDTH, WidthSet.i, #LVSCW_AUTOSIZE)
      Next WidthSet.i
      SetInfoBarArea("Headings", "Info", "Finished resizing columns to fit data", "SearchCallsignLog")
      SetInfoBarArea("Callsigns", "",         Str(CountGadgetItems(#Gadget_ID51LogLister_lLoglist)),  "MainMenu")
    Else
      SetInfoBarArea("Headings", "Warn", "User entered no data to search for", "SearchCallsignLog")
    EndIf
  Else
    SetInfoBarArea("Headings", "Error", "Nothing loaded in memory to search through", "SearchCallsignLog")
  EndIf
EndProcedure

; 

Procedure ProcessLogFiles()
  Pattern.s       = "Csv (*.csv)|*.csv"
  Position.i      = 0
  LogFileNames.s  = OpenFileRequester("Provide CSV logfile names", Program\CsvDirectory, Pattern.s, Position.i, #PB_Requester_MultiSelection)
  If LogFileNames.s <> ""
    While LogFileNames.s
      ProcessCurrentLogFile(LogFileNames.s)
      LogFileNames.s = NextSelectedFileName() 
    Wend 
    SetInfoBarArea("Headings", "Info", "All selected log files have been loaded into memory", "ProcessLogFiles")
    If CountGadgetItems(#Gadget_ID51LogLister_Callsigns) <> 0
      SetGadgetState(#Gadget_ID51LogLister_Callsigns, 0)
      PostEvent(#PB_Event_Gadget, #Window_ID51LogLister, #Gadget_ID51LogLister_Callsigns, #PB_EventType_Change)
    EndIf
  Else
    SetInfoBarArea("Headings", "Warn", "User provided no filenames to process", "ProcessLogFiles")
  EndIf
EndProcedure

; 

Procedure ProcessCurrentLogFile(LogFileNames.s)
  CurrentFileName.i = ReadFile(#PB_Any, LogFileNames.s)
  If CurrentFileName.i
    While Eof(CurrentFileName.i) = 0
      CurrentLine.s = ReadString(CurrentFileName.i)
      CheckDuplicateCallsign(StringField(CurrentLine.s, 3, ","))
      CheckDuplicateCallsign(StringField(CurrentLine.s, 5, ","))
      If Left(CurrentLine.s, 9) <> "Frequency"
        If FindString(CurrentLine.s, "LMSG") = 0 And FindString(CurrentLine.s, "RPTR") = 0
          If StringField(CurrentLine.s, 3, ",") <> "" And StringField(CurrentLine.s, 5, ",") <> ""
            AddElement(Logdetails.s())
            Logdetails.s()  = CurrentLine.s
          EndIf
        EndIf
      EndIf
    Wend
    CloseFile(CurrentFileName.i)
  Else
    SetInfoBarArea("Headings", "Warn", "The current filename could not be processed", "ProcessCurrentLogFile")
  EndIf
EndProcedure

; Send messages and error reports to the fake status bar area

Procedure SetInfoBarArea(FieldName.s, FieldStatus.s, MessageContent.s = "0", ModuleName.s = #EmptyString)
  ; Take care of any orphan routines that might want to send status messages here
  If IsWindow(#Window_ID51LogLister)
    ; Select the name of the field to put our heading string
    Select FieldName.s
      ; Select the correct heading by the status field
      Case "Headings"
        ; 
        Select FieldStatus.s
          Case "Welcome"
            MessageHeader.s = "Welcome!"
            Colour.i        = $0000FF
          Case "Info"
            MessageHeader.s = "Information"
            Colour.i        = $000000
          Case "Warn"
            MessageHeader.s = "Warning"
            Colour.i        = $7D1F82
          Case "Error"
            MessageHeader.s = "Error"
            Colour.i        = $0402FB
        EndSelect
        ; Send all the strings to the fake status bar area
        If ModuleName.s <> #EmptyString
          SetGadgetText(#Gadget_ID51LogLister_Messages, MessageHeader.s + ": "  + MessageContent.s  + " ::" + ModuleName.s  + "::")
        Else
          SetGadgetText(#Gadget_ID51LogLister_Messages, MessageHeader.s + ": "  + MessageContent.s)
        EndIf
        ; 
      Case "Record"
        ; 
        SetGadgetText(#Gadget_ID51LogLister_Current, "Call: " + MessageContent.s)
        ; 
      Case "Callsigns"
        ; Figure out the correct spelling for the record field for singles or multiples
        If Val(MessageContent.s) = 0
          RecordHeader.s = "Records"
        ElseIf Val(MessageContent.s) = 1
          RecordHeader.s = "Record"
        ElseIf Val(MessageContent.s) >= 2
          RecordHeader.s = "Records"
        EndIf
        ; Set the record number details in the fake status bar area
        SetGadgetText(#Gadget_ID51LogLister_Lines, MessageContent.s + " " + RecordHeader.s)
        ; 
    EndSelect
    ; 
  EndIf
  ; 
EndProcedure

; 

If Window_ID51LogLister()
  ; Add a keyboard shortcut for the search box
  AddKeyboardShortcut(#Window_ID51LogLister, #PB_Shortcut_Return, #Shortcut_ID51LogLister_SearchCalsigns)
  ; Remove the empty column from the details list
  RemoveGadgetColumn(#Gadget_ID51LogLister_lLoglist, 0)
  ; Load the directory configuration file
  LoadConfigFile()
  ; Add the list of column names from the data sections
  Program\ListColumns = 0
  ; 
  Restore ListColumnNames
    While TempString.s <> "_END_"
      Read.s TempString.s
      If TempString.s <> "_END_"
        AddGadgetColumn(#Gadget_ID51LogLister_lLoglist, Program\ListColumns, TempString.s, 0)
        Program\ListColumns + 1
      EndIf
    Wend
  TempString.s = "<><>"
  ; Limit the number of search box characters and set the cue banner text. These variables are set
  ; in the Keeper_Myconstants file.
  SendMessage_(GadgetID(#Gadget_ID51LogLister_Searchbox), #EM_SETLIMITTEXT, 67, 0)
  SendMessage_(GadgetID(#Gadget_ID51LogLister_Searchbox), #EM_SETCUEBANNER,  1,  Program\SearchCueText)
  ; Set initial search cue font
  SetGadgetFont(#Gadget_ID51LogLister_Searchbox, FontID(Program\SearchCueFont))
  ; Give the startup message and callsign count
  SetInfoBarArea("Headings",  "Welcome",  "ID-51 log parser startup",                             "MainMenu")
  SetInfoBarArea("Record",    "",         "?",                                                    "MainMenu")
  SetInfoBarArea("Callsigns", "",         Str(CountGadgetItems(#Gadget_ID51LogLister_lLoglist)),  "MainMenu")
  ; Set focus on the search bar
  SetActiveGadget(#Gadget_ID51LogLister_Searchbox)  
  ; Main event handler
  Repeat
    ; 
    EventID  = WaitWindowEvent()
    MenuID   = EventMenu()
    GadgetID = EventGadget()
    WindowID = EventWindow()
    ; 
    Select EventID
      ; 
      Case #PB_Event_CloseWindow
        Select WindowID
          Case #Window_ID51LogLister                  : Program\QuitValue = 1
        EndSelect
        ; 
      Case #PB_Event_Menu
        Select MenuID
          Case #MenuBar_ID51LogLister_Setdirectory    : SaveConfigFile()
          Case #MenuBar_ID51LogLister_Getlogfiles     : ProcessLogFiles()
          Case #MenuBar_ID51LogLister_Savemasterlog   : ExportMasterLogFile()
          Case #MenuBar_ID51LogLister_Exitprogram     : Program\QuitValue = 1
          Case #Shortcut_ID51LogLister_SearchCalsigns : If GetActiveGadget() = #Gadget_ID51LogLister_Searchbox : SearchCallsignLog() : EndIf
        EndSelect
        ; 
      Case #PB_Event_Gadget
        Select GadgetID
          Case #Gadget_ID51LogLister_Callsigns
            Select EventType()
              Case #PB_EventType_LeftDoubleClick      : 
              Case #PB_EventType_RightDoubleClick     : 
              Case #PB_EventType_RightClick           : 
              Case #PB_EventType_Change               : GetCallsignLog()
            EndSelect
          Case #Gadget_ID51LogLister_lLoglist
            Select EventType()
              Case #PB_EventType_LeftDoubleClick      : 
              Case #PB_EventType_RightDoubleClick     : 
              Case #PB_EventType_RightClick           : 
              Case #PB_EventType_Change               : 
            EndSelect
          Case #Gadget_ID51LogLister_Searchbox
            Select EventType()
              Case #PB_EventType_Change
              If GetGadgetText(#Gadget_ID51LogLister_Searchbox) = ""
                SetGadgetFont(#Gadget_ID51LogLister_Searchbox, FontID(Program\SearchCueFont))
              Else
                SetGadgetFont(#Gadget_ID51LogLister_Searchbox, FontID(Program\SearchNormalFont))
              EndIf
            EndSelect
          Case #Gadget_ID51LogLister_Setdirectory     : SaveConfigFile()
          Case #Gadget_ID51LogLister_Getlogfiles      : ProcessLogFiles()
          Case #Gadget_ID51LogLister_Savemasterlog    : ExportMasterLogFile()
          Case #Gadget_ID51LogLister_ExitProgram      : Program\QuitValue = 1
        EndSelect
        ; 
    EndSelect
    ; 
  Until Program\QuitValue
  ; 
  CloseWindow(#Window_ID51LogLister)
  ; 
EndIf
; 
End
Amateur Radio/VK3HAF, (D-STAR/DMR and more), Arduino, ESP32, Coding, Crochet
User avatar
Fangbeast
PureBasic Protozoa
PureBasic Protozoa
Posts: 4790
Joined: Fri Apr 25, 2003 3:08 pm
Location: Not Sydney!!! (Bad water, no goats)

Re: Icom ID-51A log file viewer and concatenater

Post by Fangbeast »

Did a load of cleanup, still has room for improvements. But now a lot of useless repeater data has been omitted from the load and searches. Export to LOG, XML and JSON are implemented, sort the callsign list on load and a lot more.

Hope it's useful to somebody, it certainly is to me.

Code: Select all

Define EventID, MenuID, GadgetID, WindowID

; Window Constants

Enumeration 1
  #Window_ID51LogLister
EndEnumeration

#WindowIndex = #PB_Compiler_EnumerationValue

; Gadget Constants

Enumeration 1
  ; Window_ID51LogLister
  #MenuBar_ID51LogLister_Files
  #MenuBar_ID51LogLister_Setdirectory
  #MenuBar_ID51LogLister_Getlogfiles
  #MenuBar_ID51LogLister_Savemasterlog
  #MenuBar_ID51LogLister_Exitprogram

  #Gadget_ID51LogLister_Callsigns
  #Gadget_ID51LogLister_fSeparator1
  #Gadget_ID51LogLister_lLoglist
  #Gadget_ID51LogLister_fSeparator2
  #Gadget_ID51LogLister_cControl
  #Gadget_ID51LogLister_ExitProgram
  #Gadget_ID51LogLister_fSeparator4
  #Gadget_ID51LogLister_cStatusbar
  #Gadget_ID51LogLister_Setdirectory
  #Gadget_ID51LogLister_Getlogfiles
  #Gadget_ID51LogLister_Savemasterlog
  #Gadget_ID51LogLister_fSeparator3
  #Gadget_ID51LogLister_Directory
  #Gadget_ID51LogLister_LgetDirectory
  #Gadget_ID51LogLister_lSearchmask
  #Gadget_ID51LogLister_Searchmask
  #Gadget_ID51LogLister_Messages
  #Gadget_ID51LogLister_Current
  #Gadget_ID51LogLister_Lines
  #Gadget_ID51LogLister_lSearchbox
  #Gadget_ID51LogLister_Searchbox
EndEnumeration

#GadgetIndex = #PB_Compiler_EnumerationValue

; MenuBar Constants

Enumeration 1
  #MenuBar_ID51LogLister
EndEnumeration

#MenuBarIndex = #PB_Compiler_EnumerationValue

Procedure.i Window_ID51LogLister()
  If OpenWindow(#Window_ID51LogLister, 96, 71, 1000, 760, "Parse and display Icom D-Star CSV log file lists", #PB_Window_SystemMenu|#PB_Window_ScreenCentered|#PB_Window_Invisible)
      SetWindowColor(#Window_ID51LogLister, $E0E0E0)
    CreateImageMenu(#MenuBar_ID51LogLister, WindowID(#Window_ID51LogLister))
      MenuTitle("Files menu")
      MenuItem(#MenuBar_ID51LogLister_Setdirectory, "Set directory")
      MenuItem(#MenuBar_ID51LogLister_Getlogfiles, "Get log files")
      MenuItem(#MenuBar_ID51LogLister_Savemasterlog, "Save master log")
      MenuBar()
      MenuItem(#MenuBar_ID51LogLister_Exitprogram, "Exit this program")
      ListIconGadget(#Gadget_ID51LogLister_Callsigns, 5, 5, 140, 600, "Callsigns", 136, #PB_ListIcon_FullRowSelect|#PB_ListIcon_AlwaysShowSelection)
        SetGadgetColor(#Gadget_ID51LogLister_Callsigns, #PB_Gadget_BackColor, $E0E0E0)
        SetGadgetFont(#Gadget_ID51LogLister_Callsigns, LoadFont(#Gadget_ID51LogLister_Callsigns, "Comic Sans MS", 10, 0))
      FrameGadget(#Gadget_ID51LogLister_fSeparator1, 150, 5, 5, 600, "", #PB_Frame_Double)
      ListIconGadget(#Gadget_ID51LogLister_lLoglist, 160, 5, 835, 600, "Details", 0, #PB_ListIcon_FullRowSelect|#PB_ListIcon_AlwaysShowSelection)
        SetGadgetColor(#Gadget_ID51LogLister_lLoglist, #PB_Gadget_BackColor, $E0E0E0)
        SetGadgetFont(#Gadget_ID51LogLister_lLoglist, LoadFont(#Gadget_ID51LogLister_lLoglist, "Comic Sans MS", 10, 0))
      FrameGadget(#Gadget_ID51LogLister_fSeparator2, 5, 610, 990, 5, "", #PB_Frame_Double)
      ContainerGadget(#Gadget_ID51LogLister_cControl, 5, 620, 990, 80, #PB_Container_Flat|#PB_Container_BorderLess)
        SetGadgetColor(#Gadget_ID51LogLister_cControl, #PB_Gadget_BackColor, $E0E0E0)
      ButtonGadget(#Gadget_ID51LogLister_ExitProgram, 895, 5, 90, 70, "Exit this  program", #PB_Button_MultiLine)
        SetGadgetFont(#Gadget_ID51LogLister_ExitProgram, LoadFont(#Gadget_ID51LogLister_ExitProgram, "Comic Sans MS", 10, 0))
      ButtonGadget(#Gadget_ID51LogLister_Setdirectory, 5, 5, 135, 22, "Set log directory", #PB_Button_MultiLine)
        SetGadgetFont(#Gadget_ID51LogLister_Setdirectory, LoadFont(#Gadget_ID51LogLister_Setdirectory, "Comic Sans MS", 10, 0))
      ButtonGadget(#Gadget_ID51LogLister_Getlogfiles, 5, 28, 135, 22, "Get log files", #PB_Button_MultiLine)
        SetGadgetFont(#Gadget_ID51LogLister_Getlogfiles, LoadFont(#Gadget_ID51LogLister_Getlogfiles, "Comic Sans MS", 10, 0))
      ButtonGadget(#Gadget_ID51LogLister_Savemasterlog, 5, 51, 135, 22, "Save master log", #PB_Button_MultiLine)
        SetGadgetFont(#Gadget_ID51LogLister_Savemasterlog, LoadFont(#Gadget_ID51LogLister_Savemasterlog, "Comic Sans MS", 10, 0))
      FrameGadget(#Gadget_ID51LogLister_fSeparator3, 145, 5, 5, 70, "", #PB_Frame_Double)
      StringGadget(#Gadget_ID51LogLister_Directory, 155, 5, 735, 25, "", #PB_String_ReadOnly|#PB_String_BorderLess)
        SetGadgetColor(#Gadget_ID51LogLister_Directory, #PB_Gadget_BackColor, $D4D4D4)
        SetGadgetFont(#Gadget_ID51LogLister_Directory, LoadFont(#Gadget_ID51LogLister_Directory, "Comic Sans MS", 10, 0))
      TextGadget(#Gadget_ID51LogLister_LgetDirectory, 155, 30, 735, 15, "Current directory to be catalogued...")
        SetGadgetColor(#Gadget_ID51LogLister_LgetDirectory, #PB_Gadget_BackColor, $E0E0E0)
        SetGadgetFont(#Gadget_ID51LogLister_LgetDirectory, LoadFont(#Gadget_ID51LogLister_LgetDirectory, "Comic Sans MS", 8, 0))
      TextGadget(#Gadget_ID51LogLister_lSearchmask, 155, 55, 150, 15, "Caller search mask --->")
        SetGadgetColor(#Gadget_ID51LogLister_lSearchmask, #PB_Gadget_BackColor, $E0E0E0)
        SetGadgetFont(#Gadget_ID51LogLister_lSearchmask, LoadFont(#Gadget_ID51LogLister_lSearchmask, "Comic Sans MS", 8, 0))
      StringGadget(#Gadget_ID51LogLister_Searchmask, 275, 50, 85, 20, "vk3rwn c", #PB_String_UpperCase|#PB_String_BorderLess)
        SetGadgetColor(#Gadget_ID51LogLister_Searchmask, #PB_Gadget_BackColor, $D4D4D4)
        SetGadgetFont(#Gadget_ID51LogLister_Searchmask, LoadFont(#Gadget_ID51LogLister_Searchmask, "Comic Sans MS", 10, 0))
      TextGadget(#Gadget_ID51LogLister_lSearchbox, 555, 55, 150, 15, "Search for items in here --->")
        SetGadgetColor(#Gadget_ID51LogLister_lSearchbox, #PB_Gadget_BackColor, $E0E0E0)
        SetGadgetFont(#Gadget_ID51LogLister_lSearchbox, LoadFont(#Gadget_ID51LogLister_lSearchbox, "Comic Sans MS", 8, 0))
      StringGadget(#Gadget_ID51LogLister_Searchbox, 705, 50, 185, 20, "", #PB_String_BorderLess)
        SetGadgetColor(#Gadget_ID51LogLister_Searchbox, #PB_Gadget_BackColor, $D4D4D4)
        SetGadgetFont(#Gadget_ID51LogLister_Searchbox, LoadFont(#Gadget_ID51LogLister_Searchbox, "Comic Sans MS", 10, 0))
      CloseGadgetList()
      FrameGadget(#Gadget_ID51LogLister_fSeparator4, 5, 705, 990, 5, "", #PB_Frame_Double)
      ContainerGadget(#Gadget_ID51LogLister_cStatusbar, 5, 715, 990, 20, #PB_Container_Flat|#PB_Container_BorderLess)
        SetGadgetColor(#Gadget_ID51LogLister_cStatusbar, #PB_Gadget_BackColor, $E0E0E0)
      StringGadget(#Gadget_ID51LogLister_Messages, 0, 0, 780, 20, "", #PB_String_ReadOnly|#PB_String_BorderLess)
        SetGadgetColor(#Gadget_ID51LogLister_Messages, #PB_Gadget_BackColor, $E0E0E0)
        SetGadgetFont(#Gadget_ID51LogLister_Messages, LoadFont(#Gadget_ID51LogLister_Messages, "Comic Sans MS", 8, 0))
      StringGadget(#Gadget_ID51LogLister_Current, 785, 0, 100, 20, "", #PB_String_ReadOnly|#PB_String_BorderLess)
        SetGadgetColor(#Gadget_ID51LogLister_Current, #PB_Gadget_BackColor, $E0E0E0)
        SetGadgetFont(#Gadget_ID51LogLister_Current, LoadFont(#Gadget_ID51LogLister_Current, "Comic Sans MS", 8, 0))
      StringGadget(#Gadget_ID51LogLister_Lines, 890, 0, 100, 20, "", #PB_String_ReadOnly|#PB_String_BorderLess)
        SetGadgetColor(#Gadget_ID51LogLister_Lines, #PB_Gadget_BackColor, $E0E0E0)
        SetGadgetFont(#Gadget_ID51LogLister_Lines, LoadFont(#Gadget_ID51LogLister_Lines, "Comic Sans MS", 8, 0))
      CloseGadgetList()
      HideWindow(#Window_ID51LogLister, 0)
    ProcedureReturn WindowID(#Window_ID51LogLister)
  EndIf
EndProcedure

; 

#EmptyString        = ""
#StringNotFound     = 0
#FileNotFound       = -1
#NoCurrentLine      = -1
#AtTheEndOfTheLine  = -1
#NoFileHandle       = 0
#NoColumnsFound     = 0
#AtTheEndOfTheList  = -1

; 

Structure ProgramData
  QuitValue.i                                                                                       ; 
  ListColumns.i                                                                                     ; 
  CsvDirectory.s                                                                                    ; 
  CallerMask.s                                                                                      ; 
  CurrentDirectory.s                                                                                ; 
  InitialisationFile.s                                                                              ; 
  MasterLogFileName.s                                                                               ; 
  
  SearchCueFont.i                                                                                   ; Searchbox cue font
  SearchNormalFont.i                                                                                ; Searchbox normal font
  SearchCueText.s                                                                                   ; Search box prompt text
EndStructure

; 

Structure MasterlogData
  Frequency.s           ;  1
  Mode.s                ;  2
  Caller.s              ;  3
  Slash.s               ;  4
  Called.s              ;  5
  Rx_RPT1.s             ;  6
  Rx_RPT2.s             ;  7
  Message.s             ;  8
  Status.s              ;  9
  Received_date.s       ; 10
  BK.s                  ; 11
  EMR.s                 ; 12
  Latitude.s            ; 13
  Longitude.s           ; 14
  Altitude.s            ; 15
  SSID.s                ; 16
  D_PRS_Symbol.s        ; 17
  Course.s              ; 18
  Speed.s               ; 19
  Power.s               ; 20
  Height.s              ; 21
  Gain.s                ; 22
  Directivity.s         ; 23
  Object_Item_Name.s    ; 24
  Data_Type.s           ; 25
  Temperature.s         ; 26
  Rainfall.s            ; 27
  Rainfall_24_Hours.s   ; 28
  Rainfall_Midnight.s   ; 29
  Wind_Direction.s      ; 20
  Wind_Speed.s          ; 21
  Gust_Speed.s          ; 22
  Barometric.s          ; 23
  Humidity.s            ; 24
  GPS_Time_Stamp.s      ; 25
  GPS_Message.s         ; 26
EndStructure

; 

Global Program.ProgramData                                                                          ; Main program structure
Global NewList CallsignList.s()                                                                    ; List of callsigns on the left
Global NewList MasterLog.MasterlogData()                                                           ; Master memory log file

; 

Program\CurrentDirectory    = GetCurrentDirectory()
Program\InitialisationFile  = Program\CurrentDirectory  + "ID-51 log parser.config"
Program\MasterLogFileName   = Program\CurrentDirectory  + "ID-51 master log file"

; Setup the search box cue fonts

Program\SearchCueFont       = LoadFont(#PB_Any,   "Georgia",       10, #PB_Font_Italic)             ; Empty search cue font
Program\SearchNormalFont    = LoadFont(#PB_Any,   "Comic Sans MS", 10, 0)                           ; Filled cue box font
Program\SearchCueText       = Space(256)                                                            ; Set the cue text buffer

PokeS(@Program\SearchCueText, "Search string here...", -1, #PB_Unicode)                             ; Fill the buffer with the cue text

; 

Enumeration #GadgetIndex
  #Shortcut_ID51LogLister_SearchCalsigns
EndEnumeration

Declare   SetInfoBarArea(FieldName.s, FieldStatus.s, MessageContent.s = "0", ModuleName.s = #EmptyString)     ; 
Declare   CreateConfigFile()                                                                                  ; 
Declare   LoadConfigFile()                                                                                    ; 
Declare   SaveConfigFile()                                                                                    ; 
Declare   CheckDuplicateCallsign(CallSign.s)                                                                  ; 
Declare   ProcessLogFiles()                                                                                   ; 
Declare   ProcessCurrentLogFile(LogFileNames.s)                                                               ; 
Declare   ReadFileHeadings(LogFileNames.s)                                                                    ; 
Declare   SortCallSignList()                                                                                  ; 
Declare   ExportMasterLogFile()                                                                               ; 
Declare   GetCallsignLog()                                                                                    ; 
Declare   SearchCallsignLog()                                                                                 ; 

; Send messages and error reports to the fake status bar area

Procedure SetInfoBarArea(FieldName.s, FieldStatus.s, MessageContent.s = "0", ModuleName.s = #EmptyString)
  ; Take care of any orphan routines that might want to send status messages here
  If IsWindow(#Window_ID51LogLister)
    ; Select the name of the field to put our heading string
    Select FieldName.s
      ; Select the correct heading by the status field
      Case "Headings"
        ; 
        Select FieldStatus.s
          Case "Welcome"
            MessageHeader.s = "Welcome!"
            Colour.i        = $0000FF
          Case "Info"
            MessageHeader.s = "Information"
            Colour.i        = $000000
          Case "Warn"
            MessageHeader.s = "Warning"
            Colour.i        = $7D1F82
          Case "Error"
            MessageHeader.s = "Error"
            Colour.i        = $0402FB
        EndSelect
        ; Send all the strings to the fake status bar area
        If ModuleName.s <> #EmptyString
          SetGadgetText(#Gadget_ID51LogLister_Messages, MessageHeader.s + ": "  + MessageContent.s  + " ::" + ModuleName.s  + "::")
        Else
          SetGadgetText(#Gadget_ID51LogLister_Messages, MessageHeader.s + ": "  + MessageContent.s)
        EndIf
        ; 
      Case "Record"
        ; 
        SetGadgetText(#Gadget_ID51LogLister_Current, "Call: " + MessageContent.s)
        ; 
      Case "Callsigns"
        ; Figure out the correct spelling for the record field for singles or multiples
        If Val(MessageContent.s) = 0
          RecordHeader.s = "Records"
        ElseIf Val(MessageContent.s) = 1
          RecordHeader.s = "Record"
        ElseIf Val(MessageContent.s) >= 2
          RecordHeader.s = "Records"
        EndIf
        ; Set the record number details in the fake status bar area
        SetGadgetText(#Gadget_ID51LogLister_Lines, MessageContent.s + " " + RecordHeader.s)
        ; 
    EndSelect
    ; 
  EndIf
  ; 
EndProcedure

; 

Procedure CreateConfigFile()
  ; 
  CreatePreferences(Program\InitialisationFile, #PB_Preference_GroupSeparator)                    ;
  ; 
  PreferenceComment(" ")                                                                          ; 
  PreferenceComment("----------------------------------------------------------")                 ; 
  PreferenceGroup("Program Options")                                                              ; 
  PreferenceComment("----------------------------------------------------------")                 ; 
  PreferenceComment(" ")                                                                          ; 
  WritePreferenceString("Csv directory",  "")                                                     ; 
  WritePreferenceString("Caller Mask",    "")                                                     ; 
  PreferenceComment(" ")                                                                          ; 
  ; 
  ClosePreferences()                                                                              ;
  ; 
EndProcedure

; 

Procedure LoadConfigFile()
  ; If the INI file doesn't exist, create a default one
  If FileSize(Program\InitialisationFile) = #FileNotFound                                         ; 
    CreateConfigFile()                                                                            ; 
  EndIf                                                                                           ; 
  ; 
  OpenPreferences(Program\InitialisationFile, #PB_Preference_GroupSeparator)                      ; 
  ; 
  PreferenceGroup("Program Options")                                                              ; 
  ; Main details
  Program\CsvDirectory  = ReadPreferenceString("Csv directory", "")                               ; 
  Program\CallerMask    = ReadPreferenceString("Caller Mask",   "")                               ; 
  ; 
  ClosePreferences()                                                                              ; 
  ; 
EndProcedure

; 

Procedure SaveConfigFile()
  ; Main details
  Program\CsvDirectory  = GetGadgetText(#Gadget_ID51LogLister_Directory)                           ;
  Program\CallerMask    = GetGadgetText(#Gadget_ID51LogLister_Searchmask)                          ; 
  ; 
  OpenPreferences(Program\InitialisationFile, #PB_Preference_GroupSeparator)                       ; 
  ;
  PreferenceGroup("Program Options")                                                               ; 
  ; 
  WritePreferenceString("Csv directory",  Program\CsvDirectory)                                    ; 
  WritePreferenceString("Caller Mask",    Program\CallerMask)                                      ; 
  ; 
  ClosePreferences()                                                                               ;
  ; 
EndProcedure

; 

Procedure CheckDuplicateCallsign(CallSign.s)
  ; Don't let wasteful entries clog up the callsigns list firstly
  If CallSign.s <> "" And CallSign.s <> "Caller" And CallSign.s <> "Called" And CallSign.s <> "       I"
    ; Set a flag if the passed callsign already exists in the list
    ForEach CallsignList.s()
      If CallsignList.s() = CallSign.s
        FoundFlag.i = #True
      EndIf
    Next
    ; If the passed callsign doesn't exist in the list. add it in to the list
    If FoundFlag.i = #False
      AddElement(CallsignList.s())
      CallsignList.s() = CallSign.s
      AddGadgetItem(#Gadget_ID51LogLister_Callsigns, #AtTheEndOfTheList, CallSign.s)
    EndIf
    ; 
  EndIf
  ; 
EndProcedure

; Read the list headings from the first log file

Procedure ProcessLogFiles()
  ; 
  Pattern.s       = "Csv (*.csv)|*.csv"
  Position.i      = 0
  LogFileNames.s  = OpenFileRequester("Provide CSV logfile names", Program\CsvDirectory, Pattern.s, Position.i, #PB_Requester_MultiSelection)
  ; 
  If LogFileNames.s <> #EmptyString
    ; 
    FirstFile.i = #False
    ; 
    While LogFileNames.s
      ; Check if the first log file has been processed for headings
      If FirstFile.i = #False
        ; Read the list headings from the first log file and then setup the list with those headings
        ReadFileHeadings(LogFileNames.s)
        ; Set a flag to insure that we don't process any other file for headings
        FirstFile.i = #True
        ; 
      EndIf
      ; Processes the current log file for data
      ProcessCurrentLogFile(LogFileNames.s)
      ; Get the next log file name
      LogFileNames.s = NextSelectedFileName() 
      ; 
    Wend 
    ; 
    SetInfoBarArea("Headings", "Info", "All selected log files have been loaded into memory", "ProcessLogFiles")
    ; 
    If CountGadgetItems(#Gadget_ID51LogLister_Callsigns) <> 0
      ; 
      SortCallSignList()
      ; 
      SetGadgetState(#Gadget_ID51LogLister_Callsigns, 0)
      ; 
      PostEvent(#PB_Event_Gadget, #Window_ID51LogLister, #Gadget_ID51LogLister_Callsigns, #PB_EventType_Change)
      ; 
    EndIf
    ; 
  Else
    SetInfoBarArea("Headings", "Warn", "User provided no filenames to process", "ProcessLogFiles")
  EndIf
  ; 
EndProcedure

; 

Procedure ProcessCurrentLogFile(LogFileNames.s)
  ; 
  CurrentFileName.i = ReadFile(#PB_Any, LogFileNames.s)
  ; 
  If CurrentFileName.i
    ; 
    While Eof(CurrentFileName.i) = 0
      ; 
      CurrentLine.s = ReadString(CurrentFileName.i)
      ; Check 'Called' and 'Caller' fields to prevent duplicate callsigns in the list
      CheckDuplicateCallsign(StringField(CurrentLine.s, 3, ","))
      CheckDuplicateCallsign(StringField(CurrentLine.s, 5, ","))
      ; Prevent headers and empty fields to litter the log file (repeater messages etc)
      If StringField(CurrentLine.s,  1, ",") <> "Frequency" And StringField(CurrentLine.s,  3, ",") <> "" And StringField(CurrentLine.s,  4, ",") <> "LMSG" And StringField(CurrentLine.s,  4, ",") <> "RPTR"
        ; 
        AddElement(MasterLog())
        ; 
        MasterLog()\Frequency           = StringField(CurrentLine.s,  1, ",")
        MasterLog()\Mode                = StringField(CurrentLine.s,  2, ",")
        MasterLog()\Caller              = StringField(CurrentLine.s,  3, ",")
        MasterLog()\Slash               = StringField(CurrentLine.s,  4, ",")
        MasterLog()\Called              = StringField(CurrentLine.s,  5, ",")
        MasterLog()\Rx_RPT1             = StringField(CurrentLine.s,  6, ",")
        MasterLog()\Rx_RPT2             = StringField(CurrentLine.s,  7, ",")
        MasterLog()\Message             = StringField(CurrentLine.s,  8, ",")
        MasterLog()\Status              = StringField(CurrentLine.s,  9, ",")
        MasterLog()\Received_date       = StringField(CurrentLine.s, 10, ",")
        MasterLog()\BK                  = StringField(CurrentLine.s, 11, ",")
        MasterLog()\EMR                 = StringField(CurrentLine.s, 12, ",")
        MasterLog()\Latitude            = StringField(CurrentLine.s, 13, ",")
        MasterLog()\Longitude           = StringField(CurrentLine.s, 14, ",")
        MasterLog()\Altitude            = StringField(CurrentLine.s, 15, ",")
        MasterLog()\SSID                = StringField(CurrentLine.s, 16, ",")
        MasterLog()\D_PRS_Symbol        = StringField(CurrentLine.s, 17, ",")
        MasterLog()\Course              = StringField(CurrentLine.s, 18, ",")
        MasterLog()\Speed               = StringField(CurrentLine.s, 19, ",")
        MasterLog()\Power               = StringField(CurrentLine.s, 20, ",")
        MasterLog()\Height              = StringField(CurrentLine.s, 21, ",")
        MasterLog()\Gain                = StringField(CurrentLine.s, 22, ",")
        MasterLog()\Directivity         = StringField(CurrentLine.s, 23, ",")
        MasterLog()\Object_Item_Name    = StringField(CurrentLine.s, 24, ",")
        MasterLog()\Data_Type           = StringField(CurrentLine.s, 25, ",")
        MasterLog()\Temperature         = StringField(CurrentLine.s, 26, ",")
        MasterLog()\Rainfall            = StringField(CurrentLine.s, 27, ",")
        MasterLog()\Rainfall_24_Hours   = StringField(CurrentLine.s, 28, ",")
        MasterLog()\Rainfall_Midnight   = StringField(CurrentLine.s, 29, ",")
        MasterLog()\Wind_Direction      = StringField(CurrentLine.s, 30, ",")
        MasterLog()\Wind_Speed          = StringField(CurrentLine.s, 31, ",")
        MasterLog()\Gust_Speed          = StringField(CurrentLine.s, 32, ",")
        MasterLog()\Barometric          = StringField(CurrentLine.s, 33, ",")
        MasterLog()\Humidity            = StringField(CurrentLine.s, 34, ",")
        MasterLog()\GPS_Time_Stamp      = StringField(CurrentLine.s, 35, ",")
        MasterLog()\GPS_Message         = StringField(CurrentLine.s, 36, ",")
        ; 
        CurrentLine.s = ""
        ; 
      EndIf
      ; 
    Wend
    ; 
    CloseFile(CurrentFileName.i)
    ; 
  Else
    SetInfoBarArea("Headings", "Warn", "The current filename could not be processed", "ProcessCurrentLogFile")
  EndIf
  ; 
EndProcedure

; 

Procedure ReadFileHeadings(FirstFileName.s)
  ; 
  TestFileHandle.i = ReadFile(#PB_Any, FirstFileName.s)
  ; 
  If TestFileHandle.i <> #NoFileHandle
    ; 
    TestLine.s = ReadString(TestFileHandle.i)
    ; 
    If TestLine.s <> #EmptyString
      ; 
      Program\ListColumns = CountString(TestLine.s, ",")
      ; 
      If Program\ListColumns <> #NoColumnsFound
        ; 
        For ColumnStart.i = 0 To Program\ListColumns
          ColumnName.s = StringField(TestLine.s, ColumnStart.i + 1, ",")
          AddGadgetColumn(#Gadget_ID51LogLister_lLoglist, ColumnStart.i, ColumnName.s, Len(ColumnName.s) * 10)
        Next ColumnStart.i
        ; 
      Else
        SetInfoBarArea("Headings", "Warn", "No columns of data found in the data file", "ReadFileHeadings")
      EndIf
      ; 
    Else
      SetInfoBarArea("Headings", "Warn", "No string of data found on that line", "ReadFileHeadings")
    EndIf
    ; 
    CloseFile(TestFileHandle.i)
    ; 
  Else
    SetInfoBarArea("Headings", "Warn", "No file handle found", "ReadFileHeadings")
  EndIf
  ; 
EndProcedure

; Sort ListIconGadget as you need it. Based on Reg Venaglia's routine.

Procedure SortCallSignList()
  ; Get number items in ListIcon
  NumberOfItems.i = CountGadgetItems(#Gadget_ID51LogLister_Callsigns)
  ; Get number items in ListIcon. That is standard categories + two others
  If NumberOfItems.i <> #False
    ; Get number items in ListIcon
    NewList CallSignSort.s()
    ; Place each item text into the list. Must start at Zero
    For LoopCounter.i = 0 To NumberOfItems.i - 1
      AddElement(CallSignSort())
      CallSignSort() = GetGadgetItemText(#Gadget_ID51LogLister_Callsigns, LoopCounter.i, 0)
    Next LoopCounter 
    ; Sort the Array in ascending order
    SortList(CallSignSort(), #PB_Sort_Ascending | #PB_Sort_NoCase)
    ; Now replace ListIcon Items from the sorted Array
    ForEach CallSignSort()
      SetGadgetItemText(#Gadget_ID51LogLister_Callsigns, ListIndex(CallSignSort()), CallSignSort(), 0)
    Next CallSignSort()
    ; 
    ClearList(CallSignSort())
    ; 
  EndIf
  ; 
EndProcedure

; 

Procedure ExportMasterLogFile()
  ; 
  SortStructuredList(Masterlog(), #PB_Sort_Ascending | #PB_Sort_NoCase, OffsetOf(MasterLogData\Caller), TypeOf(MasterLogData\Caller))
  ; 
  MasterLogFile.i   = CreateFile(#PB_Any, Program\MasterLogFileName + ".LOG")                      ; : Debug "Created master output file:  "     + Str(MasterLogFile.i)
  ; 
  If MasterLogFile.i <> 0
    ; 
    ForEach (MasterLog.s())
      WriteString(MasterLogFile.i,  MasterLog()\Frequency          + ",")
      WriteString(MasterLogFile.i,  MasterLog()\Mode               + ",")
      WriteString(MasterLogFile.i,  MasterLog()\Caller             + ",")
      WriteString(MasterLogFile.i,  MasterLog()\Slash              + ",")
      WriteString(MasterLogFile.i,  MasterLog()\Called             + ",")
      WriteString(MasterLogFile.i,  MasterLog()\Rx_RPT1            + ",")
      WriteString(MasterLogFile.i,  MasterLog()\Rx_RPT2            + ",")
      WriteString(MasterLogFile.i,  MasterLog()\Message            + ",")
      WriteString(MasterLogFile.i,  MasterLog()\Status             + ",")
      WriteString(MasterLogFile.i,  MasterLog()\Received_date      + ",")
      WriteString(MasterLogFile.i,  MasterLog()\BK                 + ",")
      WriteString(MasterLogFile.i,  MasterLog()\EMR                + ",")
      WriteString(MasterLogFile.i,  MasterLog()\Latitude           + ",")
      WriteString(MasterLogFile.i,  MasterLog()\Longitude          + ",")
      WriteString(MasterLogFile.i,  MasterLog()\Altitude           + ",")
      WriteString(MasterLogFile.i,  MasterLog()\SSID               + ",")
      WriteString(MasterLogFile.i,  MasterLog()\D_PRS_Symbol       + ",")
      WriteString(MasterLogFile.i,  MasterLog()\Course             + ",")
      WriteString(MasterLogFile.i,  MasterLog()\Speed              + ",")
      WriteString(MasterLogFile.i,  MasterLog()\Power              + ",")
      WriteString(MasterLogFile.i,  MasterLog()\Height             + ",")
      WriteString(MasterLogFile.i,  MasterLog()\Gain               + ",")
      WriteString(MasterLogFile.i,  MasterLog()\Directivity        + ",")
      WriteString(MasterLogFile.i,  MasterLog()\Object_Item_Name   + ",")
      WriteString(MasterLogFile.i,  MasterLog()\Data_Type          + ",")
      WriteString(MasterLogFile.i,  MasterLog()\Temperature        + ",")
      WriteString(MasterLogFile.i,  MasterLog()\Rainfall           + ",")
      WriteString(MasterLogFile.i,  MasterLog()\Rainfall_24_Hours  + ",")
      WriteString(MasterLogFile.i,  MasterLog()\Rainfall_Midnight  + ",")
      WriteString(MasterLogFile.i,  MasterLog()\Wind_Direction     + ",")
      WriteString(MasterLogFile.i,  MasterLog()\Wind_Speed         + ",")
      WriteString(MasterLogFile.i,  MasterLog()\Gust_Speed         + ",")
      WriteString(MasterLogFile.i,  MasterLog()\Barometric         + ",")
      WriteString(MasterLogFile.i,  MasterLog()\Humidity           + ",")
      WriteString(MasterLogFile.i,  MasterLog()\GPS_Time_Stamp     + ",")
      WriteStringN(MasterLogFile.i, MasterLog()\GPS_Message)
    Next
    ; 
    CloseFile(MasterLogFile.i)
    ; Create a JSON dump file
    JSONHandle.i = CreateJSON(#PB_Any)
    If JSONHandle.i
      JSONDataType.i = JSONValue(JSONHandle.i)
      If JSONDataType.i
        InsertJSONList(JSONDataType.i, MasterLog())
        SaveJSON(JSONHandle.i, Program\MasterLogFileName  + ".JSON")
      EndIf
      FreeJSON(JSONHandle.i)
    EndIf    
    ; Create a XML dump file
    XMLFileHandle.i = CreateXML(#PB_Any)
    If XMLFileHandle.i
      InsertXMLList(RootXMLNode(XMLFileHandle.i), MasterLog())
      FormatXML(XMLFileHandle.i, #PB_XML_ReFormat)
      ; Debug ComposeXML(XMLFileHandle.i)
      SaveXML(XMLFileHandle.i, Program\MasterLogFileName  + ".XML")
      FreeXML(XMLFileHandle.i)
    EndIf
    ; 
    SetInfoBarArea("Headings", "Info", "Master log file created in program directory", "ExportMasterLogFile")
    ; 
  Else
    SetInfoBarArea("Headings", "Warn", "Could not create the master log file", "ExportMasterLogFile")
  EndIf
  ; 
EndProcedure

; 

Procedure SearchCallsignLog()
  ; 
  If ListSize(MasterLog.s())
    ; 
    CurrentText.s = GetGadgetText(#Gadget_ID51LogLister_Searchbox)
    CallerMask.s  = GetGadgetText(#Gadget_ID51LogLister_Searchmask)
    ; 
    If CurrentText.s <> ""
      ; 
      ClearGadgetItems(#Gadget_ID51LogLister_lLoglist)
      ; 
      SetGadgetText(#Gadget_ID51LogLister_Searchbox, "")
      ; 
      ForEach MasterLog.s()
        ; 
        If FindString(MasterLog()\Frequency,          CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf
        If FindString(MasterLog()\Mode,               CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf
        If FindString(MasterLog()\Caller,             CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf
        If FindString(MasterLog()\Slash ,             CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf
        If FindString(MasterLog()\Called,             CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf
        If FindString(MasterLog()\Rx_RPT1,            CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf
        If FindString(MasterLog()\Rx_RPT2,            CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf
        If FindString(MasterLog()\Message,            CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf
        If FindString(MasterLog()\Status,             CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf
        If FindString(MasterLog()\Received_date,      CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf 
        If FindString(MasterLog()\BK,                 CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf 
        If FindString(MasterLog()\EMR,                CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf 
        If FindString(MasterLog()\Latitude,           CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf 
        If FindString(MasterLog()\Longitude,          CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf 
        If FindString(MasterLog()\Altitude,           CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf 
        If FindString(MasterLog()\SSID,               CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf 
        If FindString(MasterLog()\D_PRS_Symbol,       CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf 
        If FindString(MasterLog()\Course,             CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf 
        If FindString(MasterLog()\Speed ,             CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf 
        If FindString(MasterLog()\Power ,             CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf 
        If FindString(MasterLog()\Height,             CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf 
        If FindString(MasterLog()\Gain,               CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf 
        If FindString(MasterLog()\Directivity,        CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf 
        If FindString(MasterLog()\Object_Item_Name,   CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf 
        If FindString(MasterLog()\Data_Type,          CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf 
        If FindString(MasterLog()\Temperature,        CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf 
        If FindString(MasterLog()\Rainfall,           CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf 
        If FindString(MasterLog()\Rainfall_24_Hours,  CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf 
        If FindString(MasterLog()\Rainfall_Midnight,  CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf 
        If FindString(MasterLog()\Wind_Direction,     CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf 
        If FindString(MasterLog()\Wind_Speed,         CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf 
        If FindString(MasterLog()\Gust_Speed,         CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf 
        If FindString(MasterLog()\Barometric,         CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf 
        If FindString(MasterLog()\Humidity,           CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf 
        If FindString(MasterLog()\GPS_Time_Stamp,     CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf 
        If FindString(MasterLog()\GPS_Message,        CurrentText.s, 1, #PB_String_NoCase) <> #StringNotFound : StringFound.i = #False : EndIf 
        ; Don't add searches from your local access repeater (FROM field in your radio)
        If CallerMask.s = #EmptyString And StringFound.i = #False
          ; 
          AddGadgetItem(#Gadget_ID51LogLister_lLoglist, #AtTheEndOfTheList, 
          ;               
          MasterLog()\Frequency         + #LF$ + 
          MasterLog()\Mode              + #LF$ + 
          MasterLog()\Caller            + #LF$ + 
          MasterLog()\Slash             + #LF$ + 
          MasterLog()\Called            + #LF$ + 
          MasterLog()\Rx_RPT1           + #LF$ + 
          MasterLog()\Rx_RPT2           + #LF$ + 
          MasterLog()\Message           + #LF$ + 
          MasterLog()\Status            + #LF$ + 
          MasterLog()\Received_date     + #LF$ + 
          MasterLog()\BK                + #LF$ + 
          MasterLog()\EMR               + #LF$ + 
          MasterLog()\Latitude          + #LF$ + 
          MasterLog()\Longitude         + #LF$ + 
          MasterLog()\Altitude          + #LF$ + 
          MasterLog()\SSID              + #LF$ + 
          MasterLog()\D_PRS_Symbol      + #LF$ + 
          MasterLog()\Course            + #LF$ + 
          MasterLog()\Speed             + #LF$ + 
          MasterLog()\Power             + #LF$ + 
          MasterLog()\Height            + #LF$ + 
          MasterLog()\Gain              + #LF$ + 
          MasterLog()\Directivity       + #LF$ + 
          MasterLog()\Object_Item_Name  + #LF$ + 
          MasterLog()\Data_Type         + #LF$ + 
          MasterLog()\Temperature       + #LF$ + 
          MasterLog()\Rainfall          + #LF$ + 
          MasterLog()\Rainfall_24_Hours + #LF$ + 
          MasterLog()\Rainfall_Midnight + #LF$ + 
          MasterLog()\Wind_Direction    + #LF$ + 
          MasterLog()\Wind_Speed        + #LF$ + 
          MasterLog()\Gust_Speed        + #LF$ + 
          MasterLog()\Barometric        + #LF$ + 
          MasterLog()\Humidity          + #LF$ + 
          MasterLog()\GPS_Time_Stamp    + #LF$ + 
          MasterLog()\GPS_Message)
          ; 
        ElseIf CallerMask.s <> #EmptyString And StringFound.i = #False
          ; 
          If MasterLog()\Caller <> CallerMask.s And MasterLog()\Called <> CallerMask.s
            ; 
            AddGadgetItem(#Gadget_ID51LogLister_lLoglist, #AtTheEndOfTheList,
            ;               
            MasterLog()\Frequency         + #LF$ + 
            MasterLog()\Mode              + #LF$ + 
            MasterLog()\Caller            + #LF$ + 
            MasterLog()\Slash             + #LF$ + 
            MasterLog()\Called            + #LF$ + 
            MasterLog()\Rx_RPT1           + #LF$ + 
            MasterLog()\Rx_RPT2           + #LF$ + 
            MasterLog()\Message           + #LF$ + 
            MasterLog()\Status            + #LF$ + 
            MasterLog()\Received_date     + #LF$ + 
            MasterLog()\BK                + #LF$ + 
            MasterLog()\EMR               + #LF$ + 
            MasterLog()\Latitude          + #LF$ + 
            MasterLog()\Longitude         + #LF$ + 
            MasterLog()\Altitude          + #LF$ + 
            MasterLog()\SSID              + #LF$ + 
            MasterLog()\D_PRS_Symbol      + #LF$ + 
            MasterLog()\Course            + #LF$ + 
            MasterLog()\Speed             + #LF$ + 
            MasterLog()\Power             + #LF$ + 
            MasterLog()\Height            + #LF$ + 
            MasterLog()\Gain              + #LF$ + 
            MasterLog()\Directivity       + #LF$ + 
            MasterLog()\Object_Item_Name  + #LF$ + 
            MasterLog()\Data_Type         + #LF$ + 
            MasterLog()\Temperature       + #LF$ + 
            MasterLog()\Rainfall          + #LF$ + 
            MasterLog()\Rainfall_24_Hours + #LF$ + 
            MasterLog()\Rainfall_Midnight + #LF$ + 
            MasterLog()\Wind_Direction    + #LF$ + 
            MasterLog()\Wind_Speed        + #LF$ + 
            MasterLog()\Gust_Speed        + #LF$ + 
            MasterLog()\Barometric        + #LF$ + 
            MasterLog()\Humidity          + #LF$ + 
            MasterLog()\GPS_Time_Stamp    + #LF$ + 
            MasterLog()\GPS_Message)
          EndIf
        EndIf
        StringFound.i = #False
      Next
      ; 
      For WidthSet.i = 0 To Program\ListColumns - 1
        SendMessage_(GadgetID(#Gadget_ID51LogLister_lLoglist), #LVM_SETCOLUMNWIDTH, WidthSet.i, #LVSCW_AUTOSIZE)
      Next WidthSet.i
      ; 
      SetInfoBarArea("Headings", "Info", "Finished resizing columns to fit data", "SearchCallsignLog")
      SetInfoBarArea("Callsigns", "",         Str(CountGadgetItems(#Gadget_ID51LogLister_lLoglist)),  "MainMenu")
      ; 
    Else
      SetInfoBarArea("Headings", "Warn", "User entered no data to search for", "SearchCallsignLog")
    EndIf
    ; 
  Else
    SetInfoBarArea("Headings", "Error", "Nothing loaded in memory to search through", "SearchCallsignLog")
  EndIf
  ; 
EndProcedure

; 

Procedure ShowEntriesForCallsign()
  ; 
  CurrentLine.i = GetGadgetState(#Gadget_ID51LogLister_Callsigns)
  ; 
  If CurrentLine.i <> #NoCurrentLine
    ; 
    ClearGadgetItems(#Gadget_ID51LogLister_lLoglist)
    ; 
    CurrentCallsign.s = GetGadgetItemText(#Gadget_ID51LogLister_Callsigns, CurrentLine.i, 0)
    ; 
    SetInfoBarArea("Record", "",  CurrentCallsign.s, "GetCallsignLog")
    ; 
    ForEach MasterLog.s()
      If MasterLog()\Caller = CurrentCallsign.s Or MasterLog()\Called = CurrentCallsign.s
        AddGadgetItem(#Gadget_ID51LogLister_lLoglist, #AtTheEndOfTheList,
        MasterLog()\Frequency         + #LF$ + 
        MasterLog()\Mode              + #LF$ + 
        MasterLog()\Caller            + #LF$ + 
        MasterLog()\Slash             + #LF$ + 
        MasterLog()\Called            + #LF$ + 
        MasterLog()\Rx_RPT1           + #LF$ + 
        MasterLog()\Rx_RPT2           + #LF$ + 
        MasterLog()\Message           + #LF$ + 
        MasterLog()\Status            + #LF$ + 
        MasterLog()\Received_date     + #LF$ + 
        MasterLog()\BK                + #LF$ + 
        MasterLog()\EMR               + #LF$ + 
        MasterLog()\Latitude          + #LF$ + 
        MasterLog()\Longitude         + #LF$ + 
        MasterLog()\Altitude          + #LF$ + 
        MasterLog()\SSID              + #LF$ + 
        MasterLog()\D_PRS_Symbol      + #LF$ + 
        MasterLog()\Course            + #LF$ + 
        MasterLog()\Speed             + #LF$ + 
        MasterLog()\Power             + #LF$ + 
        MasterLog()\Height            + #LF$ + 
        MasterLog()\Gain              + #LF$ + 
        MasterLog()\Directivity       + #LF$ + 
        MasterLog()\Object_Item_Name  + #LF$ + 
        MasterLog()\Data_Type         + #LF$ + 
        MasterLog()\Temperature       + #LF$ + 
        MasterLog()\Rainfall          + #LF$ + 
        MasterLog()\Rainfall_24_Hours + #LF$ + 
        MasterLog()\Rainfall_Midnight + #LF$ + 
        MasterLog()\Wind_Direction    + #LF$ + 
        MasterLog()\Wind_Speed        + #LF$ + 
        MasterLog()\Gust_Speed        + #LF$ + 
        MasterLog()\Barometric        + #LF$ + 
        MasterLog()\Humidity          + #LF$ + 
        MasterLog()\GPS_Time_Stamp    + #LF$ + 
        MasterLog()\GPS_Message)
      EndIf
    Next
    ; 
    For WidthSet.i = 0 To Program\ListColumns - 1
      SendMessage_(GadgetID(#Gadget_ID51LogLister_lLoglist), #LVM_SETCOLUMNWIDTH, WidthSet.i, #LVSCW_AUTOSIZE)
    Next WidthSet.i
    ; 
    SetInfoBarArea("Headings", "Info", "Finished resizing columns to fit Data", "GetCallsignLog")
    SetInfoBarArea("Callsigns", "",         Str(CountGadgetItems(#Gadget_ID51LogLister_lLoglist)),  "GetCallsignLog")
    ; 
  Else
    SetInfoBarArea("Headings", "Warn", "Nothing to resize, no data found", "GetCallsignLog")
  EndIf
  ; 
EndProcedure

; 

If Window_ID51LogLister()
  ; Program quit semaphore is initialised
  Program\QuitValue = #False
  ; Add a keyboard shortcut for the search box
  AddKeyboardShortcut(#Window_ID51LogLister, #PB_Shortcut_Return, #Shortcut_ID51LogLister_SearchCalsigns)
  ; Remove the empty column from the details list
  RemoveGadgetColumn(#Gadget_ID51LogLister_lLoglist, 0)
  ; Load the directory configuration file
  LoadConfigFile()
  ; 
  If Program\CsvDirectory = #EmptyString                                                           ; 
    Program\CsvDirectory  = PathRequester("CSV log path", "")                                      ; 
    SetGadgetText(#Gadget_ID51LogLister_Directory, Program\CsvDirectory)                           ;
  Else                                                                                             ; 
    SetGadgetText(#Gadget_ID51LogLister_Directory, Program\CsvDirectory)                           ;
  EndIf                                                                                            ; 
  ; 
  SetGadgetText(#Gadget_ID51LogLister_Searchmask, Program\CallerMask)                              ; 
  ; Limit the number of search box characters and set the cue banner text. These variables are set
  ; in the Keeper_Myconstants file.
  SendMessage_(GadgetID(#Gadget_ID51LogLister_Searchbox), #EM_SETLIMITTEXT, 67, 0)
  SendMessage_(GadgetID(#Gadget_ID51LogLister_Searchbox), #EM_SETCUEBANNER,  1,  Program\SearchCueText)
  ; Set initial search cue font
  SetGadgetFont(#Gadget_ID51LogLister_Searchbox, FontID(Program\SearchCueFont))
  ; Give the startup message and callsign count
  SetInfoBarArea("Headings",  "Welcome",  "ID-51 log parser startup",                             "MainMenu")
  SetInfoBarArea("Record",    "",         "?",                                                    "MainMenu")
  SetInfoBarArea("Callsigns", "",         Str(CountGadgetItems(#Gadget_ID51LogLister_lLoglist)),  "MainMenu")
  ; Set focus on the search bar
  SetActiveGadget(#Gadget_ID51LogLister_Searchbox)  
  ; Main event handler
  Repeat
    ; 
    EventID  = WaitWindowEvent()
    MenuID   = EventMenu()
    GadgetID = EventGadget()
    WindowID = EventWindow()
    ; 
    Select EventID
      ; 
      Case #PB_Event_CloseWindow
        Select WindowID
          Case #Window_ID51LogLister                  : Program\QuitValue = #True
        EndSelect
        ; 
      Case #PB_Event_Menu
        Select MenuID
          Case #MenuBar_ID51LogLister_Setdirectory    : SaveConfigFile()
          Case #MenuBar_ID51LogLister_Getlogfiles     : ProcessLogFiles()
          Case #MenuBar_ID51LogLister_Savemasterlog   : ExportMasterLogFile()
          Case #MenuBar_ID51LogLister_Exitprogram     : Program\QuitValue = #True
          Case #Shortcut_ID51LogLister_SearchCalsigns : If GetActiveGadget() = #Gadget_ID51LogLister_Searchbox : SearchCallsignLog() : EndIf
        EndSelect
        ; 
      Case #PB_Event_Gadget
        Select GadgetID
          Case #Gadget_ID51LogLister_Callsigns
            Select EventType()
              Case #PB_EventType_Change               : ShowEntriesForCallsign()
            EndSelect
          Case #Gadget_ID51LogLister_lLoglist
            Select EventType()
              Case #PB_EventType_Change               : 
            EndSelect
          Case #Gadget_ID51LogLister_Searchbox
            Select EventType()
              Case #PB_EventType_Change
              If GetGadgetText(#Gadget_ID51LogLister_Searchbox) = ""
                SetGadgetFont(#Gadget_ID51LogLister_Searchbox, FontID(Program\SearchCueFont))
              Else
                SetGadgetFont(#Gadget_ID51LogLister_Searchbox, FontID(Program\SearchNormalFont))
              EndIf
            EndSelect
          Case #Gadget_ID51LogLister_Setdirectory     : SaveConfigFile()
          Case #Gadget_ID51LogLister_Getlogfiles      : ProcessLogFiles()
          Case #Gadget_ID51LogLister_Savemasterlog    : ExportMasterLogFile()
          Case #Gadget_ID51LogLister_ExitProgram      : Program\QuitValue = #True
        EndSelect
        ; 
    EndSelect
    ; 
  Until Program\QuitValue
  ; 
  SaveConfigFile()
  ; 
  CloseWindow(#Window_ID51LogLister)
  ; 
EndIf
; 
End
Amateur Radio/VK3HAF, (D-STAR/DMR and more), Arduino, ESP32, Coding, Crochet
Post Reply