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