Skip to content

Click Handlers

Per-handler implementation details for the five context menu items in FCoreModule_Popup.vb. For the high-level overview, see Menu Items. For the reset algorithm specifically, see Reset Module Algorithm.

Common preamble

Every handler starts with the same null-check:

If Activator Is Nothing OrElse Activator.m_CoreModule Is Nothing Then Exit Sub

Dim curCoreModule As CCoreModule = Activator.m_CoreModule

This is defensive — under normal flow Activator is always set by MyTabPage.ShowContextMenu before the popup opens. The early exit means a click on a stale popup is a silent no-op rather than an NPE.

Refresh Module

Private Sub btnRefresh_ItemClick(...) Handles btnRefresh.ItemClick
    If Activator Is Nothing OrElse Activator.m_CoreModule Is Nothing Then Exit Sub

    Dim curCoreModule As CCoreModule = Activator.m_CoreModule
    Dim parentForm As Form = Activator.FindForm
    If parentForm IsNot Nothing Then parentForm.Cursor = Cursors.WaitCursor

    Try
        For Each curTabPage As MyTabPage In curCoreModule.m_TabControl.TabPages
            If curTabPage.RefreshWithModule Then
                curTabPage.PulseContainer.RefreshAllBoxes()
            End If
        Next
    Finally
        If parentForm IsNot Nothing Then parentForm.Cursor = Cursors.Default
    End Try
End Sub

Iterates each Pulse tab in the module's inner m_TabControl and calls PulseContainer.RefreshAllBoxes() on tabs flagged RefreshWithModule. Lifted directly from the per-module loop in Main.vb (around line 1484) used by the global Refresh button.

The Try/Finally around the loop guarantees the wait cursor is restored even if a refresh throws.

Reset Module to Default Settings…

The biggest handler. Three phases: 1. Resolve the default-tab folder for this module (with company-default override). 2. Confirm with the user. 3. Apply the changes — remove non-defaults, reset/create matching tabs, reorder.

See Reset Module Algorithm for the full walkthrough.

Save and Share Module…

Private Sub btnSaveAndShare_ItemClick(...) Handles btnSaveAndShare.ItemClick
    If Activator Is Nothing OrElse Activator.m_CoreModule Is Nothing Then Exit Sub

    Dim curCoreModule As CCoreModule = Activator.m_CoreModule
    curCoreModule.Settings.RaiseOnDataSave()  ' (1)

    Dim newSS As New SaveAndShare.CSaveAndShareFile
    newSS.FileName = curCoreModule.ModuleInfo.ModuleCaption  ' (2)
    newSS.SerialData = curCoreModule.Settings.m_SerialData
    newSS.SettingsType = SaveAndShare.SettingsType.CORE_MODULE
    newSS.ShowSaveAsForm(Activator.FindForm)  ' (3)
End Sub
  1. RaiseOnDataSave() triggers CCoreModule.Settings_DataSaveBegin (around line 374), which flushes the live MyTabPage instances back into CoreModuleData.m_BoxModuleTabs. Without this, recently-edited tabs would be missing from the saved payload.
  2. Default filename is the module's display caption (e.g. "Customer Service"). The user can change it in the Save-As form.
  3. ShowSaveAsForm is the existing UI for the Save-and-Share dialog. Not new — same dialog used by the per-tab Save and Share.

The result is a .psm (or whatever extension CSaveAndShareFile.ShowSaveAsForm chooses based on SettingsType.CORE_MODULE) — the receiving side of this is Load Module from File….

Publish Module…

Private Sub btnPublish_ItemClick(...) Handles btnPublish.ItemClick
    If Activator Is Nothing OrElse Activator.m_CoreModule Is Nothing Then Exit Sub

    Dim curCoreModule As CCoreModule = Activator.m_CoreModule
    curCoreModule.Settings.RaiseOnDataSave()

    Dim newPF As New SaveAndShare.CPublishInfo_CSD_1(
        curCoreModule.Settings.m_SerialData,
        SaveAndShare.SettingsType.CORE_MODULE)
    newPF.PublishPolicy.PublishPolicyCode = SaveAndShare.PolicyCode.Everyone
    newPF.PublishMap.Add("Module", curCoreModule.ModuleInfo.ModuleID)
    newPF.ShowPublishForm(Instance.MainForm)
End Sub

Builds a CPublishInfo_CSD_1 matching exactly the shape CPulseConnection.ProcessPublishQueue expects:

Field Value Why
SerialData curCoreModule.Settings.m_SerialData The CCoreModuleData payload
SettingsType CORE_MODULE Discriminator the receiver dispatches on
PublishPolicy.PublishPolicyCode PolicyCode.Everyone Default — recipients see it as a normal published item
PublishMap("Module") ModuleID Receiver uses this to find \<ModuleID>.core virtual file

ShowPublishForm is the existing publishing UI — picks recipients, writes to their PublishQueue columns. See Publish/Receive Loop for the receiving side.

Load Module from File…

Private Sub btnLoadFromFile_ItemClick(...) Handles btnLoadFromFile.ItemClick
    If Activator Is Nothing OrElse Activator.m_CoreModule Is Nothing Then Exit Sub

    Dim fileDialog As New OpenFileDialog
    fileDialog.DefaultExt = "pmod"
    fileDialog.Filter = "Pulse Module (*.pmod)|*.pmod"
    If fileDialog.ShowDialog() <> DialogResult.OK Then Exit Sub

    Try
        Dim buffer() As Byte
        Using fileStream As New IO.FileStream(fileDialog.FileName, IO.FileMode.Open)
            ReDim buffer(fileStream.Length - 1)
            fileStream.Read(buffer, 0, fileStream.Length)
        End Using

        Dim ssFile As SaveAndShareFile = FileIO.Functions.DeserializeFromBuffer(
            buffer, FileIO.SerializationFlags.UseCompression)

        ' Confirm: replacing the module wipes out the current tabs.
        If MsgBox(
            "Loading this file will replace all tabs in the '" &
            Activator.m_CoreModule.ModuleInfo.ModuleCaption &
            "' module with the contents of '" &
            IO.Path.GetFileName(fileDialog.FileName) & "'." &
            vbCrLf & vbCrLf & "Continue?",
            MsgBoxStyle.OkCancel Or MsgBoxStyle.Question, "Load Module") <> MsgBoxResult.Ok Then
            Exit Sub
        End If

        Dim parentForm As Form = Activator.FindForm
        If parentForm IsNot Nothing Then parentForm.Cursor = Cursors.WaitCursor

        Try
            Dim newCoreData As CCoreModuleData = FileIO.Functions.DeserializeFromBuffer(
                ssFile.SaveAndShareData.ToArray, FileIO.SerializationFlags.UseCompression)
            newCoreData = newCoreData.UpgradeSerialData

            Activator.m_CoreModule.CoreModuleData = newCoreData
            Activator.m_CoreModule.Settings.RaiseOnDataLoad()
            Activator.m_CoreModule.m_TabControl.PerformLayout()
        Finally
            If parentForm IsNot Nothing Then parentForm.Cursor = Cursors.Default
        End Try

    Catch ex As Exception
        MsgBox("This file is not a valid Pulse Module (pmod) file." & vbCrLf & vbCrLf & ex.Message,
               MsgBoxStyle.Exclamation, "Load Module")
    End Try
End Sub

Key steps

  1. Open dialog with filter for *.pmod. The extension .pmod was chosen by analogy with the existing .ptab / .pbox conventions; if the existing Save-and-Share machinery writes core modules with a different extension, change DefaultExt and Filter to match.
  2. Read the file into a byte buffer. Standard FileStream.Read pattern.
  3. Deserialize as a SaveAndShareFile. This is the outer envelope.
  4. Confirm with the user before mutating anything.
  5. Deserialize the inner CCoreModuleData from ssFile.SaveAndShareData.
  6. UpgradeSerialData — runs the schema migration if the file is from an older Pulse version.
  7. Assign and raisem_CoreModule.CoreModuleData = newCoreData followed by Settings.RaiseOnDataLoad(). The existing CCoreModule.Settings_DataLoadEnd handler (in CCoreModule.vb around line 335) does the actual tab-rebuild work.
  8. PerformLayout() — forces a layout pass on the inner tab control.

Error handling

The whole thing is wrapped in Try/Catch. If any step fails (file read, deserialize, etc.), the user gets an MsgBox saying it's not a valid .pmod file. A more granular error path could distinguish "file IO failure" from "malformed payload" but the user-facing distinction is small enough that the catch-all is acceptable.