-- Copyright 2011-16 Paul Kulchenko, ZeroBrane LLC -- authors: Lomtik Software (J. Winwood & John Labenski) -- Luxinia Dev (Eike Decker & Christoph Kubisch) --------------------------------------------------------- local ide = ide local frame = ide.frame local menuBar = frame.menuBar local filehistorymenu = ide:MakeMenu { { }, { ID_RECENTFILESCLEAR, TR("Clear Items")..KSC(ID_RECENTFILESCLEAR), TR("Clear items from this list") }, } local projecthistorymenu = ide:MakeMenu { { }, { ID_RECENTPROJECTSCLEAR, TR("Clear Items")..KSC(ID_RECENTPROJECTSCLEAR), TR("Clear items from this list") }, } local fileMenu = ide:MakeMenu { { ID_NEW, TR("&New")..KSC(ID_NEW), TR("Create an empty document") }, { ID_OPEN, TR("&Open...")..KSC(ID_OPEN), TR("Open an existing document") }, { ID_CLOSE, TR("&Close Page")..KSC(ID_CLOSE), TR("Close the current editor window") }, { }, { ID_SAVE, TR("&Save")..KSC(ID_SAVE), TR("Save the current document") }, { ID_SAVEAS, TR("Save &As...")..KSC(ID_SAVEAS), TR("Save the current document to a file with a new name") }, { ID_SAVEALL, TR("Save A&ll")..KSC(ID_SAVEALL), TR("Save all open documents") }, { }, { ID_RECENTFILES, TR("Recent Files")..KSC(ID_RECENTFILES), TR("File history"), filehistorymenu }, { ID_RECENTPROJECTS, TR("Recent Projects")..KSC(ID_RECENTPROJECTS), TR("Project history"), projecthistorymenu }, { }, { ID_EXIT, TR("E&xit")..KSC(ID_EXIT), TR("Exit program") }, } menuBar:Append(fileMenu, TR("&File")) do -- recent file history local iscaseinsensitive = wx.wxFileName("A"):SameAs(wx.wxFileName("a")) local function isSameAs(f1, f2) return f1 == f2 or iscaseinsensitive and f1:lower() == f2:lower() end local filehistory = {[0] = 1} -- add file to the file history removing duplicates local function addFileHistory(filename) -- a new (empty) tab is opened; don't change the history if not filename then return end local fn = wx.wxFileName(filename) if fn:Normalize() then filename = fn:GetFullPath() end local index = filehistory[0] -- special case: selecting the current file (or moving through the history) if filehistory[index] and isSameAs(filename, filehistory[index].filename) then return end -- something else is selected -- (1) flip the history from 1 to the current index for i = 1, math.floor(index/2) do filehistory[i], filehistory[index-i+1] = filehistory[index-i+1], filehistory[i] end -- (2) if the file is in the history, remove it for i = #filehistory, 1, -1 do if isSameAs(filename, filehistory[i].filename) then table.remove(filehistory, i) end end -- (3) add the file to the top and update the index table.insert(filehistory, 1, {filename=filename}) filehistory[0] = 1 -- (4) remove all entries that are no longer needed while #filehistory>ide.config.filehistorylength do table.remove(filehistory) end end local function remFileHistory(filename) if not filename then return end local fn = wx.wxFileName(filename) if fn:Normalize() then filename = fn:GetFullPath() end local index = filehistory[0] -- special case: removing the current file if filehistory[index] and isSameAs(filename, filehistory[index].filename) then -- (1) flip the history from 1 to the current index for i = 1, math.floor(index/2) do filehistory[i], filehistory[index-i+1] = filehistory[index-i+1], filehistory[i] end end -- (2) if the file is in the history, remove it for i = #filehistory, 1, -1 do if isSameAs(filename, filehistory[i].filename) then table.remove(filehistory, i) end end -- (3) update index filehistory[0] = 1 end local updateRecentFiles -- need forward declaration because of recursive refs local function loadRecent(event) local id = event:GetId() local item = filehistorymenu:FindItem(id) local filename = item:GetItemLabelText() local index = filehistory[0] filehistory[0] = ( (index > 1 and id == ID("file.recentfiles."..(index-1)) and index-1) or (index < #filehistory) and id == ID("file.recentfiles."..(index+1)) and index+1 or 1) if not LoadFile(filename, nil, true) then wx.wxMessageBox( TR("File '%s' no longer exists."):format(filename), ide:GetProperty("editormessage"), wx.wxOK + wx.wxCENTRE, ide.frame) remFileHistory(filename) updateRecentFiles(filehistory) end end local items = 0 updateRecentFiles = function (list) -- protect against recent files menu not being present if not ide:FindMenuItem(ID_RECENTFILES) then return end for i=1, #list do local file = list[i].filename local id = ID("file.recentfiles."..i) local label = file..( i == list[0]-1 and KSC(ID_RECENTFILESNEXT) or i == list[0]+1 and KSC(ID_RECENTFILESPREV) or "") if i <= items then -- this is an existing item; update the label filehistorymenu:FindItem(id):SetItemLabel(label) else -- need to add an item local item = wx.wxMenuItem(filehistorymenu, id, label, "") filehistorymenu:Insert(i-1, item) frame:Connect(id, wx.wxEVT_COMMAND_MENU_SELECTED, loadRecent) end end for i=items, #list+1, -1 do -- delete the rest if the list got shorter filehistorymenu:Delete(filehistorymenu:FindItemByPosition(i-1)) end items = #list -- update the number of items for the next refresh -- enable if there are any recent files fileMenu:Enable(ID_RECENTFILES, #list > 0) end -- public methods function GetFileHistory() return filehistory end function SetFileHistory(fh) filehistory = fh filehistory[0] = 1 updateRecentFiles(filehistory) end function AddToFileHistory(filename) addFileHistory(filename) updateRecentFiles(filehistory) end function FileRecentListUpdate(menu) local list = filehistory for i=#list, 1, -1 do local id = ID("file.recentfiles."..i) local label = list[i].filename local item = wx.wxMenuItem(menu, id, label, "") menu:Insert(0, item) ide.frame:Connect(id, wx.wxEVT_COMMAND_MENU_SELECTED, loadRecent) end end end frame:Connect(ID_NEW, wx.wxEVT_COMMAND_MENU_SELECTED, function() return NewFile() end) frame:Connect(ID_OPEN, wx.wxEVT_COMMAND_MENU_SELECTED, OpenFile) frame:Connect(ID_SAVE, wx.wxEVT_COMMAND_MENU_SELECTED, function () local editor = ide.findReplace:CanSave(ide:GetEditorWithFocus()) or ide:GetEditor() local doc = ide:GetDocument(editor) SaveFile(editor, doc and doc:GetFilePath() or nil) end) frame:Connect(ID_SAVE, wx.wxEVT_UPDATE_UI, function (event) local doc = ide:GetDocument(ide:GetEditor()) event:Enable(ide.findReplace:CanSave(ide:GetEditorWithFocus()) and true or doc and (doc:IsModified() or doc:IsNew()) or false) end) frame:Connect(ID_SAVEAS, wx.wxEVT_COMMAND_MENU_SELECTED, function () SaveFileAs(ide:GetEditor()) end) frame:Connect(ID_SAVEAS, wx.wxEVT_UPDATE_UI, function (event) event:Enable(ide:GetEditor() ~= nil) end) frame:Connect(ID_SAVEALL, wx.wxEVT_COMMAND_MENU_SELECTED, function (event) SaveAll() end) frame:Connect(ID_SAVEALL, wx.wxEVT_UPDATE_UI, function (event) local atLeastOneModifiedDocument = false for _, document in pairs(ide:GetDocuments()) do if document:IsModified() or document:IsNew() then atLeastOneModifiedDocument = true break end end event:Enable(atLeastOneModifiedDocument) end) frame:Connect(ID_CLOSE, wx.wxEVT_COMMAND_MENU_SELECTED, function (event) local editor = ide:GetEditorWithFocus() local nb = ide:GetOutputNotebook() local index = editor and nb:GetPageIndex(editor) if index and ide.findReplace:IsPreview(editor) and index >= 0 then nb:DeletePage(index) -- close preview tab else local doc = ide:GetDocument(ide:GetEditor()) if doc then doc:Close() end end end) frame:Connect(ID_CLOSE, wx.wxEVT_UPDATE_UI, function (event) event:Enable(ide.findReplace:IsPreview(ide:GetEditorWithFocus()) or ide:GetEditor() ~= nil) end) frame:Connect(ID_EXIT, wx.wxEVT_COMMAND_MENU_SELECTED, function (event) frame:Close() -- this will trigger wxEVT_CLOSE_WINDOW end) frame:Connect(ID_RESTART, wx.wxEVT_COMMAND_MENU_SELECTED, function (event) ide:Restart(true) end) frame:Connect(ID_RECENTPROJECTSCLEAR, wx.wxEVT_COMMAND_MENU_SELECTED, function (event) FileTreeProjectListClear() end) frame:Connect(ID_RECENTFILESCLEAR, wx.wxEVT_COMMAND_MENU_SELECTED, function (event) SetFileHistory({}) local ed = ide:GetEditor() if ed then AddToFileHistory(ide:GetDocument(ed):GetFilePath()) end end) local recentprojects = 0 frame:Connect(ID_RECENTPROJECTS, wx.wxEVT_UPDATE_UI, function (event) recentprojects = FileTreeProjectListUpdate(projecthistorymenu, recentprojects) if not recentprojects then return end local pos = 1 -- add shortcut for the previous project (if any) if recentprojects > pos then local item = projecthistorymenu:FindItemByPosition(pos) item:SetItemLabel(item:GetItemLabelText()..KSC(ID_RECENTPROJECTSPREV)) end event:Enable(recentprojects > 0) end)