Skip to content

FCoreModule_Popup.vb

State before

The file existed but was an empty stub:

Public Class FCoreModule_Popup
End Class

The corresponding designer file (FCoreModule_Popup.Designer.vb) had a partial form with bar items already defined, but nothing was wiring it up — the form was never instantiated and the buttons had no click handlers. Some scaffolding existed in CCoreModule.vb (around lines 102–109) but was commented out.

State after

A full code-behind. The class:

  • Exposes an Activator property of type MyTabPage — set by the caller (MyTabPage.ShowContextMenu) so the click handlers know which core module to operate on.
  • Has a DefineContextMenu() method that explicitly wires the popup's items.
  • Has a BeforePopup handler that sets the menu caption and applies enable/disable rules based on Instance.LockUserSettings and Instance.PublisherMode.
  • Has a CloseUp handler that clears Activator (avoids holding a stale reference between popups).
  • Has five ItemClick handlers — one per menu item.

Imports

Imports PulseDevTools.ReportingModules
Imports PulseDevTools.TabControl
Imports PulseDevTools.TabControl.MyTabPage

Same imports as FPulseTab_Popup.vb. The third import (a class import, not a namespace) brings the nested ePageType into scope.

Activator pattern

Public Property Activator As TabControl.MyTabPage

The fully-qualified TabControl.MyTabPage is intentional — Activator collides with System.Activator, so the property type must be unambiguous. FPulseTab_Popup uses the same pattern.

The flow is:

  1. MyTabPage.ShowContextMenu sets s_CoreModule_ContextMenuForm.Activator = Me immediately before calling ShowPopup.
  2. BeforePopup and the click handlers read Activator to get the current core module.
  3. CloseUp clears it.

DefineContextMenu

FCoreModule_Popup.vb
Public Sub DefineContextMenu()
    PopupMenu1.Manager = BarManager1
    PopupMenu1.ShowCaption = True
    PopupMenu1.ClearLinks()
    PopupMenu1.AddItem(btnRefresh)
    PopupMenu1.AddItem(btnResetToDefault).BeginGroup = True
    PopupMenu1.AddItem(btnSaveAndShare)
    PopupMenu1.AddItem(btnPublish)
    PopupMenu1.AddItem(btnLoadFromFile)
End Sub

Mirrors the proven pattern in MyTabPage.DefinePopContextMenu. Called once on first creation by MyTabPage.ShowContextMenu. The BeginGroup = True on btnResetToDefault produces the visual separator after Refresh Module.

BeforePopup handler

Private Sub PopupMenu1_BeforePopup(...) Handles PopupMenu1.BeforePopup
    Dim myPopup As DevExpress.XtraBars.PopupMenu = sender

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

    myPopup.MenuCaption = "Module: " & Activator.m_CoreModule.ModuleInfo.ModuleCaption

    For Each curItemLink As XtraBars.BarItemLink In myPopup.ItemLinks
        If curItemLink.Item Is btnRefresh Then
            curItemLink.Item.Enabled = True
        Else
            curItemLink.Item.Enabled = Not Instance.LockUserSettings
        End If
    Next

    btnPublish.Enabled = Instance.PublisherMode AndAlso Not Instance.LockUserSettings
End Sub

Three responsibilities:

  1. Menu caption. Shows Module: <name> at the top of the popup so users can confirm which module they're acting on. Useful when right-clicking quickly between modules.
  2. Lock state. When Instance.LockUserSettings = True (a deployment-locked-down state), all state-mutating items are disabled. Refresh stays enabled — refreshing data isn't a "setting change."
  3. Publisher mode. Publish Module… requires both PublisherMode = True and the unlock state. This matches the existing rule for the per-tab Publish action in FPulseTab_Popup.

Why no e.Cancel

The Activator Is Nothing branch deliberately does not set e.Cancel = True. If the popup is invoked with a stale state, showing a slightly-off menu is more diagnostic for users than swallowing the click silently. In normal flow this branch should never be reached — MyTabPage.ShowContextMenu always sets Activator before ShowPopup.

Click handlers

Handler Purpose Cross-reference
btnRefresh_ItemClick Refresh every tab in the module Click Handlers — Refresh
btnResetToDefault_ItemClick Reset module to default tab set Reset Algorithm
btnSaveAndShare_ItemClick Save module via CSaveAndShareFile Click Handlers — Save and Share
btnPublish_ItemClick Publish to other users Publish/Receive Loop
btnLoadFromFile_ItemClick Load .pmod file Click Handlers — Load From File

All handlers start with the same null-check:

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

This is defensive — under normal flow Activator is always set, but if the popup is somehow shown without an Activator, the click is a no-op rather than an NPE.