Server/MainForm.cs
author sl
Tue, 19 Aug 2014 17:29:52 +0200
changeset 36 a3aa661da810
parent 34 59bfa4ebcbbb
child 37 405a2590eda4
permissions -rw-r--r--
Adding warning when newly selected font is too height.
Reworking our UI.
sl@0
     1
using System;
sl@0
     2
using System.Collections.Generic;
sl@0
     3
using System.ComponentModel;
sl@0
     4
using System.Data;
sl@0
     5
using System.Drawing;
sl@0
     6
using System.Linq;
sl@0
     7
using System.Text;
sl@0
     8
using System.Threading.Tasks;
sl@0
     9
using System.Windows.Forms;
sl@14
    10
using System.IO;
sl@0
    11
using CodeProject.Dialog;
sl@14
    12
using System.Drawing.Imaging;
sl@17
    13
using System.ServiceModel;
sl@25
    14
using System.Threading;
sl@31
    15
using System.Diagnostics;
sl@25
    16
//
sl@22
    17
using SharpDisplayInterface;
sl@25
    18
using SharpDisplayClient;
sl@14
    19
sl@0
    20
sl@0
    21
namespace SharpDisplayManager
sl@0
    22
{
sl@0
    23
    public partial class MainForm : Form
sl@0
    24
    {
sl@2
    25
        DateTime LastTickTime;
sl@3
    26
        Display iDisplay;
sl@14
    27
        System.Drawing.Bitmap iBmp;
sl@14
    28
        bool iCreateBitmap; //Workaround render to bitmap issues when minimized
sl@17
    29
        ServiceHost iServiceHost;
sl@21
    30
        /// <summary>
sl@21
    31
        /// Our collection of clients
sl@21
    32
        /// </summary>
sl@33
    33
        public Dictionary<string, ClientData> iClients;
sl@29
    34
        public bool iClosing;
sl@2
    35
sl@0
    36
        public MainForm()
sl@0
    37
        {
sl@2
    38
            LastTickTime = DateTime.Now;
sl@3
    39
            iDisplay = new Display();
sl@33
    40
            iClients = new Dictionary<string, ClientData>();
sl@2
    41
sl@0
    42
            InitializeComponent();
sl@7
    43
            UpdateStatus();
sl@13
    44
sl@8
    45
            //Load settings
sl@8
    46
            marqueeLabelTop.Font = Properties.Settings.Default.DisplayFont;
sl@8
    47
            marqueeLabelBottom.Font = Properties.Settings.Default.DisplayFont;
sl@9
    48
            checkBoxShowBorders.Checked = Properties.Settings.Default.DisplayShowBorders;
sl@13
    49
            checkBoxConnectOnStartup.Checked = Properties.Settings.Default.DisplayConnectOnStartup;
sl@16
    50
            checkBoxReverseScreen.Checked = Properties.Settings.Default.DisplayReverseScreen;
sl@13
    51
            //
sl@13
    52
            tableLayoutPanel.CellBorderStyle = (checkBoxShowBorders.Checked ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
sl@14
    53
            //We have a bug when drawing minimized and reusing our bitmap
sl@14
    54
            iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
sl@14
    55
            iCreateBitmap = false;
sl@0
    56
        }
sl@0
    57
sl@13
    58
        private void MainForm_Load(object sender, EventArgs e)
sl@13
    59
        {
sl@17
    60
            StartServer();
sl@17
    61
sl@13
    62
            if (Properties.Settings.Default.DisplayConnectOnStartup)
sl@13
    63
            {
sl@13
    64
                iDisplay.Open();
sl@13
    65
                UpdateStatus();
sl@13
    66
            }
sl@13
    67
        }
sl@13
    68
sl@13
    69
sl@0
    70
        private void buttonFont_Click(object sender, EventArgs e)
sl@0
    71
        {
sl@0
    72
            //fontDialog.ShowColor = true;
sl@0
    73
            //fontDialog.ShowApply = true;
sl@0
    74
            fontDialog.ShowEffects = true;
sl@11
    75
            fontDialog.Font = marqueeLabelTop.Font;
sl@28
    76
sl@28
    77
            fontDialog.FixedPitchOnly = checkBoxFixedPitchFontOnly.Checked;
sl@28
    78
sl@0
    79
            //fontDialog.ShowHelp = true;
sl@0
    80
sl@0
    81
            //fontDlg.MaxSize = 40;
sl@0
    82
            //fontDlg.MinSize = 22;
sl@0
    83
sl@0
    84
            //fontDialog.Parent = this;
sl@0
    85
            //fontDialog.StartPosition = FormStartPosition.CenterParent;
sl@0
    86
sl@0
    87
            //DlgBox.ShowDialog(fontDialog);
sl@0
    88
sl@0
    89
            //if (fontDialog.ShowDialog(this) != DialogResult.Cancel)
sl@0
    90
            if (DlgBox.ShowDialog(fontDialog) != DialogResult.Cancel)
sl@0
    91
            {
sl@0
    92
sl@4
    93
                //MsgBox.Show("MessageBox MsgBox", "MsgBox caption");
sl@0
    94
sl@0
    95
                //MessageBox.Show("Ok");
sl@4
    96
                marqueeLabelTop.Font = fontDialog.Font;
sl@4
    97
                marqueeLabelBottom.Font = fontDialog.Font;
sl@8
    98
                Properties.Settings.Default.DisplayFont = fontDialog.Font;
sl@8
    99
                Properties.Settings.Default.Save();
sl@36
   100
                //
sl@36
   101
                if (fontDialog.Font.Height > marqueeLabelBottom.Height)
sl@36
   102
                {
sl@36
   103
                    labelWarning.Text = "WARNING: Selected font is too height by " + (fontDialog.Font.Height - marqueeLabelBottom.Height) + " pixels!";
sl@36
   104
                    labelWarning.Visible = true;
sl@36
   105
                }
sl@36
   106
                else
sl@36
   107
                {
sl@36
   108
                    labelWarning.Visible = false;
sl@36
   109
                }
sl@36
   110
sl@0
   111
            }
sl@0
   112
        }
sl@0
   113
sl@0
   114
        private void buttonCapture_Click(object sender, EventArgs e)
sl@0
   115
        {
sl@0
   116
            System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height);
sl@0
   117
            tableLayoutPanel.DrawToBitmap(bmp, tableLayoutPanel.ClientRectangle);
sl@14
   118
            //Bitmap bmpToSave = new Bitmap(bmp);
sl@14
   119
            bmp.Save("D:\\capture.png");
sl@14
   120
sl@17
   121
            marqueeLabelTop.Text = "Sweet";
sl@17
   122
sl@14
   123
            /*
sl@14
   124
            string outputFileName = "d:\\capture.png";
sl@14
   125
            using (MemoryStream memory = new MemoryStream())
sl@14
   126
            {
sl@14
   127
                using (FileStream fs = new FileStream(outputFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
sl@14
   128
                {
sl@14
   129
                    bmp.Save(memory, System.Drawing.Imaging.ImageFormat.Png);
sl@14
   130
                    byte[] bytes = memory.ToArray();
sl@14
   131
                    fs.Write(bytes, 0, bytes.Length);
sl@14
   132
                }
sl@14
   133
            }
sl@14
   134
             */
sl@14
   135
sl@0
   136
        }
sl@2
   137
sl@12
   138
        private void CheckForRequestResults()
sl@12
   139
        {
sl@12
   140
            if (iDisplay.IsRequestPending())
sl@12
   141
            {
sl@12
   142
                switch (iDisplay.AttemptRequestCompletion())
sl@12
   143
                {
sl@12
   144
                    case Display.TMiniDisplayRequest.EMiniDisplayRequestPowerSupplyStatus:
sl@12
   145
                        if (iDisplay.PowerSupplyStatus())
sl@12
   146
                        {
sl@12
   147
                            toolStripStatusLabelPower.Text = "ON";
sl@12
   148
                        }
sl@12
   149
                        else
sl@12
   150
                        {
sl@12
   151
                            toolStripStatusLabelPower.Text = "OFF";
sl@12
   152
                        }
sl@12
   153
                        //Issue next request then
sl@12
   154
                        iDisplay.RequestDeviceId();
sl@12
   155
                        break;
sl@12
   156
sl@12
   157
                    case Display.TMiniDisplayRequest.EMiniDisplayRequestDeviceId:
sl@12
   158
                        toolStripStatusLabelConnect.Text += " - " + iDisplay.DeviceId();
sl@12
   159
                        //Issue next request then
sl@12
   160
                        iDisplay.RequestFirmwareRevision();
sl@12
   161
                        break;
sl@12
   162
sl@12
   163
                    case Display.TMiniDisplayRequest.EMiniDisplayRequestFirmwareRevision:
sl@12
   164
                        toolStripStatusLabelConnect.Text += " v" + iDisplay.FirmwareRevision();
sl@12
   165
                        //No more request to issue
sl@12
   166
                        break;
sl@12
   167
                }
sl@12
   168
            }
sl@12
   169
        }
sl@12
   170
sl@16
   171
sl@16
   172
        public delegate int CoordinateTranslationDelegate(System.Drawing.Bitmap aBmp, int aInt);
sl@16
   173
sl@16
   174
sl@16
   175
        public static int ScreenReversedX(System.Drawing.Bitmap aBmp, int aX)
sl@16
   176
        {
sl@16
   177
            return aBmp.Width - aX - 1;
sl@16
   178
        }
sl@16
   179
sl@16
   180
        public int ScreenReversedY(System.Drawing.Bitmap aBmp, int aY)
sl@16
   181
        {
sl@16
   182
            return iBmp.Height - aY - 1;
sl@16
   183
        }
sl@16
   184
sl@16
   185
        public int ScreenX(System.Drawing.Bitmap aBmp, int aX)
sl@16
   186
        {
sl@16
   187
            return aX;
sl@16
   188
        }
sl@16
   189
sl@16
   190
        public int ScreenY(System.Drawing.Bitmap aBmp, int aY)
sl@16
   191
        {
sl@16
   192
            return aY;
sl@16
   193
        }
sl@16
   194
sl@16
   195
sl@16
   196
        //This is our timer tick responsible to perform our render
sl@2
   197
        private void timer_Tick(object sender, EventArgs e)
sl@14
   198
        {
sl@2
   199
            //Update our animations
sl@2
   200
            DateTime NewTickTime = DateTime.Now;
sl@2
   201
sl@2
   202
            marqueeLabelTop.UpdateAnimation(LastTickTime, NewTickTime);
sl@2
   203
            marqueeLabelBottom.UpdateAnimation(LastTickTime, NewTickTime);
sl@2
   204
sl@4
   205
            //Update our display
sl@4
   206
            if (iDisplay.IsOpen())
sl@4
   207
            {
sl@12
   208
                CheckForRequestResults();
sl@12
   209
sl@22
   210
                //Draw to bitmap
sl@14
   211
                if (iCreateBitmap)
sl@14
   212
                {
sl@14
   213
                    iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
sl@14
   214
                }
sl@14
   215
                tableLayoutPanel.DrawToBitmap(iBmp, tableLayoutPanel.ClientRectangle);
sl@14
   216
                //iBmp.Save("D:\\capture.png");
sl@16
   217
sl@16
   218
                //Select proper coordinate translation functions
sl@16
   219
                //We used delegate/function pointer to support reverse screen without doing an extra test on each pixels
sl@16
   220
                CoordinateTranslationDelegate screenX;
sl@16
   221
                CoordinateTranslationDelegate screenY;
sl@16
   222
sl@16
   223
                if (Properties.Settings.Default.DisplayReverseScreen)
sl@16
   224
                {
sl@16
   225
                    screenX = ScreenReversedX;
sl@16
   226
                    screenY = ScreenReversedY;
sl@16
   227
                }
sl@16
   228
                else
sl@16
   229
                {
sl@16
   230
                    screenX = ScreenX;
sl@16
   231
                    screenY = ScreenY;
sl@16
   232
                }
sl@22
   233
sl@7
   234
                //Send it to our display
sl@14
   235
                for (int i = 0; i < iBmp.Width; i++)
sl@4
   236
                {
sl@14
   237
                    for (int j = 0; j < iBmp.Height; j++)
sl@4
   238
                    {
sl@4
   239
                        unchecked
sl@4
   240
                        {
sl@14
   241
                            uint color = (uint)iBmp.GetPixel(i, j).ToArgb();
sl@14
   242
                            //For some reason when the app is minimized in the task bar only the alpha of our color is set.
sl@14
   243
                            //Thus that strange test for rendering to work both when the app is in the task bar and when it isn't.
sl@16
   244
                            iDisplay.SetPixel(screenX(iBmp, i), screenY(iBmp, j), Convert.ToInt32(!(color != 0xFF000000)));
sl@4
   245
                        }
sl@4
   246
                    }
sl@4
   247
                }
sl@4
   248
sl@4
   249
                iDisplay.SwapBuffers();
sl@4
   250
sl@4
   251
            }
sl@8
   252
sl@8
   253
            //Compute instant FPS
sl@8
   254
            toolStripStatusLabelFps.Text = (1.0/NewTickTime.Subtract(LastTickTime).TotalSeconds).ToString("F0") + " FPS";
sl@8
   255
sl@8
   256
            LastTickTime = NewTickTime;
sl@8
   257
sl@2
   258
        }
sl@3
   259
sl@3
   260
        private void buttonOpen_Click(object sender, EventArgs e)
sl@3
   261
        {
sl@3
   262
            if (iDisplay.Open())
sl@3
   263
            {
sl@7
   264
                UpdateStatus();
sl@12
   265
                iDisplay.RequestPowerSupplyStatus();
sl@3
   266
            }
sl@7
   267
            else
sl@7
   268
            {
sl@7
   269
                UpdateStatus();
sl@7
   270
                toolStripStatusLabelConnect.Text = "Connection error";
sl@7
   271
            }
sl@7
   272
sl@3
   273
        }
sl@3
   274
sl@3
   275
        private void buttonClose_Click(object sender, EventArgs e)
sl@3
   276
        {
sl@3
   277
            iDisplay.Close();
sl@9
   278
            UpdateStatus();
sl@3
   279
        }
sl@3
   280
sl@3
   281
        private void buttonClear_Click(object sender, EventArgs e)
sl@3
   282
        {
sl@3
   283
            iDisplay.Clear();
sl@3
   284
            iDisplay.SwapBuffers();
sl@3
   285
        }
sl@3
   286
sl@3
   287
        private void buttonFill_Click(object sender, EventArgs e)
sl@3
   288
        {
sl@3
   289
            iDisplay.Fill();
sl@3
   290
            iDisplay.SwapBuffers();
sl@3
   291
        }
sl@3
   292
sl@3
   293
        private void trackBarBrightness_Scroll(object sender, EventArgs e)
sl@3
   294
        {
sl@9
   295
            Properties.Settings.Default.DisplayBrightness = trackBarBrightness.Value;
sl@9
   296
            Properties.Settings.Default.Save();
sl@3
   297
            iDisplay.SetBrightness(trackBarBrightness.Value);
sl@9
   298
sl@3
   299
        }
sl@7
   300
sl@7
   301
        private void UpdateStatus()
sl@7
   302
        {
sl@7
   303
            if (iDisplay.IsOpen())
sl@7
   304
            {
sl@7
   305
                buttonFill.Enabled = true;
sl@7
   306
                buttonClear.Enabled = true;
sl@7
   307
                buttonOpen.Enabled = false;
sl@7
   308
                buttonClose.Enabled = true;
sl@7
   309
                trackBarBrightness.Enabled = true;
sl@7
   310
                trackBarBrightness.Minimum = iDisplay.MinBrightness();
sl@11
   311
                trackBarBrightness.Maximum = iDisplay.MaxBrightness();
sl@9
   312
                trackBarBrightness.Value = Properties.Settings.Default.DisplayBrightness;
sl@9
   313
                trackBarBrightness.LargeChange = Math.Max(1,(iDisplay.MaxBrightness() - iDisplay.MinBrightness())/5);
sl@9
   314
                trackBarBrightness.SmallChange = 1;
sl@9
   315
                iDisplay.SetBrightness(Properties.Settings.Default.DisplayBrightness);
sl@9
   316
sl@10
   317
                toolStripStatusLabelConnect.Text = "Connected - " + iDisplay.Vendor() + " - " + iDisplay.Product();
sl@10
   318
                //+ " - " + iDisplay.SerialNumber();
sl@7
   319
            }
sl@7
   320
            else
sl@7
   321
            {
sl@7
   322
                buttonFill.Enabled = false;
sl@7
   323
                buttonClear.Enabled = false;
sl@7
   324
                buttonOpen.Enabled = true;
sl@7
   325
                buttonClose.Enabled = false;
sl@7
   326
                trackBarBrightness.Enabled = false;
sl@9
   327
                toolStripStatusLabelConnect.Text = "Disconnected";
sl@7
   328
            }
sl@7
   329
        }
sl@9
   330
sl@13
   331
sl@13
   332
sl@9
   333
        private void checkBoxShowBorders_CheckedChanged(object sender, EventArgs e)
sl@9
   334
        {
sl@16
   335
            //Save our show borders setting
sl@13
   336
            tableLayoutPanel.CellBorderStyle = (checkBoxShowBorders.Checked ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
sl@9
   337
            Properties.Settings.Default.DisplayShowBorders = checkBoxShowBorders.Checked;
sl@9
   338
            Properties.Settings.Default.Save();
sl@9
   339
        }
sl@13
   340
sl@13
   341
        private void checkBoxConnectOnStartup_CheckedChanged(object sender, EventArgs e)
sl@13
   342
        {
sl@16
   343
            //Save our connect on startup setting
sl@13
   344
            Properties.Settings.Default.DisplayConnectOnStartup = checkBoxConnectOnStartup.Checked;
sl@13
   345
            Properties.Settings.Default.Save();
sl@13
   346
        }
sl@13
   347
sl@16
   348
        private void checkBoxReverseScreen_CheckedChanged(object sender, EventArgs e)
sl@16
   349
        {
sl@16
   350
            //Save our reverse screen setting
sl@16
   351
            Properties.Settings.Default.DisplayReverseScreen = checkBoxReverseScreen.Checked;
sl@16
   352
            Properties.Settings.Default.Save();
sl@16
   353
        }
sl@16
   354
sl@14
   355
        private void MainForm_Resize(object sender, EventArgs e)
sl@14
   356
        {
sl@14
   357
            if (WindowState == FormWindowState.Minimized)
sl@14
   358
            {
sl@14
   359
                // Do some stuff
sl@14
   360
                //iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
sl@14
   361
                iCreateBitmap = true;
sl@14
   362
            }
sl@14
   363
        }
sl@14
   364
sl@17
   365
        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
sl@17
   366
        {
sl@17
   367
            StopServer();
sl@32
   368
            e.Cancel = iClosing;
sl@17
   369
        }
sl@17
   370
sl@17
   371
        public void StartServer()
sl@17
   372
        {
sl@17
   373
            iServiceHost = new ServiceHost
sl@17
   374
                (
sl@17
   375
                    typeof(DisplayServer),
sl@20
   376
                    new Uri[] { new Uri("net.tcp://localhost:8001/") }
sl@17
   377
                );
sl@17
   378
sl@30
   379
            iServiceHost.AddServiceEndpoint(typeof(IDisplayService), new NetTcpBinding(SecurityMode.None,true), "DisplayService");
sl@17
   380
            iServiceHost.Open();
sl@17
   381
        }
sl@17
   382
sl@17
   383
        public void StopServer()
sl@17
   384
        {
sl@32
   385
            if (iClients.Count > 0 && !iClosing)
sl@29
   386
            {
sl@29
   387
                //Tell our clients
sl@32
   388
                iClosing = true;
sl@29
   389
                BroadcastCloseEvent();
sl@29
   390
            }
sl@32
   391
            else if (iClosing)
sl@32
   392
            {
sl@32
   393
                if (MessageBox.Show("Force exit?", "Waiting for clients...", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
sl@32
   394
                {
sl@32
   395
                    iClosing = false; //We make sure we force close if asked twice
sl@32
   396
                }
sl@32
   397
            }
sl@32
   398
            else
sl@36
   399
            {
sl@32
   400
                //We removed that as it often lags for some reason
sl@32
   401
                //iServiceHost.Close();
sl@32
   402
            }
sl@17
   403
        }
sl@17
   404
sl@21
   405
        public void BroadcastCloseEvent()
sl@21
   406
        {
sl@31
   407
            Trace.TraceInformation("BroadcastCloseEvent - start");
sl@31
   408
sl@21
   409
            var inactiveClients = new List<string>();
sl@21
   410
            foreach (var client in iClients)
sl@21
   411
            {
sl@21
   412
                //if (client.Key != eventData.ClientName)
sl@21
   413
                {
sl@21
   414
                    try
sl@21
   415
                    {
sl@31
   416
                        Trace.TraceInformation("BroadcastCloseEvent - " + client.Key);
sl@33
   417
                        client.Value.Callback.OnCloseOrder(/*eventData*/);
sl@21
   418
                    }
sl@21
   419
                    catch (Exception ex)
sl@21
   420
                    {
sl@21
   421
                        inactiveClients.Add(client.Key);
sl@21
   422
                    }
sl@21
   423
                }
sl@21
   424
            }
sl@21
   425
sl@21
   426
            if (inactiveClients.Count > 0)
sl@21
   427
            {
sl@21
   428
                foreach (var client in inactiveClients)
sl@21
   429
                {
sl@21
   430
                    iClients.Remove(client);
sl@30
   431
                    Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(client, false)[0]);
sl@21
   432
                }
sl@21
   433
            }
sl@21
   434
        }
sl@21
   435
sl@25
   436
        private void buttonStartClient_Click(object sender, EventArgs e)
sl@25
   437
        {
sl@25
   438
            Thread clientThread = new Thread(SharpDisplayClient.Program.Main);
sl@25
   439
            clientThread.Start();
sl@36
   440
            BringToFront();
sl@25
   441
        }
sl@25
   442
sl@27
   443
        private void buttonSuspend_Click(object sender, EventArgs e)
sl@27
   444
        {
sl@27
   445
            timer.Enabled = !timer.Enabled;
sl@27
   446
            if (!timer.Enabled)
sl@27
   447
            {
sl@27
   448
                buttonSuspend.Text = "Suspend";
sl@27
   449
            }
sl@27
   450
            else
sl@27
   451
            {
sl@27
   452
                buttonSuspend.Text = "Pause";
sl@27
   453
            }
sl@27
   454
        }
sl@27
   455
sl@29
   456
        private void buttonCloseClients_Click(object sender, EventArgs e)
sl@29
   457
        {
sl@29
   458
            BroadcastCloseEvent();
sl@29
   459
        }
sl@29
   460
sl@30
   461
        private void treeViewClients_AfterSelect(object sender, TreeViewEventArgs e)
sl@30
   462
        {
sl@21
   463
sl@30
   464
        }
sl@30
   465
sl@36
   466
        //Delegates are used for our thread safe method
sl@30
   467
        public delegate void AddClientDelegate(string aSessionId, IDisplayServiceCallback aCallback);
sl@30
   468
        public delegate void RemoveClientDelegate(string aSessionId);
sl@34
   469
        public delegate void SetTextDelegate(string SessionId, int aLineIndex, string aText);
sl@34
   470
        public delegate void SetTextsDelegate(string SessionId, System.Collections.Generic.IList<string> aTexts);
sl@32
   471
        public delegate void SetClientNameDelegate(string aSessionId, string aName);
sl@30
   472
sl@36
   473
sl@30
   474
        /// <summary>
sl@36
   475
        ///
sl@30
   476
        /// </summary>
sl@30
   477
        /// <param name="aSessionId"></param>
sl@30
   478
        /// <param name="aCallback"></param>
sl@30
   479
        public void AddClientThreadSafe(string aSessionId, IDisplayServiceCallback aCallback)
sl@30
   480
        {
sl@33
   481
            if (this.InvokeRequired)
sl@30
   482
            {
sl@30
   483
                //Not in the proper thread, invoke ourselves
sl@30
   484
                AddClientDelegate d = new AddClientDelegate(AddClientThreadSafe);
sl@30
   485
                this.Invoke(d, new object[] { aSessionId, aCallback });
sl@30
   486
            }
sl@30
   487
            else
sl@30
   488
            {
sl@30
   489
                //We are in the proper thread
sl@30
   490
                //Add this session to our collection of clients
sl@33
   491
                ClientData newClient = new ClientData(aSessionId, aCallback);
sl@33
   492
                Program.iMainForm.iClients.Add(aSessionId, newClient);
sl@30
   493
                //Add this session to our UI
sl@33
   494
                UpdateClientTreeViewNode(newClient);
sl@30
   495
            }
sl@30
   496
        }
sl@30
   497
sl@30
   498
        /// <summary>
sl@36
   499
        ///
sl@30
   500
        /// </summary>
sl@30
   501
        /// <param name="aSessionId"></param>
sl@30
   502
        public void RemoveClientThreadSafe(string aSessionId)
sl@30
   503
        {
sl@33
   504
            if (this.InvokeRequired)
sl@30
   505
            {
sl@30
   506
                //Not in the proper thread, invoke ourselves
sl@30
   507
                RemoveClientDelegate d = new RemoveClientDelegate(RemoveClientThreadSafe);
sl@30
   508
                this.Invoke(d, new object[] { aSessionId });
sl@30
   509
            }
sl@30
   510
            else
sl@30
   511
            {
sl@30
   512
                //We are in the proper thread
sl@33
   513
                //Remove this session from both client collection and UI tree view
sl@30
   514
                if (Program.iMainForm.iClients.Keys.Contains(aSessionId))
sl@30
   515
                {
sl@30
   516
                    Program.iMainForm.iClients.Remove(aSessionId);
sl@30
   517
                    Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(aSessionId, false)[0]);
sl@32
   518
                }
sl@32
   519
sl@32
   520
                if (iClosing && iClients.Count == 0)
sl@32
   521
                {
sl@32
   522
                    //We were closing our form
sl@32
   523
                    //All clients are now closed
sl@32
   524
                    //Just resume our close operation
sl@32
   525
                    iClosing = false;
sl@32
   526
                    Close();
sl@32
   527
                }
sl@30
   528
            }
sl@30
   529
        }
sl@30
   530
sl@30
   531
        /// <summary>
sl@36
   532
        ///
sl@30
   533
        /// </summary>
sl@30
   534
        /// <param name="aLineIndex"></param>
sl@30
   535
        /// <param name="aText"></param>
sl@34
   536
        public void SetTextThreadSafe(string aSessionId, int aLineIndex, string aText)
sl@30
   537
        {
sl@33
   538
            if (this.InvokeRequired)
sl@30
   539
            {
sl@30
   540
                //Not in the proper thread, invoke ourselves
sl@30
   541
                SetTextDelegate d = new SetTextDelegate(SetTextThreadSafe);
sl@34
   542
                this.Invoke(d, new object[] { aSessionId, aLineIndex, aText });
sl@30
   543
            }
sl@30
   544
            else
sl@30
   545
            {
sl@34
   546
                ClientData client = iClients[aSessionId];
sl@34
   547
                if (client != null)
sl@30
   548
                {
sl@34
   549
                    //Make sure all our texts are in place
sl@34
   550
                    while (client.Texts.Count < (aLineIndex + 1))
sl@34
   551
                    {
sl@34
   552
                        client.Texts.Add("");
sl@34
   553
                    }
sl@34
   554
                    client.Texts[aLineIndex] = aText;
sl@34
   555
sl@34
   556
                    //We are in the proper thread
sl@34
   557
                    //Only support two lines for now
sl@34
   558
                    if (aLineIndex == 0)
sl@34
   559
                    {
sl@36
   560
                        marqueeLabelTop.Text = aText;
sl@34
   561
                    }
sl@34
   562
                    else if (aLineIndex == 1)
sl@34
   563
                    {
sl@34
   564
                        marqueeLabelBottom.Text = aText;
sl@34
   565
                    }
sl@34
   566
sl@34
   567
sl@34
   568
                    UpdateClientTreeViewNode(client);
sl@30
   569
                }
sl@30
   570
            }
sl@30
   571
        }
sl@30
   572
sl@30
   573
        /// <summary>
sl@36
   574
        ///
sl@30
   575
        /// </summary>
sl@30
   576
        /// <param name="aTexts"></param>
sl@34
   577
        public void SetTextsThreadSafe(string aSessionId, System.Collections.Generic.IList<string> aTexts)
sl@30
   578
        {
sl@33
   579
            if (this.InvokeRequired)
sl@30
   580
            {
sl@30
   581
                //Not in the proper thread, invoke ourselves
sl@30
   582
                SetTextsDelegate d = new SetTextsDelegate(SetTextsThreadSafe);
sl@34
   583
                this.Invoke(d, new object[] { aSessionId, aTexts });
sl@30
   584
            }
sl@30
   585
            else
sl@30
   586
            {
sl@34
   587
                ClientData client = iClients[aSessionId];
sl@34
   588
                if (client != null)
sl@30
   589
                {
sl@34
   590
                    //Populate our client with the given texts
sl@34
   591
                    int j = 0;
sl@34
   592
                    foreach (string text in aTexts)
sl@30
   593
                    {
sl@34
   594
                        if (client.Texts.Count < (j + 1))
sl@34
   595
                        {
sl@34
   596
                            client.Texts.Add(text);
sl@34
   597
                        }
sl@34
   598
                        else
sl@34
   599
                        {
sl@34
   600
                            client.Texts[j]=text;
sl@34
   601
                        }
sl@34
   602
                        j++;
sl@30
   603
                    }
sl@34
   604
                    //We are in the proper thread
sl@34
   605
                    //Only support two lines for now
sl@34
   606
                    for (int i = 0; i < aTexts.Count; i++)
sl@30
   607
                    {
sl@34
   608
                        if (i == 0)
sl@34
   609
                        {
sl@34
   610
                            marqueeLabelTop.Text = aTexts[i];
sl@34
   611
                        }
sl@34
   612
                        else if (i == 1)
sl@34
   613
                        {
sl@34
   614
                            marqueeLabelBottom.Text = aTexts[i];
sl@34
   615
                        }
sl@30
   616
                    }
sl@34
   617
sl@34
   618
sl@34
   619
                    UpdateClientTreeViewNode(client);
sl@30
   620
                }
sl@30
   621
            }
sl@32
   622
        }
sl@30
   623
sl@32
   624
sl@32
   625
        /// <summary>
sl@36
   626
        ///
sl@32
   627
        /// </summary>
sl@32
   628
        /// <param name="aSessionId"></param>
sl@32
   629
        /// <param name="aName"></param>
sl@32
   630
        public void SetClientNameThreadSafe(string aSessionId, string aName)
sl@32
   631
        {
sl@32
   632
            if (this.InvokeRequired)
sl@32
   633
            {
sl@32
   634
                //Not in the proper thread, invoke ourselves
sl@32
   635
                SetClientNameDelegate d = new SetClientNameDelegate(SetClientNameThreadSafe);
sl@32
   636
                this.Invoke(d, new object[] { aSessionId, aName });
sl@32
   637
            }
sl@32
   638
            else
sl@32
   639
            {
sl@32
   640
                //We are in the proper thread
sl@33
   641
                //Get our client
sl@33
   642
                ClientData client = iClients[aSessionId];
sl@33
   643
                if (client != null)
sl@32
   644
                {
sl@33
   645
                    //Set its name
sl@33
   646
                    client.Name = aName;
sl@33
   647
                    //Update our tree-view
sl@33
   648
                    UpdateClientTreeViewNode(client);
sl@33
   649
                }
sl@33
   650
            }
sl@33
   651
        }
sl@33
   652
sl@33
   653
        /// <summary>
sl@36
   654
        ///
sl@33
   655
        /// </summary>
sl@33
   656
        /// <param name="aClient"></param>
sl@33
   657
        private void UpdateClientTreeViewNode(ClientData aClient)
sl@33
   658
        {
sl@33
   659
            if (aClient == null)
sl@33
   660
            {
sl@33
   661
                return;
sl@33
   662
            }
sl@33
   663
sl@33
   664
            TreeNode node = null;
sl@33
   665
            //Check that our client node already exists
sl@33
   666
            //Get our client root node using its key which is our session ID
sl@33
   667
            TreeNode[] nodes = treeViewClients.Nodes.Find(aClient.SessionId, false);
sl@33
   668
            if (nodes.Count()>0)
sl@33
   669
            {
sl@33
   670
                //We already have a node for that client
sl@33
   671
                node = nodes[0];
sl@33
   672
                //Clear children as we are going to recreate them below
sl@33
   673
                node.Nodes.Clear();
sl@33
   674
            }
sl@33
   675
            else
sl@33
   676
            {
sl@33
   677
                //Client node does not exists create a new one
sl@33
   678
                treeViewClients.Nodes.Add(aClient.SessionId, aClient.SessionId);
sl@33
   679
                node = treeViewClients.Nodes.Find(aClient.SessionId, false)[0];
sl@33
   680
            }
sl@33
   681
sl@33
   682
            if (node != null)
sl@33
   683
            {
sl@33
   684
                //Change its name
sl@33
   685
                if (aClient.Name != "")
sl@33
   686
                {
sl@33
   687
                    //We have a name, us it as text for our root node
sl@33
   688
                    node.Text = aClient.Name;
sl@32
   689
                    //Add a child with SessionId
sl@33
   690
                    node.Nodes.Add(new TreeNode(aClient.SessionId));
sl@33
   691
                }
sl@33
   692
                else
sl@33
   693
                {
sl@33
   694
                    //No name, use session ID instead
sl@33
   695
                    node.Text = aClient.SessionId;
sl@33
   696
                }
sl@36
   697
sl@33
   698
                if (aClient.Texts.Count > 0)
sl@33
   699
                {
sl@33
   700
                    //Create root node for our texts
sl@33
   701
                    TreeNode textsRoot = new TreeNode("Text");
sl@33
   702
                    node.Nodes.Add(textsRoot);
sl@33
   703
                    //For each text add a new entry
sl@33
   704
                    foreach (string text in aClient.Texts)
sl@33
   705
                    {
sl@33
   706
                        textsRoot.Nodes.Add(new TreeNode(text));
sl@33
   707
                    }
sl@32
   708
                }
sl@34
   709
sl@34
   710
                node.ExpandAll();
sl@32
   711
            }
sl@30
   712
        }
sl@17
   713
sl@36
   714
sl@0
   715
    }
sl@34
   716
sl@34
   717
    /// <summary>
sl@34
   718
    /// A UI thread copy of a client relevant data.
sl@34
   719
    /// Keeping this copy in the UI thread helps us deal with threading issues.
sl@34
   720
    /// </summary>
sl@34
   721
    public class ClientData
sl@34
   722
    {
sl@34
   723
        public ClientData(string aSessionId, IDisplayServiceCallback aCallback)
sl@34
   724
        {
sl@34
   725
            SessionId = aSessionId;
sl@34
   726
            Name = "";
sl@34
   727
            Texts = new List<string>();
sl@34
   728
            Callback = aCallback;
sl@34
   729
        }
sl@34
   730
sl@34
   731
        public string SessionId { get; set; }
sl@34
   732
        public string Name { get; set; }
sl@34
   733
        public List<string> Texts { get; set; }
sl@34
   734
        public IDisplayServiceCallback Callback { get; set; }
sl@34
   735
    }
sl@0
   736
}