When opening my templates, I was quite shocked, it was simply E.M.P.T.Y.!
So ~100 templates gone, nice!
I read about that problem in the past (seems to happen rarely only) and always thought "pff.. guess it was the users fault, that will never happen to me".
Well.. here we are now, quite frustrated, I found a three year old backup at least, better than nothing.
Anyway, long story short, it was time for a quick backup IDE tool for the Templates:
Code: Select all
; [IDE Tool]
; Template Backup V1.1
; (c) HeX0R 2025
; https://www.purebasic.fr/english/viewtopic.php?p=638730#p638730
;
; Compile, add as PB IDE Tool, give it some name, no Arguments and let it be triggered by "Editor closing"
; at first start it will ask for a backup path
; whenever Templates.prefs size has changed, it will add a backup there.
; they will be named (keep it simple):
; Templates_001.prefs
; Templates_002.prefs
; ...
; New in V1.1
; Because it happened again to me (PB deleted my Templates), I've added a restore function
; Just start it outside of PB (not as tool) and a restore GUI will come up.
; You can also remove old backups (DEL key), but this means also, you can't rely on the filename numbers any longer to find the latest version.
; That shouldn't be a big problem due to the new backup functionality.
; Files will be shown from latest to oldest, no matter the filenames
EnableExplicit
Structure Templates
Date.q
FileName$
EndStructure
Global NewList BkTemplate.Templates()
Global BackupPath$, PrefPath$
Runtime Procedure OnClick_CheckBox()
Protected State
If GetGadgetState(DialogGadget(0, "checkbox_default_path"))
State = 1
EndIf
DisableGadget(DialogGadget(0, "text_template_path"), State)
DisableGadget(DialogGadget(0, "string_template_path"), State)
DisableGadget(DialogGadget(0, "button_browse"), State)
EndProcedure
Runtime Procedure OnChange_String()
;maybe later
EndProcedure
Runtime Procedure OnClick_Browse()
Protected File$
File$ = PathRequester("Path to Templates.prefs", "")
If File$
SetGadgetText(DialogGadget(0, "string_template_path"), File$)
EndIf
EndProcedure
Runtime Procedure OnClick_DoRestore()
Protected i, *D.Templates, Path$
i = GetGadgetState(DialogGadget(0, "listicon_backups"))
If i > -1
*D = GetGadgetItemData(DialogGadget(0, "listicon_backups"), i)
If MessageRequester("Restore Template", "Make sure that the PB IDE is closed or it will overwrite the templates when closing, again!" + #LF$ + "Do you want to proceed?", #PB_MessageRequester_Info | #PB_MessageRequester_YesNo) = #PB_MessageRequester_Yes
If GetGadgetState(DialogGadget(0, "checkbox_default_path"))
Path$ = GetUserDirectory(#PB_Directory_ProgramData) + "PureBasic" + #PS$
Else
Path$ = GetGadgetText(DialogGadget(0, "string_template_path"))
If Path$ And Right(Path$, 1) <> #PS$
Path$ + #PS$
EndIf
If Path$
If OpenPreferences(GetUserDirectory(#PB_Directory_ProgramData) + "hex0r" + #PS$ + "IDE_bk" + #PS$ + "bk.prefs")
WritePreferenceString("PrefPath", Path$)
ClosePreferences()
EndIf
EndIf
EndIf
CopyFile(*D\FileName$, Path$ + "Templates.prefs")
DisableGadget(DialogGadget(0, "button_restore"), 1)
SetGadgetState(DialogGadget(0, "listicon_backups"), -1)
EndIf
EndIf
EndProcedure
Runtime Procedure OnChange_Backups()
Protected i
i = GetGadgetState(DialogGadget(0, "listicon_backups"))
If i > -1
DisableGadget(DialogGadget(0, "button_restore"), 0)
Else
DisableGadget(DialogGadget(0, "button_restore"), 1)
EndIf
EndProcedure
Procedure.s GetXMLString()
Protected XML$
XML$ + "<?xml version='1.0' encoding='UTF-16'?>"
XML$ + ""
XML$ + "<dialogs><!--Created by Dialog Design0R V1.87 => get it from: https://hex0rs.coderbu.de/en/sdm_downloads/dialogdesign0r/-->"
XML$ + " <window flags='#PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered' text='Restore Template' name='WinMain' xpos='1234' ypos='345'>"
XML$ + " <vbox>"
XML$ + " <frame text='Select Backup' name='frame_backups'>"
XML$ + " <listicon flags='#PB_ListIcon_GridLines | #PB_ListIcon_FullRowSelect | #PB_ListIcon_AlwaysShowSelection' height='200' width='500' text='Backup from' name='listicon_backups' onchange='OnChange_Backups()'/>"
XML$ + " </frame>"
XML$ + " <checkbox text='Use default Template path' name='checkbox_default_path' onevent='OnClick_CheckBox()'/>"
XML$ + " <hbox expand='item:2'>"
XML$ + " <text text='Path to Template (portable installations):' disabled='yes' name='text_template_path'/>"
XML$ + " <string disabled='yes' name='string_template_path' onchange='OnChange_String()'/>"
XML$ + " <button text='...' disabled='yes' name='button_browse' onevent='OnClick_Browse()'/>"
XML$ + " </hbox>"
XML$ + " <hbox align='center' expand='no'>"
XML$ + " <button text='Do Restore' flags='#PB_Button_Default' disabled='yes' name='button_restore' onevent='OnClick_DoRestore()'/>"
XML$ + " </hbox>"
XML$ + " </vbox>"
XML$ + " </window>"
XML$ + "</dialogs><!--DDesign0R Definition: PureBasic|1|1|1|__|-|0-->"
XML$ + ""
ProcedureReturn XML$
EndProcedure
Procedure$ GetTemplateContent(File$)
Protected Dir, Temp, a$, Result$
If ReadFile(0, File$)
While Eof(0) = 0
a$ = ReadString(0)
a$ = Trim(a$)
If Left(a$, 10) = "Directory:"
Dir + 1
ElseIf Left(a$, 9) = "Template:"
Temp + 1
EndIf
Wend
CloseFile(0)
EndIf
Result$ = Str(Dir) + " Directories, " + Str(Temp) + " Templates"
ProcedureReturn Result$
EndProcedure
Procedure OnDelete()
Protected i, *D.Templates, Gadget
Gadget = DialogGadget(0, "listicon_backups")
i = GetGadgetState(Gadget)
If i > -1
If MessageRequester("Delete Entry", "Do you really want to delete the Template from " + GetGadgetItemText(Gadget, i, 0) + "?", #PB_MessageRequester_YesNo) = #PB_MessageRequester_Yes
*D = GetGadgetItemData(Gadget, i)
DeleteFile(*D\FileName$)
ChangeCurrentElement(BkTemplate(), *D)
DeleteElement(BkTemplate())
RemoveGadgetItem(Gadget, i)
SetGadgetState(Gadget, i)
OnChange_Backups()
EndIf
EndIf
EndProcedure
Procedure InitRestore()
Protected i, Line$, LiGadget
ParseXML(0, GetXMLString())
CreateDialog(0)
OpenXMLDialog(0, 0, "WinMain")
LiGadget = DialogGadget(0, "listicon_backups")
SetGadgetItemAttribute(LiGadget, 0, #PB_ListIcon_ColumnWidth, 140)
AddGadgetColumn(LiGadget, 1, "Size", 80)
AddGadgetColumn(LiGadget, 2, "Templates included", 200)
If PrefPath$ = GetUserDirectory(#PB_Directory_ProgramData) + "PureBasic" + #PS$
SetGadgetState(DialogGadget(0, "checkbox_default_path"), 1)
OnClick_CheckBox()
EndIf
SetGadgetText(DialogGadget(0, "string_template_path"), PrefPath$)
AddKeyboardShortcut(DialogWindow(0), #PB_Shortcut_Delete, 0)
BindEvent(#PB_Event_Menu, @OnDelete())
If ExamineDirectory(0, BackupPath$, "*.prefs")
While NextDirectoryEntry(0)
If DirectoryEntryType(0) = #PB_DirectoryEntry_File And Left(DirectoryEntryName(0), 10) = "Templates_"
AddElement(BkTemplate())
BkTemplate()\FileName$ = BackupPath$ + DirectoryEntryName(0)
BkTemplate()\Date = DirectoryEntryDate(0, #PB_Date_Modified)
EndIf
Wend
FinishDirectory(0)
SortStructuredList(BkTemplate(), #PB_Sort_Descending, OffsetOf(Templates\Date), #PB_Quad)
ForEach BkTemplate()
Line$ = FormatDate("%dd.%mm.%yyyy %hh:%ii:%ss", BkTemplate()\Date) + #LF$ + Str(FileSize(BkTemplate()\FileName$)) + #LF$
Line$ + GetTemplateContent(BkTemplate()\FileName$)
AddGadgetItem(LiGadget, -1, Line$)
SetGadgetItemData(LiGadget, i, @BkTemplate())
i + 1
Next
EndIf
EndProcedure
Procedure DoBackup(Template$)
Protected i, Num = 1
While FileSize(BackupPath$ + "Templates_" + RSet(Str(Num), 3, "0") + ".prefs") > -1
Num + 1
Wend
CopyFile(Template$, BackupPath$ + "Templates_" + RSet(Str(Num), 3, "0") + ".prefs")
EndProcedure
Procedure MakeSureDirectoryExists(Dir$)
Protected Count, i, CurrDir$
If Right(Dir$, 1) <> #PS$
Dir$ + #PS$
EndIf
Count = CountString(Dir$, #PS$)
For i = 1 To Count
CurrDir$ + StringField(Dir$, i, #PS$) + #PS$
If FileSize(CurrDir$) <> -2
CreateDirectory(CurrDir$)
EndIf
Next i
EndProcedure
Procedure main()
Protected Path$, Template$, Own$
Protected Template_Size
Path$ = GetPathPart(GetEnvironmentVariable("PB_TOOL_Preferences"))
Own$ = GetUserDirectory(#PB_Directory_ProgramData) + "hex0r" + #PS$ + "IDE_bk" + #PS$
MakeSureDirectoryExists(Own$)
OpenPreferences(Own$ + "bk.prefs")
Template_Size = ReadPreferenceInteger("LastSize", -1)
BackupPath$ = ReadPreferenceString("BackupPath", "")
PrefPath$ = ReadPreferenceString("PrefPath", Path$)
If PrefPath$ = ""
PrefPath$ = GetUserDirectory(#PB_Directory_ProgramData) + "PureBasic" + #PS$
EndIf
ClosePreferences()
If BackupPath$ = ""
;first run
BackupPath$ = PathRequester("Select path to store template backups to", "")
If BackupPath$ = ""
MessageRequester("Quit", "Can't go on without knowing the backup path, closing now!")
ProcedureReturn
Else
CreatePreferences(Own$ + "bk.prefs")
WritePreferenceString("BackupPath", BackupPath$)
WritePreferenceString("PrefPath", PrefPath$)
ClosePreferences()
EndIf
EndIf
If Path$ = ""
InitRestore()
Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
ProcedureReturn
EndIf
Template$ = Path$ + "Templates.prefs"
If FileSize(Template$) <> Template_Size
Template_Size = FileSize(Template$)
DoBackup(Template$)
OpenPreferences(Own$ + "bk.prefs")
WritePreferenceInteger("LastSize", Template_Size)
ClosePreferences()
EndIf
EndProcedure
main()