Jump to content

Recent Files Logic


czardas
 Share

Recommended Posts

The following code is intended to illustrate a method of adding recent files to the File menu, once files have been opened or saved. This is not a UDF, nor a universal solution which fits all requirements. It is just the solution I made for myself and I thought it worth sharing. I haven't noticed much about this subject. The example only emulates opening and saving files: nothing is actually written to disk. I have not included any code for opening or saving files - only the File menu and Title bar are updated. The code is intended to illustrate the logic I used. Perhaps you can improve on it or get some ideas from this example.

#include <GUIConstants.au3>
#include <MsgBoxConstants.au3>

Example()

#Region ; core functions

Func UpdateRecentFiles(ByRef $aRecentFiles, $ahMenu, $sNewPath, $iMenuInsertPos)
    Local $iMaxFiles = UBound($aRecentFiles) -1

    For $i = 1 To $aRecentFiles[0][0] ; check to see if the path was accessed recently
        If $aRecentFiles[$i][0] = $sNewPath Then ; file is already in the list
            For $j = $i To 2 Step -1
                $aRecentFiles[$j][0] = $aRecentFiles[$j -1][0] ; push items down the list
            Next
            $aRecentFiles[1][0] = $sNewPath
            For $j = 1 To $aRecentFiles[0][0] ; update all recent file menu items
                GUICtrlSetData($aRecentFiles[$j][1], $aRecentFiles[$j][0]) ; overwrite existing control data
            Next
            Return ; the list has simply been reordered
        EndIf
    Next

    ; if we are here, then the file was not found in the recent files list
    For $i = $iMaxFiles To 2 Step -1
        $aRecentFiles[$i][0] = $aRecentFiles[$i -1][0] ; push all existing items down the list
    Next

    If $aRecentFiles[0][0] < $iMaxFiles Then
        $aRecentFiles[0][0] += 1 ; increment the number of recent files in the list
        $aRecentFiles[$aRecentFiles[0][0]][1] = GUICtrlCreateMenuItem($sNewPath, $ahMenu[0], $aRecentFiles[0][0] + $iMenuInsertPos) ; create a new control
        ; add a second spacer to the menu after the first recent item appears (one time action)
        If $aRecentFiles[0][0] = 1 Then $aRecentFiles[0][1] = GUICtrlCreateMenuItem('', $ahMenu[0], $aRecentFiles[0][0] + $iMenuInsertPos +1) ; add divider after adding the first recent item
    EndIf

    $aRecentFiles[1][0] = $sNewPath ; add the new path to the files list
    For $i = 1 To $aRecentFiles[0][0] ; update all recent file menu items
        GUICtrlSetData($aRecentFiles[$i][1], $aRecentFiles[$i][0]) ; overwrite existing control data
    Next
EndFunc ;==> UpdateRecentFiles

Func ClearRecentFiles(ByRef $aRecentFiles, $idDummyInactive)
    For $i = 0 To $aRecentFiles[0][0]
        GUICtrlDelete($aRecentFiles[$i][1]) ; delete menu items
        $aRecentFiles[$i][1] = $idDummyInactive ; render all control IDs inactivate
    Next
    $aRecentFiles[0][0] = 0 ; there are now zero files in the list
EndFunc ;==> ClearRecentFiles


Func DeleteRecentItem(ByRef $aRecentFiles, $iItem, $idDummyInactive)
    For $i = $iItem To $aRecentFiles[0][0] -1
        $aRecentFiles[$i][0] = $aRecentFiles[$i +1][0]
        GUICtrlSetData($aRecentFiles[$i][1], $aRecentFiles[$i][0])
    Next

    GUICtrlDelete($aRecentFiles[$aRecentFiles[0][0]][1])
    $aRecentFiles[$aRecentFiles[0][0]][1] = $idDummyInactive
    $aRecentFiles[0][0] -= 1

    If $aRecentFiles[0][0] = 0 Then
        GUICtrlDelete($aRecentFiles[0][1])
        $aRecentFiles[0][1] = $idDummyInactive
    EndIf
EndFunc ;==> DeleteRecentItem

#EndRegion ;==> core functions

#Region ; example code

Func Example()
    Local $sGUITitle = "New Project", $hGUI = GUICreate($sGUITitle, 500, 200) ; create GUI

    Local _ ; declare menu arrays
    $ahMenu[2] = [" File "," Options"], _ ; 1D array assigned to menus
    $ahMenuItem = GetMenuItems() ; 2D array assigned to menu item controls

    For $i = 0 To UBound($ahMenu) -1
        $ahMenu[$i] = GUICtrlCreateMenu($ahMenu[$i]) ; create menu
        For $j = 1 To $ahMenuItem[0][$i] ; add menu item controls
            $ahMenuItem[$j][$i] = GUICtrlCreateMenuItem($ahMenuItem[$j][$i], $ahMenu[$i])
        Next
    Next

    Local $iMenuInsertPos = 4 ; this is the menuentry position for the most recent file
    GUICtrlCreateMenuItem('', $ahMenu[0], $iMenuInsertPos) ; create dividor

    Local $aRecentFiles[9][2] = [[0]], _ ; zero previously stored items - assuming that the recent files list is empty at startup
    $idDummyInactive = GUICtrlCreateDummy() ; never send messages to $idDummyInactive

    For $i = 0 To 8 ; [IMPORTANT] Windows assigned a unique control ID to $idDummyInactive
        $aRecentFiles[$i][1] = $idDummyInactive ; temporarily set all (recent files list) controls to never receive messages
    Next

    GUISetState(@SW_SHOW)

    Local $msg, $sFilePath

    While 1
        $msg = GUIGetMsg()
        Switch $msg
            Case $GUI_EVENT_CLOSE, $ahMenuItem[5][0]
                ExitLoop

            Case $ahMenuItem[1][0] ; File ==> New
                New()
                WinSetTitle($hGUI , WinGetTitle($hGUI), $sGUITitle)

            Case $ahMenuItem[2][0] ; File ==> Open
                $sFilePath = Open()
                If Not @error Then
                    WinSetTitle($hGUI , WinGetTitle($hGUI), $sFilePath)
                    UpdateRecentFiles($aRecentFiles, $ahMenu, $sFilePath, $iMenuInsertPos)
                EndIf

            Case $ahMenuItem[3][0] ; File ==> Save
                $sFilePath = Save(WinGetTitle($hGUI))

                If @error Then
                    MsgBox($MB_OK, "Action Failed", "Unable to save file")
                    ContinueLoop ; [use your own code logic]
                Else
                    WinSetTitle($hGUI , WinGetTitle($hGUI), $sFilePath)
                    UpdateRecentFiles($aRecentFiles, $ahMenu, $sFilePath, $iMenuInsertPos) ; update recent files here
                EndIf

            Case $ahMenuItem[4][0] ; File ==> Save As
                $sFilePath = SaveAs()
                If @error Then
                    MsgBox($MB_OK, "Action Failed", "Unable to save file")
                    ContinueLoop ; [use your own code logic]
                Else
                    WinSetTitle($hGUI , WinGetTitle($hGUI), $sFilePath)
                    UpdateRecentFiles($aRecentFiles, $ahMenu, $sFilePath, $iMenuInsertPos) ; update recent files here
                EndIf

            Case $ahMenuItem[1][1] ; Options ==> Clear Recent Files
                ClearRecentFiles($aRecentFiles, $idDummyInactive)

            Case $aRecentFiles[1][1], $aRecentFiles[2][1], $aRecentFiles[3][1], $aRecentFiles[4][1], $aRecentFiles[5][1], $aRecentFiles[6][1], $aRecentFiles[7][1], $aRecentFiles[8][1]
                For $i = 1 To $aRecentFiles[0][0]
                    If $msg = $aRecentFiles[$i][1] Then
                        $sFilePath = OpenRecent($aRecentFiles[$i][0])
                        If Not @error Then
                            WinSetTitle($hGUI , WinGetTitle($hGUI), $sFilePath)
                            UpdateRecentFiles($aRecentFiles, $ahMenu, $sFilePath, $iMenuInsertPos) ; update recent files here
                        ElseIf @error = 1 Then
                            If MsgBox(BitOR($MB_YESNO, $MB_DEFBUTTON2, $MB_TASKMODAL), "Action Failed", "Unable to locate " & $aRecentFiles[$i][0] & @CRLF & _
                            "Do you want to remove this item from the menu?") = 6 Then DeleteRecentItem($aRecentFiles, $i, $idDummyInactive)
                        EndIf
                        ExitLoop ; return to the While loop
                    EndIf
                Next
        EndSwitch
    WEnd
EndFunc ;==> Example

Func New()
    ; start a new project [your code here]
EndFunc ;==> New

Func Open()
    Local $sFilePath = FileOpenDialog("Open", @DocumentsCommonDir, "All (*.*)")
    If @error Then Return SetError(1)

    ; read file [your code here]

    Return $sFilePath
EndFunc ;== Open

Func OpenRecent($sFilePath)
    If Not FileExists($sFilePath) Then Return SetError(1) ; unable to open recent file

    ; read file [your code here]

    Return $sFilePath
EndFunc ;== OpenRecent

Func Save($sFilePath)
    If Not FileExists($sFilePath) Then
        Local $sNewPath = SaveAs()
        If @error Then Return SetError(1) ; unable to save file
        Return $sNewPath
    EndIf

    ; save file [your code here]

    Return $sFilePath
EndFunc ;==> Save

Func SaveAs()
    Local $sFilePath = FileSaveDialog( "Save As", @DocumentsCommonDir, "All (*.*)")
    If @error Then Return SetError(1) ; unable to save file

    ; save new or existing file [your code here]

    Return $sFilePath
EndFunc ;==> SaveAs

Func GetMenuItems()
    Local $aMenuItem[6][2]
    $aMenuItem[0][0] = 5  ; number of items on the File Menu
    $aMenuItem[0][1] = 1  ; number of items on the Options Menu

    ; File Menu
    $aMenuItem[1][0] = "New"
    $aMenuItem[2][0] = "Open"
    $aMenuItem[3][0] = "Save"
    $aMenuItem[4][0] = "Save As"
    $aMenuItem[5][0] = "Exit"

    ; Options Menu
    $aMenuItem[1][1] = "Clear Recent Files"
    Return $aMenuItem
EndFunc ;==> GetMenuItems

#Region ; example code

Run the example, open some files and check for new menu items that are added. Then try a few other menu options and check the various changes occurring in the File menu.

Edited by czardas
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...