;***************************************************
; The file manager is a part of Fresh IDE
; that control all files Fresh working with.
; It supersedes most of the functionality
; of project manager and source editor that is
; related to managing any type of files.
;***************************************************
iglobal
FileTypes:
; Project file type.
ftProject TFileType CreateProjectManager, \
ProjFilter, \
-1, \
NULL
; Usual text source file.
ftCommonSource TFileType CreateSourceEditor, \
FileFilter, \
0, \
fasm_syntax
; Main source file.
ftMainSource TFileType CreateSourceEditor, \
FileFilter, \
1, \
fasm_syntax
; File containing Form template and form handling source file.
ftFormSource TFileType CreateFormEditor, \
FormFilter, \
3, \
fasm_syntax
; Text document without syntax highlighter.
ftTextDocument TFileType CreateSourceEditor, \
FileFilter, \
2, \
NULL
; graphic file
ftGraphic TFileType CreateGraphicEditor, \
GraphicFilter, \
4, \
NULL
; ftWatch TFileType CreateMemWatch, \
; WatchFilter, \
; 5, \
; NULL
FileTypeNames:
StrList \
'Project', \
'Source file', \
'Main file', \
'Form', \
'Text document', \
'Image';, \
; 'Memory watch table'
FileTypeExt dd '.fpr', '.asm', '.asm', '.frm', '.txt', '.bmp';, '.mwt'
endg
uglobal
ptrCurrentFile dd ? ; TOpenFile descendent that have the focus in that moment.
listFiles dd ? ; TArray with all open files.
endg
;-------------------------------------------------
; Prepares file manager for work.
; Call this procedure only once at the begining.
;-------------------------------------------------
proc InitFileManager
begin
stdcall CreateArray, 4
mov [listFiles], eax
return
endp
;-------------------------------------------------
; Closes all still open files and finalizes the
; file manager. Call it once on close of Fresh
;-------------------------------------------------
proc CloseFileManager
begin
; Close and free all open files.
stdcall ListFree, [listFiles], _FreeFileProc
mov [listFiles], 0
return
endp
proc _FreeFileProc, .ptrOpenFile
begin
push esi
mov esi, [.ptrOpenFile]
mov [esi+TOpenFile.projectID], 0
stdcall CloseFile, esi
pop esi
return
endp
proc OpenFileByNameEdit, .hFileName, .dummy
begin
stdcall OpenFileByName, [.hFileName], NULL, TRUE
return
endp
proc OpenFileByName, .hFileName, .hTemplate, .fLoadInEditor
begin
push ebx
; log the active file state before changing focus...
cmp [fLogFileLock], 0
jne @f
cmp [.fLoadInEditor], 0
je @f
stdcall LogInHistory, ptrBackHistory
@@:
stdcall IsFileOpen, [.hFileName]
mov ebx, eax
test eax, eax
jnz .focus
stdcall DetectFileType, [.hFileName]
mov ebx, eax
test eax, eax
jz .unknowntype
.doopen:
stdcall CreateFStruct, [.hFileName], ebx
mov ebx, eax
.focus:
cmp [ebx+TOpenFile.hEditor], 0
jne .dofocus
cmp [.fLoadInEditor], FALSE
je .finish
stdcall LoadFile, ebx, [.hTemplate]
test eax, eax
jz .error
.dofocus:
stdcall FocusFile, ebx
.finish:
mov eax, ebx
pop ebx
return
.unknowntype:
mov ebx, ftTextDocument
invoke MessageBoxA, [hApplication], cWarningUnknownType, NULL, MB_YESNO or MB_ICONQUESTION
cmp eax, IDYES
je .doopen
xor eax, eax
pop ebx
return
.error:
stdcall FreeFStruct, ebx
xor eax, eax
pop ebx
return
endp
iglobal
cWarningUnknownType text 'Unknown file type.', 13, 10, \
'Do you want to open it as text?'
endg
;--------------------------------------------------------------------
; Check whether the file is already open in the coresponding editor.
; Returns:
; eax:
; NULL - the file is not open.
; ptrOpenFile - the file is open.
;--------------------------------------------------------------------
proc IsFileOpen, .hFileName
.str rb 512
.ptr dd ?
begin
push esi ebx
stdcall StrPtr, [.hFileName]
lea ebx, [.str]
lea edx, [.ptr]
invoke GetFullPathNameA, eax, 512, ebx, edx
stdcall HashFilename, ebx
mov edx, eax
mov esi, [listFiles]
mov ecx, [esi+TArray.count]
lea esi, [esi+TArray.array]
.while:
dec ecx
js .notfound
lodsd
cmp edx, [eax+TOpenFile.hashFileName]
jne .while
stdcall StrCompNoCase, [eax+TOpenFile.hFileName], ebx
jnc .while
; Found:
pop ebx esi
return
.notfound:
xor eax, eax
pop ebx esi
return
endp
;----------------------------------------------------------------------
; Detects the proper type of the file from it's extension.
; Returns valid pointer to TFileType structure or NULL for error.
;----------------------------------------------------------------------
proc DetectFileType, .hFileName
begin
stdcall StrLen, [.hFileName]
mov ecx, eax
stdcall StrPtr, [.hFileName]
.extloop:
dec ecx
js .error
cmp byte [eax+ecx], '.'
jne .extloop
mov ecx, dword [eax+ecx] ; get the extension
or ecx, $20202000 ; case insensitive
mov eax, ftCommonSource
cmp ecx, '.asm'
je .typeok
cmp ecx, '.inc'
je .typeok
mov eax, ftFormSource
cmp ecx, '.frm'
je .typeok
mov eax, ftProject
cmp ecx, '.fpr'
je .typeok
mov eax, ftTextDocument
cmp ecx, '.txt'
je .typeok
mov eax, ftGraphic
cmp ecx, '.bmp'
je .typeok
.error:
xor eax, eax
.typeok:
return
endp
;----------------------------------------------------------------------
; Creates the file structure for given file type.
; If in some of the editors, the file with the same name is
; already open, returns the pointer to the existing file.
;
; In the case if new file is created:
; Set the values for following fields:
; .type = needed type value.
; .hFileName = full filename of the file.
; .hashFileName = hash value of the filename.
; .fNeverSaved = FALSE if the file with given name exists
; TRUE otherwize.
;
; Returns the pointer to the TOpenFile in the eax register.
;----------------------------------------------------------------------
proc CreateFStruct, .hFileName, .type
.str rb 512
.ptr dd ?
begin
push ebx esi
mov ebx, [.type]
test ebx, ebx
jnz .typeok
mov ebx, ftTextDocument
.typeok:
stdcall IsFileOpen, [.hFileName]
test eax, eax
jnz .finish
stdcall GetMem, sizeof.TOpenFile
mov esi, eax
stdcall AddArrayItems, [listFiles], 1
mov [listFiles], edx
mov [eax], esi
mov [esi+TOpenFile.ptrType], ebx
stdcall StrPtr, [.hFileName]
lea ecx, [.str]
push ecx ; for future use
lea edx, [.ptr]
invoke GetFullPathNameA, eax, 512, ecx, edx
stdcall StrDup ; .str from the stack
mov [esi+TOpenFile.hFileName], eax
stdcall HashFilename, eax
mov [esi+TOpenFile.hashFileName], eax
stdcall StrPtr, [esi+TOpenFile.hFileName]
stdcall FileExists, eax
rcl [esi+TOpenFile.fNeverSaved], 1
mov eax, esi
.finish:
pop esi ebx
return
endp
;--------------------------------------------------
; Frees the TOpenFile descendent structure.
;--------------------------------------------------
proc FreeFStruct, .ptrFile
begin
push esi
mov esi, [.ptrFile]
cmp [esi+TOpenFile.hEditor], 0
je .editorclosed
invoke DestroyWindow, [esi+TOpenFile.hEditor]
mov [esi+TOpenFile.hEditor], 0
.editorclosed:
cmp [esi+TOpenFile.projectID], 0
je .notinproject
invoke SendMessageA, [hProjManager], PMM_REMOVEFILE, esi, 0
.notinproject:
stdcall ListIndexOf, [listFiles], esi
jc .removedfromlist
stdcall DeleteArrayItems, [listFiles], eax, 1
mov [listFiles], edx
.removedfromlist:
stdcall StrDel, [esi+TOpenFile.hFileName]
stdcall FreeMem, esi
pop esi
return
endp
;------------------------------------------------------------------------
; Loads the given file in the apropriate editor window.
; If the file is loaded - do nothing.
; Returns NULL if error or eax = [ptrFile] if OK.
;------------------------------------------------------------------------
proc LoadFile, .ptrFile, .hTemplate
begin
push esi
mov esi, [.ptrFile]
cmp [esi+TOpenFile.hEditor], 0
jne .fileisloaded
mov eax, [esi+TOpenFile.ptrType]
stdcall [eax+TFileType.CreateProc], esi, [.hTemplate]
test eax, eax
jnz .error
.fileisloaded:
stdcall FocusFile, esi
mov eax, esi
pop esi
return
.error:
stdcall ErrorMessage, eax
xor eax, eax
pop esi
return
endp
;-------------------------------------------------
; Renames given file and notifies the editor that
; the file was renamed.
;-------------------------------------------------
proc RenameFile, .ptrFile, .hNewName
begin
push esi
mov esi, [.ptrFile]
stdcall StrCopy, [esi+TOpenFile.hFileName], [.hNewName]
stdcall HashFilename, [esi+TOpenFile.hFileName]
mov [esi+TOpenFile.hashFileName], eax
cmp [esi+TOpenFile.hEditor], 0
je .checkproject
; notify the editor.
invoke SendMessageA, [esi+TOpenFile.hEditor], _CEM_CHANGENOTIFY, 0, 0
.checkproject:
cmp [esi+TOpenFile.projectID], 0
je .finish
; notify project manager.
invoke SendMessageA, [hProjManager], PMM_FILECHANGED, esi, 0
.finish:
pop esi
return
endp
;------------------------------------------------
; Saves the file to the disk.
; Also checks if the flag .fNeverSaved is TRUE
; and opens the SaveAs dialog.
; The easy way to make function SaveAs is to
; set .fNeverSaved and to call this function.
; Return: TRUE if the file is saved
; FALSE if the user canceled operation or error ocures.
;---------------------------------------------------------------
proc SaveFile, .ptrFile
.inmem TInMemoryFile
.res dd ?
begin
push esi
mov [.res], TRUE
mov [.inmem.ptrBuffer], 0
mov esi, [.ptrFile]
test esi, esi
jz .finish
cmp [esi+TOpenFile.hEditor], 0
je .finish ; the file is not loaded in editor.
; Is the file need SaveAs?
cmp [esi+TOpenFile.fNeverSaved], FALSE
je .dosave
mov eax, [esi+TOpenFile.ptrType]
stdcall SaveFileDialog, cSaveFileTitle, [eax+TFileType.ptrFilter], [esi+TOpenFile.hFileName]
test eax, eax
jnz .rename
mov [.res], eax
jmp .finish
.rename:
push eax
stdcall RenameFile, esi, eax
stdcall StrDel ; from the stack.
.dosave:
lea eax, [.inmem]
invoke SendMessageA, [esi+TOpenFile.hEditor], _CEM_GETTEXT, 0, eax
test eax, eax
jnz .errorsave
stdcall StrPtr, [esi+TOpenFile.hFileName]
stdcall SaveBinaryFile, eax, [.inmem.ptrBuffer], [.inmem.fileSize]
jc .errorsave
mov [esi+TOpenFile.fNeverSaved], 0 ; Mark it as saved at least once.
xor eax, eax
push eax eax eax eax
invoke SendMessageA, [esi+TOpenFile.hEditor], EM_EMPTYUNDOBUFFER ; remaining arguments are in stack.
invoke SendMessageA, [esi+TOpenFile.hEditor], _CEM_SETMODIFIED
jmp .free
.errorsave:
mov [.res], 0
stdcall ErrorMessage, eax
.free:
cmp [.inmem.ptrBuffer], 0
je .finish
stdcall FreeMem, [.inmem.ptrBuffer]
.finish:
mov eax, [.res]
pop esi
return
endp
;--------------------------------------------------
; Close the file and removes it from its editor.
; Returns:
; 0: file is closed successfully
; 1: file is closed and TOpenFile structure was destroyed.
; 2: some error
; 3: CANCEL button was pressed on the save dialog.
;--------------------------------------------------
proc CloseFile, .ptrFile
begin
push esi
mov esi, [.ptrFile]
test esi, esi
jz .fault
cmp [esi+TOpenFile.hEditor], 0
je .checkproj
stdcall GetModified, esi
test eax, eax
je .saveok
stdcall StrDup, cNotSaved1
push eax
stdcall StrCat, eax, [esi+TOpenFile.hFileName]
stdcall StrCat, eax, cNotSaved2
stdcall StrPtr, eax
invoke MessageBoxA, [hApplication], eax, cTitleWarning, MB_YESNOCANCEL or MB_ICONQUESTION
stdcall StrDel ; from the stack
cmp eax, IDNO
je .saveok
cmp eax, IDCANCEL
je .cancel
stdcall SaveFile, esi
.saveok:
invoke DestroyWindow, [esi+TOpenFile.hEditor]
mov [esi+TOpenFile.hEditor], 0
.checkproj:
cmp [esi+TOpenFile.projectID], 0
jne .finishok
stdcall FreeFStruct, esi
mov eax, cfrDestroyed
pop esi
return
.finishok:
xor eax, eax
mov al, cfrClosed
pop esi
return
.fault:
xor eax, eax
mov al, cfrFault
pop esi
return
.cancel:
xor eax, eax
mov al, cfrCanceled
pop esi
return
endp
iglobal
cTitleWarning text 'Warning!'
cNotSaved1 text 'The file "'
cNotSaved2 text '" is not saved.', 13, 10, \
'Do you want to save it now?'
endg
proc FocusFile, .ptrFile
begin
push esi
mov esi, [.ptrFile]
test esi, esi
jz .focusok
cmp [esi+TOpenFile.hEditor], 0
jz .finish
invoke SendMessageA, [esi+TOpenFile.hEditor], _CEM_FOCUSFILE, 0, 0
.focusok:
stdcall SetCurrentFile, esi
.finish:
pop esi
return
endp
proc SetCurrentFile, .ptrFile
begin
push [.ptrFile]
pop [ptrCurrentFile]
return
endp
;----------------------------------------------------------
; Returns TRUE if the file allows some edit action,
; FALSE otherwise.
;----------------------------------------------------------
proc CanAction, .ptrFile, .action
begin
invoke GetFocus
cmp eax, [hLister]
je .check_action
mov eax, [.ptrFile]
test eax, eax
jz .finish
mov eax, [eax+TOpenFile.hEditor]
test eax, eax
jz .finish
.check_action:
invoke SendMessageA, eax, _CEM_CANACTION, 0, [.action]
.finish:
return
endp
proc CommonAction, .ptrFile, .action
begin
push esi
mov esi, [.ptrFile]
test esi, esi
jz .finish
cmp [esi+TOpenFile.hEditor], 0
je .finish
invoke SendMessageA, [esi+TOpenFile.hEditor], \
_CEM_EDITACTION, 0, [.action]
.finish:
pop esi
return
endp
;*******************************************************
; Returns TRUE if the file is modified after loading
;*******************************************************
proc GetModified, .ptrFile
begin
mov eax, [.ptrFile]
test eax, eax
jz .exit
cmp [eax+TOpenFile.fNeverSaved], 0 ; if the file is never saved.
jne .finish
mov eax, [eax+TOpenFile.hEditor]
test eax, eax
jz .exit
invoke SendMessageA, eax, _CEM_GETMODIFIED, 0, 0
return
.finish:
xor eax, eax
inc eax
.exit:
return
endp
;*****************************************
; Returns visual properties of the file.
; eax - string handle with screen title
; edx - index of the icon in the files
; image list.
;*****************************************
proc GetScreenProperties, .ptrFile
begin
push edi
mov edi, [.ptrFile]
test edi,edi
jz .error
stdcall ExtractFileName, [edi+TOpenFile.hFileName]
stdcall StrExtract, [edi+TOpenFile.hFileName], eax, -1
mov edx, [edi+TOpenFile.ptrType]
mov edx, [edx+TFileType.iFileIcon]
cmp [edi+TOpenFile.projectID], 0
jne @f
add edx, 8
@@:
pop edi
return
.error:
mov eax, edi
pop edi
return
endp
;-------------------------------------
; Returns ptr to TOpenFile of given
; editor. IF there is no such editor
; registered, returns NULL
;-------------------------------------
proc GetEditorFile, .hEditor
begin
invoke SendMessageA, [.hEditor], _CEM_GETFILE, 0, 0
return
endp
;-----------------------------------
; Returns handle of AsmEdit window
; of the some editor. (if any)
; If editor does not contains
; AsmEdit control, returns NULL
;-----------------------------------
proc GetAsmEdit, .hEditor
begin
invoke SendMessageA, [.hEditor], _CEM_GETASMEDIT, 0, 0
return
endp
proc GetFileAsmEdit, .ptrOpenFile
begin
mov eax, [.ptrOpenFile]
test eax, eax
jz .finish
mov eax, [eax+TOpenFile.hEditor]
test eax, eax
jz .finish
invoke SendMessageA, eax, _CEM_GETASMEDIT, 0, 0
.finish:
return
endp
;-------------------------------------------------------
; Notifies editor, that file properties were changed
; ptrFile - TOpenFile structute of the file.
; fWho - fcEditor, fcProject, fcAll
;-------------------------------------------------------
proc FileChanged, .ptrFile, .fWho
begin
push ebx
mov ebx, [.ptrFile]
test ebx, ebx
jz .finish
stdcall CheckFileForFree, ebx
test eax, eax
jnz .finish
test [.fWho], fcEditor
jz .notifyproject
cmp [ebx+TOpenFile.hEditor], 0
je .notifyproject
invoke SendMessageA, [ebx+TOpenFile.hEditor], _CEM_CHANGENOTIFY, 0, 0
.notifyproject:
test [.fWho], fcProject
jz .finish
cmp [eax+TOpenFile.projectID], NULL
je .finish
invoke SendMessageA, [hProjManager], PMM_FILECHANGED, eax, 0
.finish:
pop ebx
return
endp
;--------------------------------------------
; Returns TRUE if the file was destroyed.
;--------------------------------------------
proc CheckFileForFree, .ptrFile
begin
xor eax, eax
mov ecx, [.ptrFile]
jecxz .finish
mov edx, [ecx+TOpenFile.hEditor]
add edx, [ecx+TOpenFile.projectID]
jnz .finish
stdcall FreeFStruct, ecx
xor eax, eax
inc eax
.finish:
return
endp
;---------------------------------------------------
; Enumerates all open files and calls [ptrCallBack]
; Format for callback is:
; proc MyCallBack, ptrFile, lParam
; if callback returns C=1, the enumeration stops
; and the functions returns value in eax.
;---------------------------------------------------
proc EnumOpenFiles, .ptrCallBack, .lParam
begin
push esi ecx
mov esi, [listFiles]
mov ecx, [esi+TArray.count]
xor eax, eax
jecxz .finish
lea esi, [esi+4*ecx-4+TArray.array]
.filesloop:
push esi ecx
stdcall [.ptrCallBack], [esi], [.lParam]
pop ecx esi
jc .finish
lea esi, [esi-4]
loop .filesloop
.finish:
pop ecx esi
return
endp
;------------------------------------------
; Returns the number of the files that are
; members of the currently open project.
;------------------------------------------
proc GetProjectFilesCount
begin
xor edx, edx
stdcall EnumOpenFiles, _docountproject, 0
mov eax, edx
return
endp
proc _docountproject, .ptrFile, .lParam
begin
mov eax, [.ptrFile]
cmp [eax+TOpenFile.projectID], NULL
je @f
inc edx
@@:
clc
return
endp
;------------------------------------------
; Returns the number of the files that are
; currently open for editing.
;------------------------------------------
proc GetEditFilesCount
begin
xor edx, edx
stdcall EnumOpenFiles, _docountedit, 0
mov eax, edx
return
endp
proc _docountedit, .ptrFile, .lParam
begin
mov eax, [.ptrFile]
cmp [eax+TOpenFile.hEditor], NULL
je @f
inc edx
@@:
clc
return
endp