Files
TeslaSuite/Console/TeslaConsole/PodActionDialog.cs
T
CydandClaude Opus 4.8 548550b312 Initial commit: TeslaSuite monorepo (TeslaConsole + TeslaLauncher)
Co-locate the two cockpit-pod projects into a single repository:

- Console/  : TeslaConsole, the net48 WinForms operator console (decompiled
              reconstruction) plus its differential + catalog test suite.
- Launcher/ : TeslaLauncher, the net6 pod-side Service + Agent rewrite.

Adds a combined TeslaSuite.sln, root README documenting the shared wire
contract (and its current duplication, the main follow-up), and a root
.gitignore. Histories were not preserved per request; this is a fresh start
from the current working state of both projects.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 14:43:28 -05:00

258 lines
5.5 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
namespace TeslaConsole;
public class PodActionDialog : Form
{
private delegate void ActionCompleted();
private class ActionItem
{
private readonly PodInfo mPodInfo;
private readonly Action<PodInfo> mAction;
private readonly ActionCompleted mActionCompleted;
private readonly ListViewItem rListViewItem;
private bool mDone;
private bool mCanceled;
private bool mError;
public ListViewItem ListViewItem => rListViewItem;
public bool Done
{
get
{
return mDone;
}
set
{
if (!mDone && value)
{
mDone = true;
mActionCompleted();
}
}
}
public bool Canceled
{
get
{
return mCanceled;
}
set
{
if (!mDone && !mCanceled && value)
{
mCanceled = true;
Done = true;
}
}
}
public bool Error => mError;
public ActionItem(PodInfo podInfo, Action<PodInfo> action, ActionCompleted complete)
{
mPodInfo = podInfo;
mAction = action;
mActionCompleted = complete;
rListViewItem = new ListViewItem(new string[2]
{
mPodInfo.Pod.Name,
"Connecting..."
});
}
public void Begin()
{
mPodInfo.EnqueueConnectAction(DoAction);
}
private void DoAction(PodInfo pod)
{
if (!mCanceled)
{
try
{
mAction(pod);
}
catch (Exception ex)
{
rListViewItem.SubItems[1].Text = ex.Message;
mError = true;
}
if (!mError)
{
rListViewItem.SubItems[1].Text = "Complete";
}
Done = true;
}
}
}
private IContainer components;
private Button mCancel;
private ListView mActionList;
private ColumnHeader mPodColumn;
private ColumnHeader mStatusColumn;
private readonly List<ActionItem> mActionItems = new List<ActionItem>();
private bool mDone;
private bool mError;
protected override void Dispose(bool disposing)
{
if (disposing && components != null)
{
components.Dispose();
}
base.Dispose(disposing);
}
private void InitializeComponent()
{
this.mCancel = new System.Windows.Forms.Button();
this.mActionList = new System.Windows.Forms.ListView();
this.mPodColumn = new System.Windows.Forms.ColumnHeader();
this.mStatusColumn = new System.Windows.Forms.ColumnHeader();
base.SuspendLayout();
this.mCancel.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right;
this.mCancel.Location = new System.Drawing.Point(377, 247);
this.mCancel.Name = "mCancel";
this.mCancel.Size = new System.Drawing.Size(75, 23);
this.mCancel.TabIndex = 0;
this.mCancel.Text = "Cancel";
this.mCancel.UseVisualStyleBackColor = true;
this.mCancel.Click += new System.EventHandler(mCancel_Click);
this.mActionList.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
this.mActionList.Columns.AddRange(new System.Windows.Forms.ColumnHeader[2] { this.mPodColumn, this.mStatusColumn });
this.mActionList.GridLines = true;
this.mActionList.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable;
this.mActionList.Location = new System.Drawing.Point(12, 12);
this.mActionList.MultiSelect = false;
this.mActionList.Name = "mActionList";
this.mActionList.Size = new System.Drawing.Size(440, 229);
this.mActionList.TabIndex = 1;
this.mActionList.UseCompatibleStateImageBehavior = false;
this.mActionList.View = System.Windows.Forms.View.Details;
this.mPodColumn.Text = "Pod";
this.mPodColumn.Width = 300;
this.mStatusColumn.Text = "Status";
this.mStatusColumn.Width = 120;
base.AutoScaleDimensions = new System.Drawing.SizeF(6f, 13f);
base.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
base.ClientSize = new System.Drawing.Size(464, 282);
base.Controls.Add(this.mActionList);
base.Controls.Add(this.mCancel);
base.Name = "PodActionDialog";
this.Text = "Performing Action...";
base.ResumeLayout(false);
}
public static void Show(ICollection<PodInfo> pods, Action<PodInfo> action, string title)
{
if (pods.Count > 0)
{
PodActionDialog podActionDialog = new PodActionDialog(pods, action, title);
if (!podActionDialog.IsDisposed)
{
podActionDialog.Show();
}
}
}
private PodActionDialog()
{
InitializeComponent();
}
private PodActionDialog(IEnumerable<PodInfo> pods, Action<PodInfo> action, string title)
: this()
{
Text = title;
foreach (PodInfo pod in pods)
{
ActionItem actionItem = new ActionItem(pod, action, ItemDone);
mActionItems.Add(actionItem);
mActionList.Items.Add(actionItem.ListViewItem);
}
foreach (ActionItem mActionItem in mActionItems)
{
mActionItem.Begin();
}
if (mActionItems.Count < 1)
{
ItemDone();
}
}
private void ItemDone()
{
if (mDone)
{
return;
}
foreach (ActionItem mActionItem in mActionItems)
{
if (!mActionItem.Done)
{
return;
}
if (mActionItem.Error)
{
mError = true;
}
}
mDone = true;
if (!mError)
{
Close();
}
else
{
mCancel.Text = "OK";
}
}
private void mCancel_Click(object sender, EventArgs e)
{
Close();
}
protected override void OnClosing(CancelEventArgs e)
{
if (!mDone)
{
if (MessageBox.Show("Are you sure you wish to cancel this action?", "Cancel?", MessageBoxButtons.YesNoCancel) == DialogResult.Yes)
{
foreach (ActionItem mActionItem in mActionItems)
{
mActionItem.Canceled = true;
}
}
e.Cancel = true;
}
else
{
base.OnClosing(e);
}
}
}