[IDE-Tool] Templates Backup

Working on new editor enhancements?
User avatar
HeX0R
Addict
Addict
Posts: 1214
Joined: Mon Sep 20, 2004 7:12 am
Location: Hell

[IDE-Tool] Templates Backup

Post by HeX0R »

I didn't touch PB for a while and was going to create a small tool today.
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()
Last edited by HeX0R on Tue Oct 21, 2025 6:44 pm, edited 3 times in total.
Axolotl
Addict
Addict
Posts: 872
Joined: Wed Dec 31, 2008 3:36 pm

Re: Templates Backup Tool

Post by Axolotl »

Nice. Thanks for sharing.
To be honest, I don't really use the templates very much, but your post has reminded me that I should clean them up a bit.
Just because it worked doesn't mean it works.
PureBasic 6.04 (x86) and <latest stable version and current alpha/beta> (x64) on Windows 11 Home. Now started with Linux (VM: Ubuntu 22.04).
Quin
Addict
Addict
Posts: 1135
Joined: Thu Mar 31, 2022 7:03 pm
Location: Colorado, United States
Contact:

Re: Templates Backup Tool

Post by Quin »

I never explored the templates at all, thanks for introducing me to them! :D
Cool tool, too 8)
User avatar
le_magn
Enthusiast
Enthusiast
Posts: 289
Joined: Wed Aug 24, 2005 12:11 pm
Location: Italia

Re: Templates Backup Tool

Post by le_magn »

Thanks for this nice tool, added It to my PB...
Image
User avatar
HeX0R
Addict
Addict
Posts: 1214
Joined: Mon Sep 20, 2004 7:12 am
Location: Hell

Re: [IDE-Tool] Templates Backup

Post by HeX0R »

It happened again to me, therefore I've added a restore functionality.
Just start it outside of PB (not as a tool) to enter the restore GUI.
dcr3
Enthusiast
Enthusiast
Posts: 188
Joined: Fri Aug 04, 2017 11:03 pm

Re: [IDE-Tool] Templates Backup

Post by dcr3 »

Nice tool. Works. But restore button needs fixing. :mrgreen:
User avatar
HeX0R
Addict
Addict
Posts: 1214
Joined: Mon Sep 20, 2004 7:12 am
Location: Hell

Re: [IDE-Tool] Templates Backup

Post by HeX0R »

The button gets enabled as soon as you've selected a backup from the list, in case you meant that.
It doesn't make sense to enable a button "Restore", when there is nothing to restore.
Post Reply