NQAFM (or, Not Quite File Manager)

Share your advanced PureBasic knowledge/code with the community.
User avatar
Fangbeast
PureBasic Protozoa
PureBasic Protozoa
Posts: 4789
Joined: Fri Apr 25, 2003 3:08 pm
Location: Not Sydney!!! (Bad water, no goats)

NQAFM (or, Not Quite File Manager)

Post by Fangbeast »

Updated for version 5.20

I need to combine my incredimail cataloguer with some file management aspects of WIndows Explorer so I have been fiddling for weeks.

The below is the skeleton of a file manager. It:

1. Enumerates all the drives on your system
2. Builds a tree of all your drives and their directories
3. Shows files and attributes for a highlighted directory
4. Launches a file when left double clicked
5. Shows a popup menu on right mouse click in the file list

It has:

1. Pretty blue background for both gadgets
2. Form resizing and gadget resizing with minimum size
3. Custom bubble tooltip
4. Recent filename list

All of this is just a skeleton that I am playing with and many people helped me. Do what you want with it but don't complain to me if it doesn't work as I won't be listening. I am developing it for use in my own applications.

Code: Select all

;============================================================================================================================
; All program constants
;============================================================================================================================

#TV_FIRST                               = $1100             ; API constants for tree and list gadget colouring
#TVM_SETBKCOLOR                         = #TV_FIRST + 29
#TVM_SETTEXTCOLOR                       = #TV_FIRST + 30

#TTS_BALLOON                            =  $40              ; Colourful speech bubble tips

#filepointer                            = 99                ; Filepointer
#MenuRecentFiles                        = 100               ; Start where Entrys are beginning in Menu for Recent files

#ProgramVersion                         = "File Manager"

Global WindowIndex                            = 0                 ; Init all starting gadget type values
Global GadgetIndex                            = 0
Global ImageIndex                             = 0
Global StatusBarIndex                         = 0
Global MenuBarIndex                           = 0

Global Window_fileman                         = WindowIndex    : WindowIndex    = WindowIndex    + 1 ; Main program window starting number
Global MenuBar_fileman                        = MenuBarIndex   : MenuBarIndex   = MenuBarIndex   + 1 ; Main window menu bar

Global Gadget_fileman_fileman                 = GadgetIndex    : GadgetIndex    = GadgetIndex    + 1 ; Main window gadgets
Global Gadget_fileman_dirtree                 = GadgetIndex    : GadgetIndex    = GadgetIndex    + 1
Global Gadget_fileman_filelist                = GadgetIndex    : GadgetIndex    = GadgetIndex    + 1

Global StatusBar_fileman                      = StatusBarIndex : StatusBarIndex = StatusBarIndex + 1 ; Main window status bar
Global StatusBar_fileman_Field1               = 0
Global StatusBar_fileman_Field2               = 1
Global StatusBar_fileman_Field3               = 2
Global StatusBar_fileman_Field4               = 3

Global Icons_folder                           = ImageIndex     : ImageIndex     = ImageIndex     + 1 ; Program incons
Global Icons_drive                            = ImageIndex     : ImageIndex     = ImageIndex     + 1

;============================================================================================================================
; Any needed data structures
;============================================================================================================================

Structure FileInformation
  path.s    ; Full path name
  name.s    ; File name
  size.s    ; File size
  attr.s    ; File attributes
EndStructure

;============================================================================================================================
; ALl procedures pre-declared
;============================================================================================================================

Declare   FindAllDrives()                                             ; Find all local drives attached to system
Declare   ShowAllDrives()                                             ; Show all drive directories in the tree

Declare   FlushEvents()                                               ; Flush any waiting window events to prevent form timeout

Declare   DirScan(DirectoryID.l, DirectoryName.s)                     ; Do the actual recursive tre find routine
Declare   FileScan(FilePath.s)                                        ; Show the contents of a directory selected from the tree
Declare.s GetAttribMask(fattribute.s)                                 ; Get the attributes of all files in the filelist for immediate display

Declare   CustomToolTip(ToolHandle, ToolText.s)                       ; Colourful speech bubble tips

Declare.l ResizeCallback(WindowID.l, Message.l, wParam.l, lParam.l)   ; Form resizing and object colouring

Declare   Recent(NewFilename.s)                                       ; Create and add to the recent list of files
Declare   MakeMenu()                                                  ; Make the system menu and insert the recent files into it

Declare.l Window_fileman()                                            ; Main program window

;============================================================================================================================
; Any needed lists
;============================================================================================================================

Global NewList AllDrives.s()                                                 ; Linked List to hold all drive letters
Global NewList FullPaths.s()                                                 ; Linked List to hold all diretory paths
Global NewList Finfo.FileInformation()                                       ; Linked List to hold temporary file details
Global NewList Files.s()                                                     ; Linked List to hold RecentFiles

;============================================================================================================================
; Any global variables that the program needs
;============================================================================================================================

Global OriginalWidth, OriginalHeight, hStatusBar, OldStatusBarWidth, NewStatusBarWidth, recentfilename.s

;============================================================================================================================
; Initialise the list of recent files
;============================================================================================================================

recentfilename.s = "MyRecentFiles.RFN"                   ; This holds the filename for the recentlist

;============================================================================================================================
; Dimension the number of fields in the status bar that we are going to resize
;============================================================================================================================

Global Dim StatusBarFields.l(3)                                    ; Needed for resize, must be the number of Fields -1 (since it begins at 0)

;============================================================================================================================
; Main program event code
;============================================================================================================================

FindAllDrives()

If Window_fileman()

  
  SetWindowCallback(@ResizeCallback())                      ; Set form resizing and gadget colouring callback

  Recent("")                                                ; Initialise the RecentFiles list
  MakeMenu()                                                ; And generate a menu for it

  ShowAllDrives()

  Repeat
    EventID = WaitWindowEvent()
    ;----------------------------------------------------------------------------------------------
      If EventID = #PB_Event_Menu
      ;--------------------------------------------------------------------------------------------
        If EventMenu() > #MenuRecentFiles And EventMenu() < #MenuRecentFiles + 11
          SelectElement(Files(), EventMenu() - #MenuRecentFiles - 1)
          filenametoopen.s = Files()
          openrecentflag = 1
;          Gosub filenametoopen
        EndIf
        ;------------------------------------------------------------------------------------------
;        Select EventMenuID()
;          Case
;        EndSelect
        ;------------------------------------------------------------------------------------------
      EndIf
      ;--------------------------------------------------------------------------------------------
      If EventID = #PB_Event_Gadget
        Select EventGadget()
          Case Gadget_fileman_dirtree  : Gosub TreeClicked ; An item has been highlighted in the tree
          Case Gadget_fileman_filelist : Gosub ListClicked ; An item has been highlighted or double clicked in the filelist
        EndSelect
      EndIf
    ;----------------------------------------------------------------------------------------------
  Until EventID = #PB_Event_CloseWindow And EventWindow() = Window_fileman
  CloseWindow(Window_fileman)
EndIf

End

;============================================================================================================================
; An item has been highlighted in the tree
;============================================================================================================================

TreeClicked:

  If EventType() = #PB_EventType_LeftClick And GetGadgetState(Gadget_fileman_dirtree) <> -1
    ClearGadgetItemList(Gadget_fileman_filelist)
    CurrentTreeLine = GetGadgetState(Gadget_fileman_dirtree)
    SelectElement(FullPaths(), CurrentTreeLine)
    FileScan(FullPaths())
  EndIf
  
Return

;============================================================================================================================
; An item has been highlighted or double clicked in the filelist
;============================================================================================================================

ListClicked:

  If EventType() = #PB_EventType_LeftDoubleClick And GetGadgetState(Gadget_fileman_filelist) <> -1
    CurrentListLine = GetGadgetState(Gadget_fileman_filelist)
    SelectElement(Finfo(), CurrentListLine)
    RunProgram(Finfo()\Name, "", Finfo()\Path, 0)
  EndIf

  If EventType() = #PB_EventType_RightClick And GetGadgetState(Gadget_fileman_filelist) <> -1
    DisplayPopupMenu(0, WindowID(Window_fileman))
  EndIf

Return

;============================================================================================================================
; All of my procedures
;============================================================================================================================

Procedure.l Window_fileman()
  If OpenWindow(Window_fileman,177,20,800,600, #ProgramVersion,#PB_Window_SystemMenu|#PB_Window_MinimizeGadget|#PB_Window_MaximizeGadget|#PB_Window_SizeGadget|#PB_Window_Invisible)
    ;----------------------------------------------------------------------------------------------
    OriginalWidth     = WindowWidth(Window_fileman)                       ; Original non-client width.
    OriginalHeight    = WindowHeight(Window_fileman)                      ; Original non-client height.
    OldStatusBarWidth = WindowWidth(Window_fileman)                       ; Needed for resizing
    ;----------------------------------------------------------------------------------------------
    MakeMenu()
    ;----------------------------------------------------------------------------------------------
    If CreatePopupMenu(1)
      MenuItem(2, "Sort")
      MenuItem(3, "Sort All")
      MenuItem(4, "Insert")
      MenuItem(5, "Delete")
      MenuItem(6, "Expand All")
      MenuBar()
    EndIf
      Frame3DGadget(Gadget_fileman_fileman,0,0,800,560,"")
      TreeGadget(Gadget_fileman_dirtree,5,10,170,545)
        SendMessage_(GadgetID(Gadget_fileman_dirtree),#TVM_SETBKCOLOR,0,16744448)
        CustomToolTip(GadgetID(Gadget_fileman_dirtree), "Click on any member of the tree to show the corresponding files in the list view")
      ListIconGadget(Gadget_fileman_filelist,178,10,617,545,"FileName",130,#PB_ListIcon_FullRowSelect|#PB_ListIcon_AlwaysShowSelection)
        SendMessage_(GadgetID(Gadget_fileman_filelist),#LVM_SETBKCOLOR,0,16744448)
        SendMessage_(GadgetID(Gadget_fileman_filelist),#LVM_SETTEXTBKCOLOR,0,16744448)
        CustomToolTip(GadgetID(Gadget_fileman_filelist), "Click on any file in this list to view information about it or perform certain actions on it")
        AddGadgetColumn(Gadget_fileman_filelist,1,"Size",80)
        AddGadgetColumn(Gadget_fileman_filelist,2,"Attrib",80)
        AddGadgetColumn(Gadget_fileman_filelist,3,"Type",80)
        AddGadgetColumn(Gadget_fileman_filelist,4,"Category",80)
        AddGadgetColumn(Gadget_fileman_filelist,5,"Collection",80)
        AddGadgetColumn(Gadget_fileman_filelist,6,"Display",80)
      hStatusBar = CreateStatusBar(StatusBar_fileman,WindowID(Window_fileman))
        AddStatusBarField(470)
        AddStatusBarField(110)
        AddStatusBarField(110)
        AddStatusBarField(110)
      HideWindow(Window_fileman,0)
      ProcedureReturn WindowID(Window_fileman)

  EndIf
EndProcedure

;============================================================================================================================
; Find all drives attached to the local computer
;============================================================================================================================

Procedure FindAllDrives()

nBufferLength = (4 * 26) + 1                                      ; Calculate memory buffer.
*npBuffer = AllocateMemory(nBufferLength )                  ; Get the buffer and startaddress.

If *npBuffer <> 0                                                 ; Check if memory allocation succeeded.
  stringlength = GetLogicalDriveStrings_(nBufferLength,*npBuffer) ; Get drives and put the returned stringlength on a var.
  NumberOfDrives = stringlength / 4                               ; The number of drives in this system.
  For i = 0 To NumberOfDrives - 1                                 ; Step through the drive string.
    AddElement(AllDrives())
    AllDrives() = PeekS(*npBuffer + (i * 4))                      ; Get the drives names on intervals of 4 bytes.
  Next i
Else
  MessageRequester("Error","Cannot get drive list because there is no memory to figure that out", 0) ; Something went wrong.
EndIf

EndProcedure

;============================================================================================================================
; Form resizing and gadget colouring routines                                                 (Most of this is Pupil's help)
;============================================================================================================================

Procedure.l ResizeCallback(WindowID.l, Message.l, wParam.l, lParam.l) 

  Result = #PB_ProcessPureBasicEvents 
  
  If WindowID = WindowID(Window_fileman)
    Select message
      Case #WM_GETMINMAXINFO                                            ; Restrict the minimum size to 640x(480 + MenuHeight()), borders included
        Result = 0
        *ptr.MINMAXINFO       = lParam
        *ptr\ptMinTrackSize\x = 648
        *ptr\ptMinTrackSize\y = 488 + MenuHeight()
      Case #WM_SIZE                                                     ; Form's size has changed.
                                             ; Use the right window
        winwidth.l  = WindowWidth(Window_fileman)                                      ; Get the new width of the window
        winheight.l = WindowHeight(Window_fileman)                                     ; Get the new height of the window
        widthchange  = winwidth  - OriginalWidth                         ; Get the width difference
        heightchange = winheight - OriginalHeight                        ; Get the height difference
        ;------------------------------------------------------------------------------------------
        ResizeGadget(Gadget_fileman_fileman,    0,   0, 800 + widthchange, 560 + heightchange)
        ResizeGadget(Gadget_fileman_dirtree,    5,  10, 170              , 545 + heightchange)
        ResizeGadget(Gadget_fileman_filelist, 178,  10, 617 + widthchange, 545 + heightchange)
        ;------------------------------------------------------------------------------------------

        NewStatusBarWidth = WindowWidth(Window_fileman)                                ; Get new width
        SendMessage_(hStatusBar, #SB_GETPARTS, 4, @StatusBarFields())    ; 4 is the number of Fields in the StatusBar
        For i = 0 To 3                                                   ; 3 is number of Fields-1, because Array goes from 0 to 3
          StatusBarFields(i) = StatusBarFields(i) + (NewStatusBarWidth - OldStatusBarWidth)
        Next i
        SendMessage_(hStatusBar, #SB_SETPARTS, 4, @StatusBarFields())      
        OldStatusBarWidth = NewStatusBarWidth                            ; New Width will be old next time
        RedrawWindow_(WindowID(Window_fileman), 0, 0, #RDW_INVALIDATE)
    EndSelect
  EndIf
  
  ProcedureReturn Result

EndProcedure 

;============================================================================================================================
; Show all found drives in the treegadget
;============================================================================================================================

Procedure ShowAllDrives()

  ResetList(AllDrives())
  
  While NextElement(AllDrives())
    FlushEvents()
    AddGadgetItem(Gadget_fileman_dirtree, -1, AllDrives(), CatchImage(Icons_drive,?drive))
    DirScan(0, AllDrives())
  Wend
  
EndProcedure

;============================================================================================================================
; Find all directories for a given drive
;============================================================================================================================

Procedure DirScan(DirectoryID.l, DirectoryName.s)

  AddElement(FullPaths())
  FullPaths() = DirectoryName

  If ExamineDirectory(DirectoryID, DirectoryName, "*.*")
    Repeat
      entry.l = NextDirectoryEntry(DirectoryID)
      If entry = 1  ; AddGadgetItem(#Gadget_fileman_dirtree, -1, DirectoryEntryName()) (Filename found)
      ElseIf entry = 2
        name.s = DirectoryEntryName(DirectoryID)
        If name <> "." And name <> ".."
          FlushEvents()
          AddGadgetItem(Gadget_fileman_dirtree, -1, name, CatchImage(Icons_folder, ?folder))
          DirScan(DirectoryID + 1, DirectoryName + name + "\")

        EndIf
      EndIf
    Until entry = 0
  EndIf



EndProcedure

;============================================================================================================================
; Show the contents of a directory selected from the tree                                                         (FangBeast)
;============================================================================================================================

Procedure FileScan(FilePath.s)

  ClearList(Finfo())

  If ExamineDirectory(1024, FilePath.s, "*.*")
    Repeat
      FileType     = NextDirectoryEntry(1024) 
      FileName.s   = DirectoryEntryName(1024)
      FileSize     = FileSize(FilePath.s + "\" + DirectoryEntryName(1024)) 
      Attributes.s = GetAttribMask(FilePath.s + "\" + DirectoryEntryName(1024))

      If FileType = 1
      AddElement(Finfo())
        Finfo()\path = FilePath.s     ; Full path name
        Finfo()\name = FileName.s     ; File name
        Finfo()\size = Str(FileSize)  ; File size
        Finfo()\attr = Attributes.s   ; File attributes
        FlushEvents()
        AddGadgetItem(Gadget_fileman_filelist, -1, FileName.s + Chr(10) + Str(FileSize) + Chr(10) + Attributes)
      EndIf 
    Until FileType = 0 
  EndIf
  
EndProcedure

;============================================================================================================================
; Get the attributes of all files in the filelist for immediate display     (PB helped me figure this out properly)
;============================================================================================================================

Procedure.s GetAttribMask(fattribute.s)

  mask.s = "-----" : r = GetFileAttributes_(fattribute.s) 

  If r & #FILE_ATTRIBUTE_ARCHIVE    : mask.s = "A" + Mid(mask.s, 2, 5) : EndIf 
  If r & #FILE_ATTRIBUTE_COMPRESSED : mask.s = Left(mask.s, 1) + "C" + Mid(mask.s, 3, 3) : EndIf 
  If r & #FILE_ATTRIBUTE_HIDDEN     : mask.s = Left(mask.s, 2) + "H" + Mid(mask.s, 4, 2) : EndIf 
  If r & #FILE_ATTRIBUTE_READONLY   : mask.s = Left(mask.s, 3) + "R" + Mid(mask.s, 5, 1) : EndIf 
  If r & #FILE_ATTRIBUTE_SYSTEM     : mask.s = Left(mask.s, 4) + "S" : EndIf 

  ProcedureReturn mask.s 

EndProcedure 

;============================================================================================================================
; Flush any waiting window events to prevent form timeout                                                         (FangBeast)
;============================================================================================================================

Procedure FlushEvents()

  While WindowEvent()
  Wend

EndProcedure

;============================================================================================================================
;  Colourful speech bubble tips                                                                         (Terry Hough I think)
;============================================================================================================================

Procedure CustomToolTip(ToolHandle, ToolText.s)

  ToolTipControl = CreateWindowEx_(0, "tooltips_class32", "", $D0000000 | #TTS_BALLOON, 0, 0, 0, 0, WindowID(window_fileman), 0, GetModuleHandle_(0), 0)
  SendMessage_(ToolTipControl, 1044, 0 ,0)           ; ForeColor Tooltip
  SendMessage_(ToolTipControl, 1043, $F68E09, 0)     ; BackColor Tooltip
  SendMessage_(ToolTipControl, 1048, 0, 180)         ; Maximum Width of tooltip
  Button.TOOLINFO\cbSize = SizeOf(TOOLINFO)
  Button\uFlags = $11
  Button\hWnd = ToolHandle
  Button\uId = ToolHandle
  Button\lpszText = @ToolText.s
  SendMessage_(ToolTipControl, $0404, 0, Button)
  ProcedureReturn result

EndProcedure

;============================================================================================================================
; Add a new file name to the list of recent files
;============================================================================================================================

Procedure Recent(newfilename.s)                                                               ; (Routine by Sigfried Rings)

If FileSize(recentfilename) > 0 

 If OpenFile(#filepointer, recentfilename) <> 0
   ClearList(Files())
   If newfilename <> ""
    AddElement(Files())
    Files() = newfilename           ; Set as first element
   EndIf
   While Eof(#filepointer) = 0
    sDummy.s = ReadString(#filepointer)
    If sdummy <> newfilename       ; is already here ?
     If CountList(Files()) < 10    ; we allow only 10 Files in the Recentlist
      If sdummy <> ""              ; No NULL-STRING
       AddElement(Files())
       Files() = sDummy
      EndIf
     EndIf
    EndIf
   Wend
  CloseFile(#filepointer)
  ResetList(Files())
  If OpenFile(#filepointer, recentfilename) <> 0
   While NextElement(Files())       ; Process all the elements...
     WriteStringN(#filepointer,Files())
   Wend
   CloseFile(#filepointer)
  EndIf
 EndIf
Else
 If newfilename <> ""               ; New one
  If CreateFile(#filepointer, recentfilename) > 0
   WriteStringN(#filepointer,newfilename)
   CloseFile(#filepointer)
  EndIf
  AddElement(Files())
  Files() = newfilename
 EndIf
EndIf

EndProcedure

;============================================================================================================================
; Create and re-create the system menu every time you need it
;============================================================================================================================
      
Procedure MakeMenu()

  *MenuWindow = WindowID(Window_fileman)

  SendMessage_(*MenuWindow, #WM_SETREDRAW, 0, 0)  ; Needed to remove any flickering when recreating the menu on runtime

  If CreateMenu(MenuBar_fileman, WindowID(Window_fileman))
    MenuTitle("Files")
    MenuItem(1, "Open a File")
    MenuBar()
    ResetList(Files())
    While NextElement(Files())       ; Process all the elements...
      MenuItem(MenuRecentFiles + ListIndex(Files()), Files())
    Wend
    MenuBar()
  EndIf

  SendMessage_(*MenuWindow, #WM_SETREDRAW, 1, 0)
  InvalidateRect_(*MenuWindow, 0 ,0)

EndProcedure

;============================================================================================================================
; Application icons and any files to be included in the exe file
;============================================================================================================================

DataSection

  folder: 
  IncludeBinary "C:\Development\My Code\iCat\Icons\Folder.ico"
  drive:  
  IncludeBinary "C:\Development\My Code\iCat\Icons\Drive.ico"
  
EndDataSection
Amateur Radio/VK3HAF, (D-STAR/DMR and more), Arduino, ESP32, Coding, Crochet
TronDoc
Enthusiast
Enthusiast
Posts: 310
Joined: Wed Apr 30, 2003 3:50 am
Location: 3DoorsDown

Post by TronDoc »

thanks for the code and to those who helped you.
this one will get some study time for sure!
--jb
peace
[pI 166Mhz 32Mb w95]
[pII 350Mhz 256Mb atir3RagePro WinDoze '98 FE & 2k]
[Athlon 1.3Ghz 160Mb XPHome & RedHat9]
Post Reply