Server/MainForm.cs
author sl
Sat, 17 Jan 2015 10:57:30 +0100
changeset 90 aa157e129c42
parent 88 4f09ae97cdcc
child 92 787dee27fc0a
permissions -rw-r--r--
Update checks now gives notification when the application is already up-to-date.
Adding version number to main form text.
     1 using System;
     2 using System.Collections.Generic;
     3 using System.ComponentModel;
     4 using System.Data;
     5 using System.Drawing;
     6 using System.Linq;
     7 using System.Text;
     8 using System.Threading.Tasks;
     9 using System.Windows.Forms;
    10 using System.IO;
    11 using CodeProject.Dialog;
    12 using System.Drawing.Imaging;
    13 using System.ServiceModel;
    14 using System.Threading;
    15 using System.Diagnostics;
    16 using System.Deployment.Application;
    17 //
    18 using SharpDisplayClient;
    19 using SharpDisplay;
    20 
    21 namespace SharpDisplayManager
    22 {
    23     //Types declarations
    24     public delegate uint ColorProcessingDelegate(int aX, int aY, uint aPixel);
    25     public delegate int CoordinateTranslationDelegate(System.Drawing.Bitmap aBmp, int aInt);
    26     //Delegates are used for our thread safe method
    27     public delegate void AddClientDelegate(string aSessionId, ICallback aCallback);
    28     public delegate void RemoveClientDelegate(string aSessionId);
    29     public delegate void SetFieldDelegate(string SessionId, DataField aField);
    30     public delegate void SetFieldsDelegate(string SessionId, System.Collections.Generic.IList<DataField> aFields);
    31     public delegate void SetLayoutDelegate(string SessionId, TableLayout aLayout);
    32     public delegate void SetClientNameDelegate(string aSessionId, string aName);
    33 
    34 
    35     /// <summary>
    36     /// Our Display manager main form
    37     /// </summary>
    38     public partial class MainForm : Form
    39     {
    40 
    41         DateTime LastTickTime;
    42         Display iDisplay;
    43         System.Drawing.Bitmap iBmp;
    44         bool iCreateBitmap; //Workaround render to bitmap issues when minimized
    45         ServiceHost iServiceHost;
    46         // Our collection of clients sorted by session id.
    47         public Dictionary<string, ClientData> iClients;
    48         // The name of the client which informations are currently displayed.
    49         public string iCurrentClientSessionId;
    50         ClientData iCurrentClientData;
    51         //
    52         public bool iClosing;
    53         //Function pointer for pixel color filtering
    54         ColorProcessingDelegate iColorFx;
    55         //Function pointer for pixel X coordinate intercept
    56         CoordinateTranslationDelegate iScreenX;
    57         //Function pointer for pixel Y coordinate intercept
    58         CoordinateTranslationDelegate iScreenY;
    59 
    60         public MainForm()
    61         {
    62             iCurrentClientSessionId = "";
    63             iCurrentClientData = null;
    64             LastTickTime = DateTime.Now;
    65             iDisplay = new Display();
    66             iClients = new Dictionary<string, ClientData>();
    67 
    68             InitializeComponent();
    69             UpdateStatus();
    70             //We have a bug when drawing minimized and reusing our bitmap
    71             iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
    72             iCreateBitmap = false;
    73         }
    74 
    75         private void MainForm_Load(object sender, EventArgs e)
    76         {
    77 			if (ApplicationDeployment.IsNetworkDeployed)
    78 			{
    79 				this.Text += " - v" + ApplicationDeployment.CurrentDeployment.CurrentVersion;
    80 			}
    81 			else
    82 			{
    83 				this.Text += " - development";
    84 			}
    85 
    86             StartServer();
    87 
    88             if (Properties.Settings.Default.DisplayConnectOnStartup)
    89             {
    90                 OpenDisplayConnection();
    91             }
    92         }
    93 
    94         /// <summary>
    95         /// Set our current client.
    96         /// This will take care of applying our client layout and set data fields.
    97         /// </summary>
    98         /// <param name="aSessionId"></param>
    99         void SetCurrentClient(string aSessionId)
   100         {
   101             if (aSessionId == iCurrentClientSessionId)
   102             {
   103                 //Given client is already the current one.
   104                 //Don't bother changing anything then.
   105                 return;
   106             }
   107 
   108             //Set current client ID.
   109             iCurrentClientSessionId = aSessionId;
   110             //Fetch and set current client data.
   111             iCurrentClientData = iClients[aSessionId];
   112             //Apply layout and set data fields.
   113             UpdateTableLayoutPanel(iCurrentClientData);
   114         }
   115 
   116         private void buttonFont_Click(object sender, EventArgs e)
   117         {
   118             //fontDialog.ShowColor = true;
   119             //fontDialog.ShowApply = true;
   120             fontDialog.ShowEffects = true;
   121             MarqueeLabel label = (MarqueeLabel)tableLayoutPanel.Controls[0];
   122             fontDialog.Font = label.Font;
   123 
   124             fontDialog.FixedPitchOnly = checkBoxFixedPitchFontOnly.Checked;
   125 
   126             //fontDialog.ShowHelp = true;
   127 
   128             //fontDlg.MaxSize = 40;
   129             //fontDlg.MinSize = 22;
   130 
   131             //fontDialog.Parent = this;
   132             //fontDialog.StartPosition = FormStartPosition.CenterParent;
   133 
   134             //DlgBox.ShowDialog(fontDialog);
   135 
   136             //if (fontDialog.ShowDialog(this) != DialogResult.Cancel)
   137             if (DlgBox.ShowDialog(fontDialog) != DialogResult.Cancel)
   138             {
   139 
   140                 //MsgBox.Show("MessageBox MsgBox", "MsgBox caption");
   141 
   142                 //MessageBox.Show("Ok");
   143                 foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
   144                 {
   145                     ctrl.Font = fontDialog.Font;
   146                 }
   147                 cds.Font = fontDialog.Font;
   148                 Properties.Settings.Default.Save();
   149                 //
   150                 CheckFontHeight();
   151             }
   152         }
   153 
   154         /// <summary>
   155         ///
   156         /// </summary>
   157         void CheckFontHeight()
   158         {
   159             //Show font height and width
   160             labelFontHeight.Text = "Font height: " + cds.Font.Height;
   161             float charWidth = IsFixedWidth(cds.Font);
   162             if (charWidth == 0.0f)
   163             {
   164                 labelFontWidth.Visible = false;
   165             }
   166             else
   167             {
   168                 labelFontWidth.Visible = true;
   169                 labelFontWidth.Text = "Font width: " + charWidth;
   170             }
   171 
   172             MarqueeLabel label = null;
   173             //Get the first label control we can find
   174             foreach (Control ctrl in tableLayoutPanel.Controls)
   175             {
   176                 if (ctrl is MarqueeLabel)
   177                 {
   178                     label = (MarqueeLabel)ctrl;
   179                     break;
   180                 }
   181             }
   182 
   183             //Now check font height and show a warning if needed.
   184             if (label != null && label.Font.Height > label.Height)
   185             {
   186                 labelWarning.Text = "WARNING: Selected font is too height by " + (label.Font.Height - label.Height) + " pixels!";
   187                 labelWarning.Visible = true;
   188             }
   189             else
   190             {
   191                 labelWarning.Visible = false;
   192             }
   193 
   194         }
   195 
   196         private void buttonCapture_Click(object sender, EventArgs e)
   197         {
   198             System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height);
   199             tableLayoutPanel.DrawToBitmap(bmp, tableLayoutPanel.ClientRectangle);
   200             //Bitmap bmpToSave = new Bitmap(bmp);
   201             bmp.Save("D:\\capture.png");
   202 
   203             ((MarqueeLabel)tableLayoutPanel.Controls[0]).Text = "Captured";
   204 
   205             /*
   206             string outputFileName = "d:\\capture.png";
   207             using (MemoryStream memory = new MemoryStream())
   208             {
   209                 using (FileStream fs = new FileStream(outputFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
   210                 {
   211                     bmp.Save(memory, System.Drawing.Imaging.ImageFormat.Png);
   212                     byte[] bytes = memory.ToArray();
   213                     fs.Write(bytes, 0, bytes.Length);
   214                 }
   215             }
   216              */
   217 
   218         }
   219 
   220         private void CheckForRequestResults()
   221         {
   222             if (iDisplay.IsRequestPending())
   223             {
   224                 switch (iDisplay.AttemptRequestCompletion())
   225                 {
   226                     case Display.TMiniDisplayRequest.EMiniDisplayRequestFirmwareRevision:
   227                         toolStripStatusLabelConnect.Text += " v" + iDisplay.FirmwareRevision();
   228                         //Issue next request then
   229                         iDisplay.RequestPowerSupplyStatus();
   230                         break;
   231 
   232                     case Display.TMiniDisplayRequest.EMiniDisplayRequestPowerSupplyStatus:
   233                         if (iDisplay.PowerSupplyStatus())
   234                         {
   235                             toolStripStatusLabelPower.Text = "ON";
   236                         }
   237                         else
   238                         {
   239                             toolStripStatusLabelPower.Text = "OFF";
   240                         }
   241                         //Issue next request then
   242                         iDisplay.RequestDeviceId();
   243                         break;
   244 
   245                     case Display.TMiniDisplayRequest.EMiniDisplayRequestDeviceId:
   246                         toolStripStatusLabelConnect.Text += " - " + iDisplay.DeviceId();
   247                         //No more request to issue
   248                         break;
   249                 }
   250             }
   251         }
   252 
   253         public static uint ColorWhiteIsOn(int aX, int aY, uint aPixel)
   254         {
   255             if ((aPixel & 0x00FFFFFF) == 0x00FFFFFF)
   256             {
   257                 return 0xFFFFFFFF;
   258             }
   259             return 0x00000000;
   260         }
   261 
   262         public static uint ColorUntouched(int aX, int aY, uint aPixel)
   263         {
   264             return aPixel;
   265         }
   266 
   267         public static uint ColorInversed(int aX, int aY, uint aPixel)
   268         {
   269             return ~aPixel;
   270         }
   271 
   272         public static uint ColorChessboard(int aX, int aY, uint aPixel)
   273         {
   274             if ((aX % 2 == 0) && (aY % 2 == 0))
   275             {
   276                 return ~aPixel;
   277             }
   278             else if ((aX % 2 != 0) && (aY % 2 != 0))
   279             {
   280                 return ~aPixel;
   281             }
   282             return 0x00000000;
   283         }
   284 
   285 
   286         public static int ScreenReversedX(System.Drawing.Bitmap aBmp, int aX)
   287         {
   288             return aBmp.Width - aX - 1;
   289         }
   290 
   291         public int ScreenReversedY(System.Drawing.Bitmap aBmp, int aY)
   292         {
   293             return iBmp.Height - aY - 1;
   294         }
   295 
   296         public int ScreenX(System.Drawing.Bitmap aBmp, int aX)
   297         {
   298             return aX;
   299         }
   300 
   301         public int ScreenY(System.Drawing.Bitmap aBmp, int aY)
   302         {
   303             return aY;
   304         }
   305 
   306         /// <summary>
   307         /// Select proper pixel delegates according to our current settings.
   308         /// </summary>
   309         private void SetupPixelDelegates()
   310         {
   311             //Select our pixel processing routine
   312             if (cds.InverseColors)
   313             {
   314                 //iColorFx = ColorChessboard;
   315                 iColorFx = ColorInversed;
   316             }
   317             else
   318             {
   319                 iColorFx = ColorWhiteIsOn;
   320             }
   321 
   322             //Select proper coordinate translation functions
   323             //We used delegate/function pointer to support reverse screen without doing an extra test on each pixels
   324             if (cds.ReverseScreen)
   325             {
   326                 iScreenX = ScreenReversedX;
   327                 iScreenY = ScreenReversedY;
   328             }
   329             else
   330             {
   331                 iScreenX = ScreenX;
   332                 iScreenY = ScreenY;
   333             }
   334 
   335         }
   336 
   337         //This is our timer tick responsible to perform our render
   338         private void timer_Tick(object sender, EventArgs e)
   339         {
   340             //Update our animations
   341             DateTime NewTickTime = DateTime.Now;
   342 
   343             //Update animation for all our marquees
   344             foreach (Control ctrl in tableLayoutPanel.Controls)
   345             {
   346                 if (ctrl is MarqueeLabel)
   347                 {
   348                     ((MarqueeLabel)ctrl).UpdateAnimation(LastTickTime, NewTickTime);
   349                 }
   350             }
   351 
   352 
   353             //Update our display
   354             if (iDisplay.IsOpen())
   355             {
   356                 CheckForRequestResults();
   357 
   358                 //Draw to bitmap
   359                 if (iCreateBitmap)
   360                 {
   361                     iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
   362                 }
   363                 tableLayoutPanel.DrawToBitmap(iBmp, tableLayoutPanel.ClientRectangle);
   364                 //iBmp.Save("D:\\capture.png");
   365 
   366                 //Send it to our display
   367                 for (int i = 0; i < iBmp.Width; i++)
   368                 {
   369                     for (int j = 0; j < iBmp.Height; j++)
   370                     {
   371                         unchecked
   372                         {
   373                             //Get our processed pixel coordinates
   374                             int x = iScreenX(iBmp, i);
   375                             int y = iScreenY(iBmp, j);
   376                             //Get pixel color
   377                             uint color = (uint)iBmp.GetPixel(i, j).ToArgb();
   378                             //Apply color effects
   379                             color = iColorFx(x,y,color);
   380                             //Now set our pixel
   381                             iDisplay.SetPixel(x, y, color);
   382                         }
   383                     }
   384                 }
   385 
   386                 iDisplay.SwapBuffers();
   387 
   388             }
   389 
   390             //Compute instant FPS
   391             toolStripStatusLabelFps.Text = (1.0/NewTickTime.Subtract(LastTickTime).TotalSeconds).ToString("F0") + " / " + (1000/timer.Interval).ToString() + " FPS";
   392 
   393             LastTickTime = NewTickTime;
   394 
   395         }
   396 
   397         private void OpenDisplayConnection()
   398         {
   399             CloseDisplayConnection();
   400 
   401             if (iDisplay.Open((Display.TMiniDisplayType)cds.DisplayType))
   402             {
   403                 UpdateStatus();
   404                 iDisplay.RequestFirmwareRevision();
   405             }
   406             else
   407             {
   408                 UpdateStatus();
   409                 toolStripStatusLabelConnect.Text = "Connection error";
   410             }
   411         }
   412 
   413         private void CloseDisplayConnection()
   414         {
   415             iDisplay.Close();
   416             UpdateStatus();
   417         }
   418 
   419         private void buttonOpen_Click(object sender, EventArgs e)
   420         {
   421             OpenDisplayConnection();
   422         }
   423 
   424         private void buttonClose_Click(object sender, EventArgs e)
   425         {
   426             CloseDisplayConnection();
   427         }
   428 
   429         private void buttonClear_Click(object sender, EventArgs e)
   430         {
   431             iDisplay.Clear();
   432             iDisplay.SwapBuffers();
   433         }
   434 
   435         private void buttonFill_Click(object sender, EventArgs e)
   436         {
   437             iDisplay.Fill();
   438             iDisplay.SwapBuffers();
   439         }
   440 
   441         private void trackBarBrightness_Scroll(object sender, EventArgs e)
   442         {
   443             cds.Brightness = trackBarBrightness.Value;
   444             Properties.Settings.Default.Save();
   445             iDisplay.SetBrightness(trackBarBrightness.Value);
   446 
   447         }
   448 
   449 
   450         /// <summary>
   451         /// CDS stands for Current Display Settings
   452         /// </summary>
   453         private DisplaySettings cds
   454         {
   455             get
   456             {
   457                 DisplaysSettings settings = Properties.Settings.Default.DisplaysSettings;
   458                 if (settings == null)
   459                 {
   460                     settings = new DisplaysSettings();
   461                     settings.Init();
   462                     Properties.Settings.Default.DisplaysSettings = settings;
   463                 }
   464 
   465                 //Make sure all our settings have been created
   466                 while (settings.Displays.Count <= Properties.Settings.Default.CurrentDisplayIndex)
   467                 {
   468                     settings.Displays.Add(new DisplaySettings());
   469                 }
   470 
   471                 DisplaySettings displaySettings = settings.Displays[Properties.Settings.Default.CurrentDisplayIndex];
   472                 return displaySettings;
   473             }
   474         }
   475 
   476         /// <summary>
   477         /// Check if the given font has a fixed character pitch.
   478         /// </summary>
   479         /// <param name="ft"></param>
   480         /// <returns>0.0f if this is not a monospace font, otherwise returns the character width.</returns>
   481         public float IsFixedWidth(Font ft)
   482         {
   483             Graphics g = CreateGraphics();
   484             char[] charSizes = new char[] { 'i', 'a', 'Z', '%', '#', 'a', 'B', 'l', 'm', ',', '.' };
   485             float charWidth = g.MeasureString("I", ft, Int32.MaxValue, StringFormat.GenericTypographic).Width;
   486 
   487             bool fixedWidth = true;
   488 
   489             foreach (char c in charSizes)
   490                 if (g.MeasureString(c.ToString(), ft, Int32.MaxValue, StringFormat.GenericTypographic).Width != charWidth)
   491                     fixedWidth = false;
   492 
   493             if (fixedWidth)
   494             {
   495                 return charWidth;
   496             }
   497 
   498             return 0.0f;
   499         }
   500 
   501         private void UpdateStatus()
   502         {
   503             //Synchronize UI with settings
   504             //Load settings
   505             checkBoxShowBorders.Checked = cds.ShowBorders;
   506             tableLayoutPanel.CellBorderStyle = (cds.ShowBorders ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
   507 
   508             //Set the proper font to each of our labels
   509             foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
   510             {
   511                 ctrl.Font = cds.Font;
   512             }
   513 
   514             CheckFontHeight();
   515             checkBoxConnectOnStartup.Checked = Properties.Settings.Default.DisplayConnectOnStartup;
   516             checkBoxReverseScreen.Checked = cds.ReverseScreen;
   517             checkBoxInverseColors.Checked = cds.InverseColors;
   518             comboBoxDisplayType.SelectedIndex = cds.DisplayType;
   519             timer.Interval = cds.TimerInterval;
   520             maskedTextBoxTimerInterval.Text = cds.TimerInterval.ToString();
   521             //
   522             SetupPixelDelegates();
   523 
   524             if (iDisplay.IsOpen())
   525             {
   526                 //Only setup brightness if display is open
   527                 trackBarBrightness.Minimum = iDisplay.MinBrightness();
   528                 trackBarBrightness.Maximum = iDisplay.MaxBrightness();
   529                 trackBarBrightness.Value = cds.Brightness;
   530                 trackBarBrightness.LargeChange = Math.Max(1, (iDisplay.MaxBrightness() - iDisplay.MinBrightness()) / 5);
   531                 trackBarBrightness.SmallChange = 1;
   532                 iDisplay.SetBrightness(cds.Brightness);
   533                 //
   534                 buttonFill.Enabled = true;
   535                 buttonClear.Enabled = true;
   536                 buttonOpen.Enabled = false;
   537                 buttonClose.Enabled = true;
   538                 trackBarBrightness.Enabled = true;
   539                 toolStripStatusLabelConnect.Text = "Connected - " + iDisplay.Vendor() + " - " + iDisplay.Product();
   540                 //+ " - " + iDisplay.SerialNumber();
   541 
   542                 if (iDisplay.SupportPowerOnOff())
   543                 {
   544                     buttonPowerOn.Enabled = true;
   545                     buttonPowerOff.Enabled = true;
   546                 }
   547                 else
   548                 {
   549                     buttonPowerOn.Enabled = false;
   550                     buttonPowerOff.Enabled = false;
   551                 }
   552 
   553                 if (iDisplay.SupportClock())
   554                 {
   555                     buttonShowClock.Enabled = true;
   556                     buttonHideClock.Enabled = true;
   557                 }
   558                 else
   559                 {
   560                     buttonShowClock.Enabled = false;
   561                     buttonHideClock.Enabled = false;
   562                 }
   563             }
   564             else
   565             {
   566                 buttonFill.Enabled = false;
   567                 buttonClear.Enabled = false;
   568                 buttonOpen.Enabled = true;
   569                 buttonClose.Enabled = false;
   570                 trackBarBrightness.Enabled = false;
   571                 buttonPowerOn.Enabled = false;
   572                 buttonPowerOff.Enabled = false;
   573                 buttonShowClock.Enabled = false;
   574                 buttonHideClock.Enabled = false;
   575                 toolStripStatusLabelConnect.Text = "Disconnected";
   576                 toolStripStatusLabelPower.Text = "N/A";
   577             }
   578         }
   579 
   580 
   581 
   582         private void checkBoxShowBorders_CheckedChanged(object sender, EventArgs e)
   583         {
   584             //Save our show borders setting
   585             tableLayoutPanel.CellBorderStyle = (checkBoxShowBorders.Checked ? TableLayoutPanelCellBorderStyle.Single : TableLayoutPanelCellBorderStyle.None);
   586             cds.ShowBorders = checkBoxShowBorders.Checked;
   587             Properties.Settings.Default.Save();
   588             CheckFontHeight();
   589         }
   590 
   591         private void checkBoxConnectOnStartup_CheckedChanged(object sender, EventArgs e)
   592         {
   593             //Save our connect on startup setting
   594             Properties.Settings.Default.DisplayConnectOnStartup = checkBoxConnectOnStartup.Checked;
   595             Properties.Settings.Default.Save();
   596         }
   597 
   598         private void checkBoxReverseScreen_CheckedChanged(object sender, EventArgs e)
   599         {
   600             //Save our reverse screen setting
   601             cds.ReverseScreen = checkBoxReverseScreen.Checked;
   602             Properties.Settings.Default.Save();
   603             SetupPixelDelegates();
   604         }
   605 
   606         private void checkBoxInverseColors_CheckedChanged(object sender, EventArgs e)
   607         {
   608             //Save our inverse colors setting
   609             cds.InverseColors = checkBoxInverseColors.Checked;
   610             Properties.Settings.Default.Save();
   611             SetupPixelDelegates();
   612         }
   613 
   614         private void MainForm_Resize(object sender, EventArgs e)
   615         {
   616             if (WindowState == FormWindowState.Minimized)
   617             {
   618                 // Do some stuff
   619                 //iBmp = new System.Drawing.Bitmap(tableLayoutPanel.Width, tableLayoutPanel.Height, PixelFormat.Format32bppArgb);
   620                 iCreateBitmap = true;
   621             }
   622         }
   623 
   624         private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
   625         {
   626             StopServer();
   627             e.Cancel = iClosing;
   628         }
   629 
   630         public void StartServer()
   631         {
   632             iServiceHost = new ServiceHost
   633                 (
   634                     typeof(Session),
   635                     new Uri[] { new Uri("net.tcp://localhost:8001/") }
   636                 );
   637 
   638             iServiceHost.AddServiceEndpoint(typeof(IService), new NetTcpBinding(SecurityMode.None, true), "DisplayService");
   639             iServiceHost.Open();
   640         }
   641 
   642         public void StopServer()
   643         {
   644             if (iClients.Count > 0 && !iClosing)
   645             {
   646                 //Tell our clients
   647                 iClosing = true;
   648                 BroadcastCloseEvent();
   649             }
   650             else if (iClosing)
   651             {
   652                 if (MessageBox.Show("Force exit?", "Waiting for clients...", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
   653                 {
   654                     iClosing = false; //We make sure we force close if asked twice
   655                 }
   656             }
   657             else
   658             {
   659                 //We removed that as it often lags for some reason
   660                 //iServiceHost.Close();
   661             }
   662         }
   663 
   664         public void BroadcastCloseEvent()
   665         {
   666             Trace.TraceInformation("BroadcastCloseEvent - start");
   667 
   668             var inactiveClients = new List<string>();
   669             foreach (var client in iClients)
   670             {
   671                 //if (client.Key != eventData.ClientName)
   672                 {
   673                     try
   674                     {
   675                         Trace.TraceInformation("BroadcastCloseEvent - " + client.Key);
   676                         client.Value.Callback.OnCloseOrder(/*eventData*/);
   677                     }
   678                     catch (Exception ex)
   679                     {
   680                         inactiveClients.Add(client.Key);
   681                     }
   682                 }
   683             }
   684 
   685             if (inactiveClients.Count > 0)
   686             {
   687                 foreach (var client in inactiveClients)
   688                 {
   689                     iClients.Remove(client);
   690                     Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(client, false)[0]);
   691                 }
   692             }
   693         }
   694 
   695         private void buttonStartClient_Click(object sender, EventArgs e)
   696         {
   697             Thread clientThread = new Thread(SharpDisplayClient.Program.Main);
   698             clientThread.Start();
   699             BringToFront();
   700         }
   701 
   702         private void buttonSuspend_Click(object sender, EventArgs e)
   703         {
   704             LastTickTime = DateTime.Now; //Reset timer to prevent jump
   705             timer.Enabled = !timer.Enabled;
   706             if (!timer.Enabled)
   707             {
   708                 buttonSuspend.Text = "Run";
   709             }
   710             else
   711             {
   712                 buttonSuspend.Text = "Pause";
   713             }
   714         }
   715 
   716         private void buttonCloseClients_Click(object sender, EventArgs e)
   717         {
   718             BroadcastCloseEvent();
   719         }
   720 
   721         private void treeViewClients_AfterSelect(object sender, TreeViewEventArgs e)
   722         {
   723 
   724         }
   725 
   726 
   727         /// <summary>
   728         ///
   729         /// </summary>
   730         /// <param name="aSessionId"></param>
   731         /// <param name="aCallback"></param>
   732         public void AddClientThreadSafe(string aSessionId, ICallback aCallback)
   733         {
   734             if (this.InvokeRequired)
   735             {
   736                 //Not in the proper thread, invoke ourselves
   737                 AddClientDelegate d = new AddClientDelegate(AddClientThreadSafe);
   738                 this.Invoke(d, new object[] { aSessionId, aCallback });
   739             }
   740             else
   741             {
   742                 //We are in the proper thread
   743                 //Add this session to our collection of clients
   744                 ClientData newClient = new ClientData(aSessionId, aCallback);
   745                 Program.iMainForm.iClients.Add(aSessionId, newClient);
   746                 //Add this session to our UI
   747                 UpdateClientTreeViewNode(newClient);
   748             }
   749         }
   750 
   751         /// <summary>
   752         ///
   753         /// </summary>
   754         /// <param name="aSessionId"></param>
   755         public void RemoveClientThreadSafe(string aSessionId)
   756         {
   757             if (this.InvokeRequired)
   758             {
   759                 //Not in the proper thread, invoke ourselves
   760                 RemoveClientDelegate d = new RemoveClientDelegate(RemoveClientThreadSafe);
   761                 this.Invoke(d, new object[] { aSessionId });
   762             }
   763             else
   764             {
   765                 //We are in the proper thread
   766                 //Remove this session from both client collection and UI tree view
   767                 if (Program.iMainForm.iClients.Keys.Contains(aSessionId))
   768                 {
   769                     Program.iMainForm.iClients.Remove(aSessionId);
   770                     Program.iMainForm.treeViewClients.Nodes.Remove(Program.iMainForm.treeViewClients.Nodes.Find(aSessionId, false)[0]);
   771                 }
   772 
   773                 if (iClosing && iClients.Count == 0)
   774                 {
   775                     //We were closing our form
   776                     //All clients are now closed
   777                     //Just resume our close operation
   778                     iClosing = false;
   779                     Close();
   780                 }
   781             }
   782         }
   783 
   784         /// <summary>
   785         ///
   786         /// </summary>
   787         /// <param name="aSessionId"></param>
   788         /// <param name="aLayout"></param>
   789         public void SetClientLayoutThreadSafe(string aSessionId, TableLayout aLayout)
   790         {
   791             if (this.InvokeRequired)
   792             {
   793                 //Not in the proper thread, invoke ourselves
   794                 SetLayoutDelegate d = new SetLayoutDelegate(SetClientLayoutThreadSafe);
   795                 this.Invoke(d, new object[] { aSessionId, aLayout });
   796             }
   797             else
   798             {
   799                 ClientData client = iClients[aSessionId];
   800                 if (client != null)
   801                 {
   802                     client.Layout = aLayout;
   803                     UpdateTableLayoutPanel(client);
   804                     //
   805                     UpdateClientTreeViewNode(client);
   806                 }
   807             }
   808         }
   809 
   810         /// <summary>
   811         ///
   812         /// </summary>
   813         /// <param name="aSessionId"></param>
   814         /// <param name="aField"></param>
   815         public void SetClientFieldThreadSafe(string aSessionId, DataField aField)
   816         {
   817             if (this.InvokeRequired)
   818             {
   819                 //Not in the proper thread, invoke ourselves
   820                 SetFieldDelegate d = new SetFieldDelegate(SetClientFieldThreadSafe);
   821                 this.Invoke(d, new object[] { aSessionId, aField });
   822             }
   823             else
   824             {
   825                 //We are in the proper thread
   826                 //Call the non-thread-safe variant
   827                 SetClientField(aSessionId, aField);
   828             }
   829         }
   830 
   831         /// <summary>
   832         ///
   833         /// </summary>
   834         /// <param name="aSessionId"></param>
   835         /// <param name="aField"></param>
   836         private void SetClientField(string aSessionId, DataField aField)
   837         {
   838             SetCurrentClient(aSessionId);
   839             ClientData client = iClients[aSessionId];
   840             if (client != null)
   841             {
   842                 bool somethingChanged = false;
   843 
   844                 //Make sure all our fields are in place
   845                 while (client.Fields.Count < (aField.Index + 1))
   846                 {
   847                     //Add a text field with proper index
   848                     client.Fields.Add(new DataField(client.Fields.Count));
   849                     somethingChanged = true;
   850                 }
   851 
   852                 if (client.Fields[aField.Index].IsSameLayout(aField))
   853                 {
   854                     //Same layout just update our field
   855                     client.Fields[aField.Index] = aField;
   856                     //
   857                     if (aField.IsText && tableLayoutPanel.Controls[aField.Index] is MarqueeLabel)
   858                     {
   859                         //Text field control already in place, just change the text
   860                         MarqueeLabel label = (MarqueeLabel)tableLayoutPanel.Controls[aField.Index];
   861                         somethingChanged = (label.Text != aField.Text || label.TextAlign != aField.Alignment);
   862                         label.Text = aField.Text;
   863                         label.TextAlign = aField.Alignment;
   864                     }
   865                     else if (aField.IsBitmap && tableLayoutPanel.Controls[aField.Index] is PictureBox)
   866                     {
   867                         somethingChanged = true; //TODO: Bitmap comp or should we leave that to clients?
   868                         //Bitmap field control already in place just change the bitmap
   869                         PictureBox pictureBox = (PictureBox)tableLayoutPanel.Controls[aField.Index];
   870                         pictureBox.Image = aField.Bitmap;
   871                     }
   872                     else
   873                     {
   874                         somethingChanged = true;
   875                         //The requested control in our layout it not of the correct type
   876                         //Wrong control type, re-create them all
   877                         UpdateTableLayoutPanel(iCurrentClientData);
   878                     }
   879                 }
   880                 else
   881                 {
   882                     somethingChanged = true;
   883                     //Different layout, need to rebuild it
   884                     client.Fields[aField.Index] = aField;
   885                     UpdateTableLayoutPanel(iCurrentClientData);
   886                 }
   887 
   888                 //
   889                 if (somethingChanged)
   890                 {
   891                     UpdateClientTreeViewNode(client);
   892                 }
   893             }
   894         }
   895 
   896         /// <summary>
   897         ///
   898         /// </summary>
   899         /// <param name="aTexts"></param>
   900         public void SetClientFieldsThreadSafe(string aSessionId, System.Collections.Generic.IList<DataField> aFields)
   901         {
   902             if (this.InvokeRequired)
   903             {
   904                 //Not in the proper thread, invoke ourselves
   905                 SetFieldsDelegate d = new SetFieldsDelegate(SetClientFieldsThreadSafe);
   906                 this.Invoke(d, new object[] { aSessionId, aFields });
   907             }
   908             else
   909             {
   910                 //Put each our text fields in a label control
   911                 foreach (DataField field in aFields)
   912                 {
   913                     SetClientField(aSessionId, field);
   914                 }
   915             }
   916         }
   917 
   918         /// <summary>
   919         ///
   920         /// </summary>
   921         /// <param name="aSessionId"></param>
   922         /// <param name="aName"></param>
   923         public void SetClientNameThreadSafe(string aSessionId, string aName)
   924         {
   925             if (this.InvokeRequired)
   926             {
   927                 //Not in the proper thread, invoke ourselves
   928                 SetClientNameDelegate d = new SetClientNameDelegate(SetClientNameThreadSafe);
   929                 this.Invoke(d, new object[] { aSessionId, aName });
   930             }
   931             else
   932             {
   933                 //We are in the proper thread
   934                 //Get our client
   935                 ClientData client = iClients[aSessionId];
   936                 if (client != null)
   937                 {
   938                     //Set its name
   939                     client.Name = aName;
   940                     //Update our tree-view
   941                     UpdateClientTreeViewNode(client);
   942                 }
   943             }
   944         }
   945 
   946         /// <summary>
   947         ///
   948         /// </summary>
   949         /// <param name="aClient"></param>
   950         private void UpdateClientTreeViewNode(ClientData aClient)
   951         {
   952             if (aClient == null)
   953             {
   954                 return;
   955             }
   956 
   957             TreeNode node = null;
   958             //Check that our client node already exists
   959             //Get our client root node using its key which is our session ID
   960             TreeNode[] nodes = treeViewClients.Nodes.Find(aClient.SessionId, false);
   961             if (nodes.Count()>0)
   962             {
   963                 //We already have a node for that client
   964                 node = nodes[0];
   965                 //Clear children as we are going to recreate them below
   966                 node.Nodes.Clear();
   967             }
   968             else
   969             {
   970                 //Client node does not exists create a new one
   971                 treeViewClients.Nodes.Add(aClient.SessionId, aClient.SessionId);
   972                 node = treeViewClients.Nodes.Find(aClient.SessionId, false)[0];
   973             }
   974 
   975             if (node != null)
   976             {
   977                 //Change its name
   978                 if (aClient.Name != "")
   979                 {
   980                     //We have a name, us it as text for our root node
   981                     node.Text = aClient.Name;
   982                     //Add a child with SessionId
   983                     node.Nodes.Add(new TreeNode(aClient.SessionId));
   984                 }
   985                 else
   986                 {
   987                     //No name, use session ID instead
   988                     node.Text = aClient.SessionId;
   989                 }
   990 
   991                 if (aClient.Fields.Count > 0)
   992                 {
   993                     //Create root node for our texts
   994                     TreeNode textsRoot = new TreeNode("Fields");
   995                     node.Nodes.Add(textsRoot);
   996                     //For each text add a new entry
   997                     foreach (DataField field in aClient.Fields)
   998                     {
   999                         if (!field.IsBitmap)
  1000                         {
  1001                             DataField textField = (DataField)field;
  1002                             textsRoot.Nodes.Add(new TreeNode("[Text]" + textField.Text));
  1003                         }
  1004                         else
  1005                         {
  1006                             textsRoot.Nodes.Add(new TreeNode("[Bitmap]"));
  1007                         }
  1008                     }
  1009                 }
  1010 
  1011                 node.ExpandAll();
  1012             }
  1013         }
  1014 
  1015         private void buttonAddRow_Click(object sender, EventArgs e)
  1016         {
  1017             if (tableLayoutPanel.RowCount < 6)
  1018             {
  1019                 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount, tableLayoutPanel.RowCount + 1);
  1020             }
  1021         }
  1022 
  1023         private void buttonRemoveRow_Click(object sender, EventArgs e)
  1024         {
  1025             if (tableLayoutPanel.RowCount > 1)
  1026             {
  1027                 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount, tableLayoutPanel.RowCount - 1);
  1028             }
  1029 
  1030             UpdateTableLayoutRowStyles();
  1031         }
  1032 
  1033         private void buttonAddColumn_Click(object sender, EventArgs e)
  1034         {
  1035             if (tableLayoutPanel.ColumnCount < 8)
  1036             {
  1037                 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount + 1, tableLayoutPanel.RowCount);
  1038             }
  1039         }
  1040 
  1041         private void buttonRemoveColumn_Click(object sender, EventArgs e)
  1042         {
  1043             if (tableLayoutPanel.ColumnCount > 1)
  1044             {
  1045                 UpdateTableLayoutPanel(tableLayoutPanel.ColumnCount - 1, tableLayoutPanel.RowCount);
  1046             }
  1047         }
  1048 
  1049 
  1050         /// <summary>
  1051         /// Update our table layout row styles to make sure each rows have similar height
  1052         /// </summary>
  1053         private void UpdateTableLayoutRowStyles()
  1054         {
  1055             foreach (RowStyle rowStyle in tableLayoutPanel.RowStyles)
  1056             {
  1057                 rowStyle.SizeType = SizeType.Percent;
  1058                 rowStyle.Height = 100 / tableLayoutPanel.RowCount;
  1059             }
  1060         }
  1061 
  1062         /// DEPRECATED
  1063         /// <summary>
  1064         /// Empty and recreate our table layout with the given number of columns and rows.
  1065         /// Sizes of rows and columns are uniform.
  1066         /// </summary>
  1067         /// <param name="aColumn"></param>
  1068         /// <param name="aRow"></param>
  1069         private void UpdateTableLayoutPanel(int aColumn, int aRow)
  1070         {
  1071             tableLayoutPanel.Controls.Clear();
  1072             tableLayoutPanel.RowStyles.Clear();
  1073             tableLayoutPanel.ColumnStyles.Clear();
  1074             tableLayoutPanel.RowCount = 0;
  1075             tableLayoutPanel.ColumnCount = 0;
  1076 
  1077             while (tableLayoutPanel.RowCount < aRow)
  1078             {
  1079                 tableLayoutPanel.RowCount++;
  1080             }
  1081 
  1082             while (tableLayoutPanel.ColumnCount < aColumn)
  1083             {
  1084                 tableLayoutPanel.ColumnCount++;
  1085             }
  1086 
  1087             for (int i = 0; i < tableLayoutPanel.ColumnCount; i++)
  1088             {
  1089                 //Create our column styles
  1090                 this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100 / tableLayoutPanel.ColumnCount));
  1091 
  1092                 for (int j = 0; j < tableLayoutPanel.RowCount; j++)
  1093                 {
  1094                     if (i == 0)
  1095                     {
  1096                         //Create our row styles
  1097                         this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100 / tableLayoutPanel.RowCount));
  1098                     }
  1099 
  1100                     MarqueeLabel control = new SharpDisplayManager.MarqueeLabel();
  1101                     control.AutoEllipsis = true;
  1102                     control.AutoSize = true;
  1103                     control.BackColor = System.Drawing.Color.Transparent;
  1104                     control.Dock = System.Windows.Forms.DockStyle.Fill;
  1105                     control.Location = new System.Drawing.Point(1, 1);
  1106                     control.Margin = new System.Windows.Forms.Padding(0);
  1107                     control.Name = "marqueeLabelCol" + aColumn + "Row" + aRow;
  1108                     control.OwnTimer = false;
  1109                     control.PixelsPerSecond = 64;
  1110                     control.Separator = "|";
  1111                     //control.Size = new System.Drawing.Size(254, 30);
  1112                     //control.TabIndex = 2;
  1113                     control.Font = cds.Font;
  1114                     control.Text = "ABCDEFGHIJKLMNOPQRST-0123456789";
  1115                     control.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
  1116                     control.UseCompatibleTextRendering = true;
  1117                     //
  1118                     tableLayoutPanel.Controls.Add(control, i, j);
  1119                 }
  1120             }
  1121 
  1122             CheckFontHeight();
  1123         }
  1124 
  1125 
  1126         /// <summary>
  1127         /// Update our display table layout.
  1128         /// </summary>
  1129         /// <param name="aLayout"></param>
  1130         private void UpdateTableLayoutPanel(ClientData aClient)
  1131         {
  1132             TableLayout layout = aClient.Layout;
  1133             int fieldCount = 0;
  1134 
  1135             tableLayoutPanel.Controls.Clear();
  1136             tableLayoutPanel.RowStyles.Clear();
  1137             tableLayoutPanel.ColumnStyles.Clear();
  1138             tableLayoutPanel.RowCount = 0;
  1139             tableLayoutPanel.ColumnCount = 0;
  1140 
  1141             while (tableLayoutPanel.RowCount < layout.Rows.Count)
  1142             {
  1143                 tableLayoutPanel.RowCount++;
  1144             }
  1145 
  1146             while (tableLayoutPanel.ColumnCount < layout.Columns.Count)
  1147             {
  1148                 tableLayoutPanel.ColumnCount++;
  1149             }
  1150 
  1151             for (int i = 0; i < tableLayoutPanel.ColumnCount; i++)
  1152             {
  1153                 //Create our column styles
  1154                 this.tableLayoutPanel.ColumnStyles.Add(layout.Columns[i]);
  1155 
  1156                 for (int j = 0; j < tableLayoutPanel.RowCount; j++)
  1157                 {
  1158                     if (i == 0)
  1159                     {
  1160                         //Create our row styles
  1161                         this.tableLayoutPanel.RowStyles.Add(layout.Rows[j]);
  1162                     }
  1163 
  1164                     //Check if we already have a control
  1165                     Control existingControl = tableLayoutPanel.GetControlFromPosition(i,j);
  1166                     if (existingControl!=null)
  1167                     {
  1168                         //We already have a control in that cell as a results of row/col spanning
  1169                         //Move on to next cell then
  1170                         continue;
  1171                     }
  1172 
  1173                     fieldCount++;
  1174 
  1175                     //Check if a client field already exists for that cell
  1176                     if (aClient.Fields.Count <= tableLayoutPanel.Controls.Count)
  1177                     {
  1178                         //No client field specified, create a text field by default
  1179                         aClient.Fields.Add(new DataField(aClient.Fields.Count));
  1180                     }
  1181 
  1182                     //Create a control corresponding to the field specified for that cell
  1183                     DataField field = aClient.Fields[tableLayoutPanel.Controls.Count];
  1184                     Control control = CreateControlForDataField(field);
  1185 
  1186                     //Add newly created control to our table layout at the specified row and column
  1187                     tableLayoutPanel.Controls.Add(control, i, j);
  1188                     //Make sure we specify row and column span for that new control
  1189                     tableLayoutPanel.SetRowSpan(control,field.RowSpan);
  1190                     tableLayoutPanel.SetColumnSpan(control, field.ColumnSpan);
  1191                 }
  1192             }
  1193 
  1194             //
  1195             while (aClient.Fields.Count > fieldCount)
  1196             {
  1197                 //We have too much fields for this layout
  1198                 //Just discard them until we get there
  1199                 aClient.Fields.RemoveAt(aClient.Fields.Count-1);
  1200             }
  1201 
  1202             CheckFontHeight();
  1203         }
  1204 
  1205         /// <summary>
  1206         /// Check our type of data field and create corresponding control
  1207         /// </summary>
  1208         /// <param name="aField"></param>
  1209         private Control CreateControlForDataField(DataField aField)
  1210         {
  1211             Control control=null;
  1212             if (!aField.IsBitmap)
  1213             {
  1214                 MarqueeLabel label = new SharpDisplayManager.MarqueeLabel();
  1215                 label.AutoEllipsis = true;
  1216                 label.AutoSize = true;
  1217                 label.BackColor = System.Drawing.Color.Transparent;
  1218                 label.Dock = System.Windows.Forms.DockStyle.Fill;
  1219                 label.Location = new System.Drawing.Point(1, 1);
  1220                 label.Margin = new System.Windows.Forms.Padding(0);
  1221                 label.Name = "marqueeLabel" + aField.Index;
  1222                 label.OwnTimer = false;
  1223                 label.PixelsPerSecond = 64;
  1224                 label.Separator = "|";
  1225                 //control.Size = new System.Drawing.Size(254, 30);
  1226                 //control.TabIndex = 2;
  1227                 label.Font = cds.Font;
  1228 
  1229                 label.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
  1230                 label.UseCompatibleTextRendering = true;
  1231                 label.Text = aField.Text;
  1232                 //
  1233                 control = label;
  1234             }
  1235             else
  1236             {
  1237                 //Create picture box
  1238                 PictureBox picture = new PictureBox();
  1239                 picture.AutoSize = true;
  1240                 picture.BackColor = System.Drawing.Color.Transparent;
  1241                 picture.Dock = System.Windows.Forms.DockStyle.Fill;
  1242                 picture.Location = new System.Drawing.Point(1, 1);
  1243                 picture.Margin = new System.Windows.Forms.Padding(0);
  1244                 picture.Name = "pictureBox" + aField;
  1245                 //Set our image
  1246                 picture.Image = aField.Bitmap;
  1247                 //
  1248                 control = picture;
  1249             }
  1250 
  1251             return control;
  1252         }
  1253 
  1254 
  1255         private void buttonAlignLeft_Click(object sender, EventArgs e)
  1256         {
  1257             foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
  1258             {
  1259                 ctrl.TextAlign = ContentAlignment.MiddleLeft;
  1260             }
  1261         }
  1262 
  1263         private void buttonAlignCenter_Click(object sender, EventArgs e)
  1264         {
  1265             foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
  1266             {
  1267                 ctrl.TextAlign = ContentAlignment.MiddleCenter;
  1268             }
  1269         }
  1270 
  1271         private void buttonAlignRight_Click(object sender, EventArgs e)
  1272         {
  1273             foreach (MarqueeLabel ctrl in tableLayoutPanel.Controls)
  1274             {
  1275                 ctrl.TextAlign = ContentAlignment.MiddleRight;
  1276             }
  1277         }
  1278 
  1279         private void comboBoxDisplayType_SelectedIndexChanged(object sender, EventArgs e)
  1280         {
  1281             Properties.Settings.Default.CurrentDisplayIndex = comboBoxDisplayType.SelectedIndex;
  1282             cds.DisplayType = comboBoxDisplayType.SelectedIndex;
  1283             Properties.Settings.Default.Save();
  1284             if (iDisplay.IsOpen())
  1285             {
  1286                 OpenDisplayConnection();
  1287             }
  1288             else
  1289             {
  1290                 UpdateStatus();
  1291             }
  1292         }
  1293 
  1294 
  1295         private void maskedTextBoxTimerInterval_TextChanged(object sender, EventArgs e)
  1296         {
  1297             if (maskedTextBoxTimerInterval.Text != "")
  1298             {
  1299                 int interval = Convert.ToInt32(maskedTextBoxTimerInterval.Text);
  1300 
  1301                 if (interval > 0)
  1302                 {
  1303                     timer.Interval = interval;
  1304                     cds.TimerInterval = timer.Interval;
  1305                     Properties.Settings.Default.Save();
  1306                 }
  1307             }
  1308         }
  1309 
  1310         private void buttonPowerOn_Click(object sender, EventArgs e)
  1311         {
  1312             iDisplay.PowerOn();
  1313         }
  1314 
  1315         private void buttonPowerOff_Click(object sender, EventArgs e)
  1316         {
  1317             iDisplay.PowerOff();
  1318         }
  1319 
  1320         private void buttonShowClock_Click(object sender, EventArgs e)
  1321         {
  1322             iDisplay.ShowClock();
  1323         }
  1324 
  1325         private void buttonHideClock_Click(object sender, EventArgs e)
  1326         {
  1327             iDisplay.HideClock();
  1328         }
  1329 
  1330         private void buttonUpdate_Click(object sender, EventArgs e)
  1331         {
  1332             InstallUpdateSyncWithInfo();
  1333         }
  1334 
  1335 
  1336         private void InstallUpdateSyncWithInfo()
  1337         {
  1338             UpdateCheckInfo info = null;
  1339 
  1340             if (ApplicationDeployment.IsNetworkDeployed)
  1341             {
  1342                 ApplicationDeployment ad = ApplicationDeployment.CurrentDeployment;
  1343 
  1344                 try
  1345                 {
  1346                     info = ad.CheckForDetailedUpdate();
  1347 
  1348                 }
  1349                 catch (DeploymentDownloadException dde)
  1350                 {
  1351                     MessageBox.Show("The new version of the application cannot be downloaded at this time. \n\nPlease check your network connection, or try again later. Error: " + dde.Message);
  1352                     return;
  1353                 }
  1354                 catch (InvalidDeploymentException ide)
  1355                 {
  1356                     MessageBox.Show("Cannot check for a new version of the application. The ClickOnce deployment is corrupt. Please redeploy the application and try again. Error: " + ide.Message);
  1357                     return;
  1358                 }
  1359                 catch (InvalidOperationException ioe)
  1360                 {
  1361                     MessageBox.Show("This application cannot be updated. It is likely not a ClickOnce application. Error: " + ioe.Message);
  1362                     return;
  1363                 }
  1364 
  1365 				if (info.UpdateAvailable)
  1366 				{
  1367 					Boolean doUpdate = true;
  1368 
  1369 					if (!info.IsUpdateRequired)
  1370 					{
  1371 						DialogResult dr = MessageBox.Show("An update is available. Would you like to update the application now?", "Update Available", MessageBoxButtons.OKCancel);
  1372 						if (!(DialogResult.OK == dr))
  1373 						{
  1374 							doUpdate = false;
  1375 						}
  1376 					}
  1377 					else
  1378 					{
  1379 						// Display a message that the app MUST reboot. Display the minimum required version.
  1380 						MessageBox.Show("This application has detected a mandatory update from your current " +
  1381 							"version to version " + info.MinimumRequiredVersion.ToString() +
  1382 							". The application will now install the update and restart.",
  1383 							"Update Available", MessageBoxButtons.OK,
  1384 							MessageBoxIcon.Information);
  1385 					}
  1386 
  1387 					if (doUpdate)
  1388 					{
  1389 						try
  1390 						{
  1391 							ad.Update();
  1392 							MessageBox.Show("The application has been upgraded, and will now restart.");
  1393 							Application.Restart();
  1394 						}
  1395 						catch (DeploymentDownloadException dde)
  1396 						{
  1397 							MessageBox.Show("Cannot install the latest version of the application. \n\nPlease check your network connection, or try again later. Error: " + dde);
  1398 							return;
  1399 						}
  1400 					}
  1401 				}
  1402 				else
  1403 				{
  1404 					MessageBox.Show("You are already running the latest version.", "Application up-to-date");
  1405 				}
  1406             }
  1407         }
  1408     }
  1409 
  1410     /// <summary>
  1411     /// A UI thread copy of a client relevant data.
  1412     /// Keeping this copy in the UI thread helps us deal with threading issues.
  1413     /// </summary>
  1414     public class ClientData
  1415     {
  1416         public ClientData(string aSessionId, ICallback aCallback)
  1417         {
  1418             SessionId = aSessionId;
  1419             Name = "";
  1420             Fields = new List<DataField>();
  1421             Layout = new TableLayout(1, 2); //Default to one column and two rows
  1422             Callback = aCallback;
  1423         }
  1424 
  1425         public string SessionId { get; set; }
  1426         public string Name { get; set; }
  1427         public List<DataField> Fields { get; set; }
  1428         public TableLayout Layout { get; set; }
  1429         public ICallback Callback { get; set; }
  1430     }
  1431 }