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