Reset Module Algorithm¶
The full walkthrough of btnResetToDefault_ItemClick in FCoreModule_Popup.vb. This is the most algorithmically interesting handler — it's three-phase and operates on the live tab control plus the global default settings store.
Goal¶
Restore a module's tabs to its default set:
- Tabs that aren't in the default set are removed.
- Tabs in the default set that don't exist locally are added.
- Existing tabs that match by name have their contents reset to the default version.
- Tab order is rewritten to match the order in Instance.DefaultSaveAndShare.
Phase 1 — Resolve the default-tab folder¶
The default settings store (Instance.DefaultSaveAndShare) is a flat list of SaveAndShareFile entries. Each entry has a FolderPath that identifies which module it belongs to. This handler maps the module's ModuleID to a folder path:
Dim folderPath As String = ""
Select Case moduleID
Case "ExecutiveModule" : folderPath = "\\1. Executive\"
Case "FinancialModule" : folderPath = "\\2. Financial\"
Case "CustomerServiceModule" : folderPath = "\\3. Customer Service\"
Case "SalesMarketingModule" : folderPath = "\\4. Sales And Marketing\"
Case "InventoryModule" : folderPath = "\\5. Inventory\"
Case "PurchasingModule" : folderPath = "\\6. Purchasing\"
Case "ProductionModule" : folderPath = "\\7. Production\"
Case "MRPModule" : folderPath = "\\8. Material Requirements\"
Case "Analytical Dashboard" : folderPath = "\\9. Analytical Dashboard\"
End Select
If folderPath = "" Then
MsgBox("There are no default settings registered for this module.", MsgBoxStyle.Information)
Exit Sub
End If
Same mapping used by the existing per-tab reset in FPulseTab_Popup.btnResetTabToDefaultSettings_ItemClick. If ModuleID doesn't appear in this list (e.g. a custom module), the user gets an informational message and the handler exits cleanly.
Company defaults¶
If Instance.DefaultCompanySettings is non-Nothing, the handler also computes a company-specific default folder path and checks whether any defaults exist for it:
Dim companyFolderPath As String = ""
Dim hasCompanyDefaults As Boolean = False
If Instance.DefaultCompanySettings IsNot Nothing Then
companyFolderPath = "\\*" & Instance.License.CompanyName & " (" & AppCon.DatabaseName & ")" & "\" & folderPath.Trim("\") & "\"
For Each curFile As SaveAndShareFile In Instance.DefaultSaveAndShare.Tabs("")
If curFile.FolderPath = companyFolderPath Then
hasCompanyDefaults = True
Exit For
End If
Next
End If
Same precedence as the per-tab reset: company defaults are preferred when they exist.
Phase 2 — Confirm with the user¶
Two paths depending on whether company defaults exist:
Dim usePath As String
If hasCompanyDefaults Then
Dim result As MsgBoxResult = MsgBox(
"Reset the '" & curCoreModule.ModuleInfo.ModuleCaption & "' module to default?" & vbCrLf & vbCrLf &
"All tabs will be restored to defaults; tabs that aren't in the default set will be removed." & vbCrLf & vbCrLf &
"Yes = use your company's defaults" & vbCrLf &
"No = use Leahy Consulting's original defaults" & vbCrLf &
"Cancel = do nothing",
MsgBoxStyle.YesNoCancel Or MsgBoxStyle.Question, "Reset Module")
If result = MsgBoxResult.Cancel Then Exit Sub
usePath = If(result = MsgBoxResult.Yes, companyFolderPath, folderPath)
Else
If MsgBox(
"Reset the '" & curCoreModule.ModuleInfo.ModuleCaption & "' module to default?" & vbCrLf & vbCrLf &
"All tabs will be restored to defaults; tabs that aren't in the default set will be removed.",
MsgBoxStyle.YesNoCancel Or MsgBoxStyle.Question, "Reset Module") <> MsgBoxResult.Yes Then
Exit Sub
End If
usePath = folderPath
End If
| User input | Outcome |
|---|---|
| Yes (company defaults exist) | usePath = companyFolderPath |
| No (company defaults exist) | usePath = folderPath (Leahy original) |
| Yes (no company defaults) | usePath = folderPath |
| No / Cancel | Exit handler — no changes |
After this phase, usePath is the single folder path to read defaults from.
Phase 3 — Apply changes¶
Collect the default tabs¶
Dim defaultFiles As New List(Of SaveAndShareFile)
For Each curFile As SaveAndShareFile In Instance.DefaultSaveAndShare.Tabs("")
If curFile.FolderPath = usePath Then
defaultFiles.Add(curFile)
End If
Next
If defaultFiles.Count = 0 Then
MsgBox("There are no default tabs registered for this module.", MsgBoxStyle.Information)
Exit Sub
End If
defaultFiles is the list of tabs we want, in the order they appear in DefaultSaveAndShare. The order matters — it's used in step 3 to drive the final tab order.
Step 1 — Remove tabs not in the default set¶
Dim defaultNames As New HashSet(Of String)(StringComparer.OrdinalIgnoreCase)
For Each f As SaveAndShareFile In defaultFiles
defaultNames.Add(f.FileName)
Next
Dim toRemove As New List(Of MyTabPage)
For Each tp As MyTabPage In tc.TabPages
If Not defaultNames.Contains(tp.Text) Then
toRemove.Add(tp)
End If
Next
For Each tp As MyTabPage In toRemove
tc.TabPages.Remove(tp)
tp.Dispose()
Next
The HashSet(Of String) with OrdinalIgnoreCase makes the lookup O(1) and case-insensitive (matching the FileName.Equals patterns used elsewhere in the codebase).
The collect-then-remove pattern avoids modifying the collection during iteration.
Step 2 — Reset existing tabs / add missing ones¶
For i As Integer = 0 To defaultFiles.Count - 1
Dim defFile As SaveAndShareFile = defaultFiles(i)
Dim existing As MyTabPage = Nothing
For Each tp As MyTabPage In tc.TabPages
If String.Equals(tp.Text, defFile.FileName, StringComparison.OrdinalIgnoreCase) Then
existing = tp
Exit For
End If
Next
If existing Is Nothing Then
Dim newTab As New MyTabPage(True)
tc.TabPages.Add(newTab)
newTab.SerialData = PulseFileIO.DeserializeFromBuffer(
defFile.SaveAndShareData.ToArray, PulseFileIO.SerializationFlags.UseCompression)
newTab.LoadSettings()
Else
existing.SerialData = PulseFileIO.DeserializeFromBuffer(
defFile.SaveAndShareData.ToArray, PulseFileIO.SerializationFlags.UseCompression)
existing.LoadSettings()
End If
Next
For each file in defaultFiles:
- If a tab with that name exists locally → overwrite its SerialData with the deserialized default and call LoadSettings() to apply the change.
- If no such tab exists → construct a new MyTabPage(True), add it, set SerialData, call LoadSettings().
After step 2 the tab control contains exactly the right set of tabs — but the order may still be wrong (existing tabs kept their positions, new tabs were appended).
Step 3 — Reorder¶
For targetIndex As Integer = 0 To defaultFiles.Count - 1
Dim wantName As String = defaultFiles(targetIndex).FileName
Dim foundIndex As Integer = -1
For j As Integer = 0 To tc.TabPages.Count - 1
If String.Equals(tc.TabPages(j).Text, wantName, StringComparison.OrdinalIgnoreCase) Then
foundIndex = j
Exit For
End If
Next
If foundIndex >= 0 AndAlso foundIndex <> targetIndex Then
tc.TabPages.Move(targetIndex, tc.TabPages(foundIndex))
End If
Next
tc.PerformLayout()
Walks defaultFiles in order. For each one, finds where it currently lives in tc.TabPages and — if it's not already in the right slot — calls Move(targetIndex, page) to put it there.
MyTabControl.TabPages.Move(int, page) is the same DevExpress method used elsewhere in the codebase (e.g. FPulseTab_Popup.btnMoveLeft_ItemClick line 91).
PerformLayout() at the end forces the tab control to re-render with the new order.
Cursor + try/finally¶
The whole apply phase is wrapped:
Dim parentForm As Form = Activator.FindForm
If parentForm IsNot Nothing Then parentForm.Cursor = Cursors.WaitCursor
Try
' ... step 1, 2, 3 ...
Finally
If parentForm IsNot Nothing Then parentForm.Cursor = Cursors.Default
End Try
Wait cursor during the work; restored even if anything throws.
Edge cases¶
| Case | Handling |
|---|---|
Module has no entry in the Select Case mapping |
Info message, exit cleanly |
| Module is in the mapping but has no default files | Info message, exit cleanly |
| User cancels at confirmation | Exit cleanly, no changes |
| Tab name collision (case-insensitive) | Existing tab is reset (not duplicated) |
defaultFiles has duplicate names |
Step 2 finds the first match and resets it; step 3 may move it multiple times (idempotent — last move wins) |
| All current tabs are non-default | Every current tab gets removed in step 1, every default gets created in step 2 |
Risk notes¶
- Destructive on confirmation. Once the user clicks Yes, work begins immediately. There's no second confirmation.
- No undo. Save-and-Share-Module beforehand if the current state is worth preserving.
Dispose()on removed tabs. Step 1 callstp.Dispose(). This matches the disposal pattern inCCoreModule.Settings_DataLoadEnd, which similarly disposes tab pages before recreating them. If a tab was being focused-on at removal time, focus moves automatically to whatever page DevExpress chooses next.