source: Scheduling/trunk/cs/bsdx0200GUISourceCode/CalendarGrid.cs@ 894

Last change on this file since 894 was 846, checked in by Sam Habiel, 14 years ago

Addition of new version of BMXNet21.dll
More Comments in CalendarGrid.cs

File size: 54.4 KB
RevLine 
[622]1namespace IndianHealthService.ClinicalScheduling
2{
3 using System;
4 using System.Collections;
5 using System.ComponentModel;
6 using System.Drawing;
7 using System.Globalization;
8 using System.Runtime.CompilerServices;
9 using System.Runtime.InteropServices;
10 using System.Windows.Forms;
[824]11
[622]12 /// <summary>
[821]13 /// This class is reponsible for rendering the Calendar Grid.
[622]14 /// </summary>
15 public class CalendarGrid : Panel
16 {
[821]17 private IContainer components;
[622]18 private Font fontArial10;
19 private Font fontArial8;
20 private CGAppointments m_Appointments;
21 private Hashtable m_ApptOverlapTable;
22 private bool m_bAutoDrag = true;
23 private bool m_bDragDropStart;
24 private bool m_bDrawWalkIns = true;
25 private bool m_bGridEnter;
26 private bool m_bInitialUpdate;
27 private bool m_bMouseDown;
28 private bool m_bScroll;
29 private bool m_bScrollDown;
30 private bool m_bSelectingRange;
31 private int m_cellHeight;
32 private int m_cellWidth;
33 private int m_col0Width;
34 private Hashtable m_ColumnInfoTable;
35 private CGCell m_currentCell;
36 private DateTime m_dtStart;
37 private Font m_fCell;
38 private string m_GridBackColor;
39 private CGCells m_gridCells;
40 private int m_nColumns = 5;
41 private int m_nSelectID;
42 private int m_nTimeScale = 20;
43 private ArrayList m_pAvArray;
44 private string m_sDragSource;
45 private CGAppointments m_SelectedAppointments;
46 private CGRange m_selectedRange;
47 private StringFormat m_sf;
48 private StringFormat m_sfHour;
49 private StringFormat m_sfRight;
50 private ArrayList m_sResourcesArray;
[821]51 private Timer m_Timer; // Timeer used in Drag and Drop Operations
[622]52 private ToolTip m_toolTip;
[821]53 private const int WM_HSCROLL = 0x114; // Horizontal Scrolling Windows Message
54 private const int WM_VSCROLL = 0x115; // Vertical Scrolling Windows Message
[622]55
56 public event CGAppointmentChangedHandler CGAppointmentAdded;
57
58 public event CGAppointmentChangedHandler CGAppointmentChanged;
59
60 public event CGSelectionChangedHandler CGSelectionChanged;
61
62 public CalendarGrid()
63 {
64 this.InitializeComponent();
65 base.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
66 base.SetStyle(ControlStyles.UserPaint, true);
67 base.SetStyle(ControlStyles.DoubleBuffer, true);
68 this.m_nColumns = 5;
69 this.m_gridCells = new CGCells();
70 this.m_selectedRange = new CGRange();
71 this.m_SelectedAppointments = new CGAppointments();
[821]72 this.m_dtStart = new DateTime(2003, 1, 27);
[622]73 this.m_ApptOverlapTable = new Hashtable();
74 this.m_ColumnInfoTable = new Hashtable();
75 this.m_sResourcesArray = new ArrayList();
76 base.ResizeRedraw = true;
77 this.m_col0Width = 100;
78 this.fontArial8 = new Font("Arial", 8f);
79 this.fontArial10 = new Font("Arial", 10f);
80 this.m_fCell = this.fontArial10;
81 this.m_sf = new StringFormat();
82 this.m_sfRight = new StringFormat();
83 this.m_sfHour = new StringFormat();
84 this.m_sf.LineAlignment = StringAlignment.Center;
85 this.m_sfRight.LineAlignment = StringAlignment.Center;
86 this.m_sfRight.Alignment = StringAlignment.Far;
87 this.m_sfHour.LineAlignment = StringAlignment.Center;
88 this.m_sfHour.Alignment = StringAlignment.Far;
89 this.m_bInitialUpdate = false;
90 }
91
92 private Rectangle AdjustRectForOverlap()
93 {
94 return new Rectangle();
95 }
96
97 private void AutoDragStart()
98 {
99 this.m_bAutoDrag = true;
100 this.m_Timer = new Timer();
101 this.m_Timer.Interval = 5;
102 this.m_Timer.Tick += new EventHandler(this.tickEventHandler);
103 this.m_Timer.Start();
104 }
105
106 private void AutoDragStop()
107 {
108 this.m_bAutoDrag = false;
109 if (this.m_Timer != null)
110 {
111 this.m_Timer.Stop();
112 this.m_Timer.Dispose();
113 this.m_Timer = null;
114 }
115 }
116
117 private void BuildGridCellsArray(Graphics g)
118 {
119 try
120 {
121 SizeF ef = g.MeasureString("Test", this.m_fCell);
122 this.m_cellHeight = ((int) ef.Height) + 4;
123 int nColumns = this.m_nColumns;
124 int num2 = 60 / this.m_nTimeScale;
[821]125 int num3 = 24 * num2;
[622]126 nColumns++;
127 num3++;
128 this.m_cellWidth = 600 / nColumns;
129 if (base.ClientRectangle.Width > 600)
130 {
131 this.m_cellWidth = (base.ClientRectangle.Width - this.m_col0Width) / (nColumns - 1);
132 }
133 if (this.m_nColumns == 1)
134 {
135 this.m_cellWidth = base.ClientRectangle.Width - this.m_col0Width;
136 }
137 g.TranslateTransform((float) base.AutoScrollPosition.X, (float) base.AutoScrollPosition.Y);
138 for (int i = num3; i > -1; i--)
139 {
140 for (int j = 1; j < nColumns; j++)
141 {
142 int x = 0;
143 if (j == 1)
144 {
145 x = this.m_col0Width;
146 }
147 if (j > 1)
148 {
149 x = this.m_col0Width + (this.m_cellWidth * (j - 1));
150 }
151 Point point = new Point(x, i * this.m_cellHeight);
152 Rectangle r = new Rectangle(point.X, point.Y, this.m_cellWidth, this.m_cellHeight);
153 if (i != 0)
154 {
155 CGCell cell = null;
156 cell = new CGCell(r, i, j);
157 this.m_gridCells.AddCell(cell);
158 }
159 }
160 }
161 }
162 catch (Exception exception)
163 {
164 string message = exception.Message;
165 }
166 }
167
168 private void CalendarGrid_DragDrop(object Sender, DragEventArgs e)
169 {
170 CGAppointment data = (CGAppointment) e.Data.GetData(typeof(CGAppointment));
171 Point point = base.PointToClient(new Point(e.X, e.Y));
172 int x = point.X - base.AutoScrollPosition.X;
173 int y = point.Y - base.AutoScrollPosition.Y;
174 Point pt = new Point(x, y);
175 foreach (DictionaryEntry entry in this.m_gridCells.CellHashTable)
176 {
177 CGCell cgCell = (CGCell) entry.Value;
178 if (cgCell.CellRectangle.Contains(pt))
179 {
180 DateTime timeFromCell = this.GetTimeFromCell(cgCell);
181 string resourceFromColumn = this.GetResourceFromColumn(cgCell.CellColumn);
182 int duration = data.Duration;
183 TimeSpan span = new TimeSpan(0, duration, 0);
184 DateTime time2 = timeFromCell + span;
185 data.Selected = false;
186 this.m_nSelectID = 0;
187 CGAppointmentChangedArgs args = new CGAppointmentChangedArgs();
188 args.Appointment = data;
189 args.StartTime = timeFromCell;
190 args.EndTime = time2;
191 args.Resource = resourceFromColumn;
192 args.OldResource = data.Resource;
193 args.AccessTypeID = data.AccessTypeID;
194 args.Slots = data.Slots;
195 if (this.ApptDragSource == "grid")
196 {
197 this.CGAppointmentChanged(this, args);
198 }
199 else
200 {
201 this.CGAppointmentAdded(this, args);
202 }
203 break;
204 }
205 }
206 this.SetOverlapTable();
207 base.Invalidate();
208 }
209
210 private void CalendarGrid_DragEnter(object Sender, DragEventArgs e)
211 {
212 if (e.Data.GetDataPresent(typeof(CGAppointment)))
213 {
214 if ((e.KeyState & 8) == 8)
215 {
216 e.Effect = DragDropEffects.Copy;
217 }
218 else
219 {
220 e.Effect = DragDropEffects.Move;
221 }
222 }
223 else
224 {
225 e.Effect = DragDropEffects.None;
226 }
227 }
228
229 private void CalendarGrid_MouseDown(object sender, MouseEventArgs e)
230 {
231 if (e.Button == MouseButtons.Left)
232 {
233 foreach (DictionaryEntry entry in this.m_gridCells.CellHashTable)
234 {
235 CGCell cell = (CGCell) entry.Value;
236 cell.IsSelected = false;
237 }
238 this.m_selectedRange.Cells.ClearAllCells();
239 this.m_bMouseDown = true;
240 this.OnLButtonDown(e.X, e.Y, true);
241 }
242 }
243
244 private void CalendarGrid_MouseMove(object Sender, MouseEventArgs e)
245 {
246 if (this.m_bMouseDown)
247 {
248 if ((e.Y >= base.ClientRectangle.Bottom) || (e.Y <= base.ClientRectangle.Top))
249 {
250 this.m_bScrollDown = e.Y >= base.ClientRectangle.Bottom;
251 }
252 if ((e.Y < base.ClientRectangle.Bottom) && (e.Y > base.ClientRectangle.Top))
253 {
254 bool bAutoDrag = this.m_bAutoDrag;
255 }
256 if (this.m_bSelectingRange)
257 {
258 this.OnLButtonDown(e.X, e.Y, false);
259 }
260 if (this.m_nSelectID != 0)
261 {
262 if (this.m_bGridEnter)
263 {
264 this.m_bGridEnter = false;
265 }
266 else if (!this.m_bDragDropStart)
267 {
268 CGAppointment data = (CGAppointment) this.m_Appointments.AppointmentTable[this.m_nSelectID];
269 this.ApptDragSource = "grid";
270 base.DoDragDrop(data, DragDropEffects.Move);
271 this.m_bDragDropStart = true;
272 }
273 }
274 }
275 else
276 {
277 int y = e.Y - base.AutoScrollPosition.Y;
278 int x = e.X - base.AutoScrollPosition.X;
279 Point pt = new Point(x, y);
280 foreach (CGAppointment appointment2 in this.m_Appointments.AppointmentTable.Values)
281 {
282 if (appointment2.GridRectangle.Contains(pt))
283 {
284 this.m_toolTip.SetToolTip(this, appointment2.ToString());
285 return;
286 }
287 }
288 this.m_toolTip.RemoveAll();
[821]289
290 ////smh new code -- select cell
291 //int nRow = -1;
292 //int nCol = -1;
293
294 ////Is the mouse over a known cell? If so, highlight cell
295 //if (this.HitTest(x, y, ref nRow, ref nCol))
296 //{
297 // CGCell cellFromRowCol = this.m_gridCells.GetCellFromRowCol(nRow, nCol);
298 // if (cellFromRowCol != null)
299 // {
300 // this.m_currentCell = cellFromRowCol;
301 // this.m_selectedRange.StartCell = null;
302 // this.m_selectedRange.EndCell = null;
303 // this.m_selectedRange.CreateRange(this.m_gridCells, cellFromRowCol, cellFromRowCol);
304 // this.m_bSelectingRange = true;
305 // cellFromRowCol.IsSelected = true;
306 // base.Invalidate(this.m_currentCell.CellRectangle);
307 // //base.Invalidate();
308 // }
309 //}
310
311
[622]312 }
313 }
314
315 private void CalendarGrid_MouseUp(object Sender, MouseEventArgs e)
316 {
317 if (this.m_bAutoDrag)
318 {
319 this.m_bAutoDrag = false;
320 this.AutoDragStop();
321 }
322 this.m_bMouseDown = false;
323 if (this.m_bSelectingRange)
324 {
325 CGSelectionChangedArgs args = new CGSelectionChangedArgs();
326 args.StartTime = this.GetTimeFromCell(this.m_selectedRange.StartCell);
327 args.EndTime = this.GetTimeFromCell(this.m_selectedRange.EndCell);
328 args.Resource = this.GetResourceFromColumn(this.m_selectedRange.StartCell.CellColumn);
329 if (args.EndTime < args.StartTime)
330 {
331 DateTime startTime = args.StartTime;
332 args.StartTime = args.EndTime;
333 args.EndTime = startTime;
334 }
335 TimeSpan span = new TimeSpan(0, 0, this.m_nTimeScale, 0, 0);
336 args.EndTime += span;
337 this.CGSelectionChanged(this, args);
338 this.m_bSelectingRange = false;
339 }
340 }
341
342 private void CalendarGrid_Paint(object sender, PaintEventArgs e)
343 {
344 if (e.Graphics != null)
345 {
346 this.DrawGrid(e.Graphics);
347 if (!this.m_bInitialUpdate)
348 {
349 this.SetAppointmentTypes();
350 base.Invalidate();
351 this.m_bInitialUpdate = true;
352 }
353 }
354 }
355
356 public void CloseGrid()
357 {
358 foreach (CGAppointment appointment in this.m_Appointments.AppointmentTable.Values)
359 {
360 appointment.Selected = false;
361 }
362 this.m_nSelectID = 0;
363 }
364
365 protected override void Dispose(bool disposing)
366 {
367 if (disposing && (this.components != null))
368 {
369 this.components.Dispose();
370 }
371 base.Dispose(disposing);
372 }
373
374 private void DrawAppointments(Graphics g, int col0Width, int cellWidth, int cellHeight)
375 {
376 if (!base.DesignMode && (this.m_Appointments != null))
377 {
378 int num = 0;
379 int num2 = 0;
380 int x = 0;
381 ArrayList list = new ArrayList();
382 foreach (CGAppointment appointment in this.m_Appointments.AppointmentTable.Values)
383 {
384 bool bRet = false;
385 Rectangle rect = this.GetAppointmentRect(appointment, col0Width, cellWidth, cellHeight, out bRet);
386 if (bRet && (!appointment.WalkIn || this.m_bDrawWalkIns))
387 {
388 rect.Inflate(-10, 0);
389 num = (int) this.m_ApptOverlapTable[appointment.m_nKey];
390 num2 = rect.Right - rect.Left;
391 x = num2 / (num + 1);
392 rect.Width = x;
393 if (num > 0)
394 {
395 foreach (object obj2 in list)
396 {
397 Rectangle rectangle2 = (Rectangle) obj2;
398 if (rect.IntersectsWith(rectangle2))
399 {
400 rect.Offset(x, 0);
401 }
402 }
403 }
404 appointment.GridRectangle = rect;
405 if (appointment.Selected)
406 {
407 Pen pen = new Pen(Brushes.Black, 5f);
408 g.DrawRectangle(pen, rect);
409 pen.Dispose();
410 }
411 else
412 {
413 g.DrawRectangle(Pens.Blue, rect);
414 }
415 string s = appointment.ToString();
416 Rectangle rectangle3 = new Rectangle(rect.X + 1, rect.Y + 1, rect.Width - 1, rect.Height - 1);
417 g.FillRectangle(Brushes.White, rectangle3);
418 Brush black = Brushes.Black;
419 if (appointment.CheckInTime.Ticks > 0L)
420 {
421 black = Brushes.Green;
422 g.FillRectangle(Brushes.LightGreen, rectangle3);
423 }
424 if (appointment.NoShow)
425 {
426 black = Brushes.Red;
427 g.FillRectangle(Brushes.LightPink, rectangle3);
428 }
429 if (appointment.WalkIn)
430 {
431 black = Brushes.Blue;
432 g.FillRectangle(Brushes.LightSteelBlue, rectangle3);
433 }
434 g.DrawString(s, this.fontArial8, black, rectangle3);
435 list.Add(rect);
436 }
437 }
438 }
439 }
440
441 private void DrawGrid(Graphics g)
442 {
[821]443 //Default color of grid lines is black
444 Pen pen = new Pen(Color.Black);
445
446 //each cell's height is Height of Arial Font 10pt + 10 pixels (by default 26 pixels)
447 SizeF ef = g.MeasureString("Test", this.m_fCell);
448 int num = 10;
449 this.m_cellHeight = ((int) ef.Height) + num;
450
451 // Number of columns is dynamic based on user of Grid. See Property Columns. Default 5 in init.
452 int nColumns = this.m_nColumns;
453
454 //Time scale is also dynamic. Property TimeScale. Default 20 (minutes)
455 //num3 stands for number of cells per hour
456 int num3 = 60 / this.m_nTimeScale;
457 //num4 stands for number of cells per day (aka rows in the grid)
458 int num4 = 24 * num3;
459 //Add extra column to hold time in the left hand corner
460 nColumns++;
461 //add extra row to represent dates or resources (depending on which view we are in)
462 //Not sure of which variable controls view yet.
463 num4++;
464
465 // 100 px is reserved no matter our column sizes for displaying the time scale
466
467 // Minimum cell width is 600/columns (100 px by default)
468 this.m_cellWidth = 600 / nColumns;
469
470 // if we happen to have more than 600 pixels in our Client Window then cell
471 // is (Width-100) / (number of date columns)
472 if (base.ClientRectangle.Width > 600)
[622]473 {
[821]474 this.m_cellWidth = (base.ClientRectangle.Width - this.m_col0Width) / (nColumns - 1);
475 }
476
477 // If we have one column, the cell width is the itself - 100
478 if (this.m_nColumns == 1)
479 {
480 this.m_cellWidth = base.ClientRectangle.Width - this.m_col0Width;
481 }
482
483 // Our rectangle will start scrolling if width is less than 600 and height less than height of all cells comb
484 // Of course Height will scroll all the time unless you have a humungous screen
485 base.AutoScrollMinSize = new Size(600, this.m_cellHeight * num4);
486
487 // Default Rectangle is Gray
488 g.FillRectangle(Brushes.LightGray, base.ClientRectangle);
489
490 int num5 = 0; //Minutes (start at 0)
491 int num6 = 0; //Hour (starts at 0)
492
493 // flag is true only if there are no cells what so ever in the screen
494 // Only true when no resource is selected.
495 bool flag = this.m_gridCells.CellCount == 0;
496
497 // Move the base point from the client screen to the scrolling region top-left corner.
498 g.TranslateTransform((float) base.AutoScrollPosition.X, (float) base.AutoScrollPosition.Y);
499
[846]500 // This for loop draws the time scale (although I haven't completely traced it out)
[821]501 // For each row except the first one (i starts from 1 rather than zero)
502 for (int i = 1; i < num4; i++)
503 {
504 int x = 0;
505 //point is (0, 1st Cell Start) then (0, 2nd Cell Start) until we run out
506 Point point = new Point(x, i * this.m_cellHeight);
507 //rectangle2 represents each cell rectangle
508 Rectangle rectangle2 = new Rectangle(point.X, point.Y, this.m_cellWidth, this.m_cellHeight);
509 //rect stands for the time scale rectangle; width is 100px; Height is length of the hour on grid
510 Rectangle rect = new Rectangle(0, rectangle2.Y, this.m_col0Width, rectangle2.Height * num3);
511 //height is length of hour
512 int height = rect.Height;
513 //Min font height is 25 pixels (100/4)--see below where it's used
514 height = (height > (this.m_col0Width / 4)) ? (this.m_col0Width / 4) : height;
515
516 //if we are the top of the time scale (at hour:00) -- num5 is min
517 if (num5 == 0)
[622]518 {
[821]519 // Fill time scale triangle with Gray (remember, this is the whole hour!)
520 g.FillRectangle(Brushes.LightGray, rect);
521 // Draw Rectangle
522 g.DrawRectangle(pen, rect.X, rect.Y, rect.Width, rect.Height);
523 //Pad time with at least one zero to make it 2 digits
524 string str = string.Format("{0}", num6).PadLeft(2, '0');
525 //Font height using pixels. Min is 25 pixels
526 Font font = new Font("Arial", (float) height, FontStyle.Bold, GraphicsUnit.Pixel);
527 // rectangle3 is the left half of the time rectangle
528 Rectangle rectangle3 = new Rectangle(rect.X, rect.Y, rect.Width / 2, rect.Height);
529 // In this left half, draw the hours (m_sfHour is the stringformat:
530 // Horizontal Center and Right Justified to rectangle3
531 g.DrawString(str, font, Brushes.Black, rectangle3, this.m_sfHour);
532 // Increment hour
533 num6++;
534 font.Dispose();
[622]535 }
[821]536
537 // Pad minutes with zeros to be 2 digits long
538 string s = string.Format("{0}", num5);
539 s = ":" + s.PadLeft(2, '0');
540 // Rectangle starts at
541 // X: 2/3rds of width of Time Rectangle
542 // Y: Top of the current time slot cell
543 // Width: 1/3rd of the width of the Time Rectangle
544 // Height: Height of a time slot
545 Rectangle layoutRectangle = new Rectangle(rect.X + ((rect.Width * 2) / 3), rectangle2.Top, rect.Width / 3, rectangle2.Height);
546 // At in this rectangle, write the minutes. Horizontal Ctr and Right Justified to Rectangle
547 g.DrawString(s, this.m_fCell, Brushes.Black, layoutRectangle, this.m_sfRight);
[846]548 // Draw Line from two points, just under the time we have just written
[821]549 Point point2 = new Point(rect.X + ((rect.Width * 2) / 3), rectangle2.Bottom);
550 Point point3 = new Point(rect.Right, rectangle2.Bottom);
551 g.DrawLine(pen, point2, point3);
[846]552 // Increment the minutes with the time scale
[821]553 num5 += this.m_nTimeScale;
[846]554 // If miniutes reaches 60, reset to zero
[821]555 num5 = (num5 >= 60) ? 0 : num5;
[846]556 // When we reach the bottom (num4 - 1 is # of rows) and we are not scrolling
[821]557 if ((i == (num4 - 1)) && !this.m_bScroll)
[622]558 {
[846]559 // Fill the last cell with Gray (?)
[821]560 g.TranslateTransform((float) -base.AutoScrollPosition.X, (float) -base.AutoScrollPosition.Y);
561 rect = new Rectangle(0, 0, this.m_col0Width, this.m_cellHeight);
562 g.FillRectangle(Brushes.LightGray, rect);
563 g.DrawRectangle(pen, rect);
564 g.TranslateTransform((float) base.AutoScrollPosition.X, (float) base.AutoScrollPosition.Y);
[622]565 }
[821]566 }
[846]567
568 //This for loop draws the cells
569 //Start from the bottom (num4 is # of rows) and go down to the zeroth row (ie date row/resource row)
[821]570 for (int j = num4; j > -1; j--)
571 {
[846]572 // For each column - 1 (we start at 1, not zero-->We drew the first column anyways in the 1st loop)
[821]573 for (int k = 1; k < nColumns; k++)
[622]574 {
[846]575 int num12 = 0; // X-axis position
576 if (k == 1) // If we are at the first column, start at 100px (default)
[622]577 {
[821]578 num12 = this.m_col0Width;
[622]579 }
[846]580 if (k > 1) //
[622]581 {
[821]582 num12 = this.m_col0Width + (this.m_cellWidth * (k - 1));
[622]583 }
[821]584 Point point4 = new Point(num12, j * this.m_cellHeight);
585 Rectangle r = new Rectangle(point4.X, point4.Y, this.m_cellWidth, this.m_cellHeight);
586 if (j != 0)
[622]587 {
[821]588 CGCell cellFromRowCol = null;
589 if (flag)
[622]590 {
[821]591 cellFromRowCol = new CGCell(r, j, k);
592 this.m_gridCells.AddCell(cellFromRowCol);
[622]593 }
[821]594 else
[622]595 {
[821]596 cellFromRowCol = this.m_gridCells.GetCellFromRowCol(j, k);
597 cellFromRowCol.CellRectangle = r;
[622]598 }
[821]599 if (this.m_sResourcesArray.Count > 0)
[622]600 {
[821]601 if (this.m_selectedRange.CellIsInRange(cellFromRowCol))
[622]602 {
[821]603 g.FillRectangle(Brushes.Aquamarine, r);
[622]604 }
605 else
606 {
[821]607 g.FillRectangle(cellFromRowCol.AppointmentTypeColor, r);
[622]608 }
[821]609 g.DrawRectangle(pen, r.X, r.Y, r.Width, r.Height);
610 if (j == 1)
[622]611 {
[821]612 this.DrawAppointments(g, this.m_col0Width, this.m_cellWidth, this.m_cellHeight);
[622]613 }
614 }
[821]615 continue;
616 }
617 if (!this.m_bScroll)
618 {
619 g.TranslateTransform(0f, (float) -base.AutoScrollPosition.Y);
620 Rectangle rectangle6 = r;
621 g.FillRectangle(Brushes.LightBlue, rectangle6);
622 g.DrawRectangle(pen, rectangle6.X, rectangle6.Y, rectangle6.Width, rectangle6.Height);
623 string str3 = "";
624 if (this.m_sResourcesArray.Count > 1)
[622]625 {
[821]626 foreach (DictionaryEntry entry in this.m_ColumnInfoTable)
[622]627 {
[821]628 int num13 = (int) entry.Value;
629 num13++;
630 if (num13 == k)
[622]631 {
[821]632 str3 = entry.Key.ToString();
633 break;
[622]634 }
635 }
[821]636 }
637 else
638 {
639 DateTime dtStart = this.m_dtStart;
640 if (k > 1)
[622]641 {
[821]642 dtStart = dtStart.AddDays((double) (k - 1));
[622]643 }
[821]644 string format = "ddd, MMM d";
645 str3 = dtStart.ToString(format, DateTimeFormatInfo.InvariantInfo);
[622]646 }
[821]647 g.DrawString(str3, this.m_fCell, Brushes.Black, rectangle6, this.m_sf);
648 g.TranslateTransform(0f, (float) base.AutoScrollPosition.Y);
[622]649 }
650 }
651 }
[821]652 this.m_bScroll = false;
653 pen.Dispose();
[622]654 }
655
656 public Rectangle GetAppointmentRect(CGAppointment a, int col0Width, int cellWidth, int cellHeight, out bool bRet)
657 {
658 DateTime startTime = a.StartTime;
659 DateTime endTime = a.EndTime;
660 string resource = a.Resource;
661 int num = 0;
662 int num2 = 0;
663 int num3 = 0;
664 int num4 = 0;
665 int num5 = 0;
666 Rectangle rectangle = new Rectangle();
667 int totalMinutes = (int) startTime.TimeOfDay.TotalMinutes;
668 int num7 = (int) endTime.TimeOfDay.TotalMinutes;
669 if (this.m_sResourcesArray.Count > 1)
670 {
671 num5 = (int) this.m_ColumnInfoTable[resource];
672 num5++;
673 }
674 else
675 {
676 num5 = ((int) (startTime.DayOfWeek - this.m_dtStart.DayOfWeek)) + 1;
677 }
678 if (num5 < 1)
679 {
680 bRet = false;
681 return rectangle;
682 }
683 num = col0Width + (cellWidth * (num5 - 1));
684 int num8 = totalMinutes + this.m_nTimeScale;
685 int num9 = (num7 > 0) ? num7 : 0x5a0;
686 num9 -= totalMinutes;
687 num2 = (cellHeight * num8) / this.m_nTimeScale;
688 num3 = (cellHeight * num9) / this.m_nTimeScale;
689 num4 = cellWidth;
690 rectangle.X = num;
691 rectangle.Y = num2;
692 rectangle.Width = num4;
693 rectangle.Height = num3;
694 bRet = true;
695 return rectangle;
696 }
697
698 public bool GetCellFromTime(DateTime dDate, ref int nRow, ref int nCol, bool bStartCell, string sResource)
699 {
700 int num = (dDate.Hour * 60) + dDate.Minute;
701 nRow = num / this.m_nTimeScale;
702 if (bStartCell)
703 {
704 nRow++;
705 }
706 if (this.m_sResourcesArray.Count > 1)
707 {
708 if (sResource == "")
709 {
710 sResource = this.m_sResourcesArray[0].ToString();
711 }
712 nCol = (int) this.m_ColumnInfoTable[sResource];
713 nCol++;
714 return true;
715 }
716 DateTime time = new DateTime(dDate.Year, dDate.Month, dDate.Day);
717 TimeSpan span = (TimeSpan) (time - this.StartDate);
718 int totalDays = 0;
719 totalDays = (int) span.TotalDays;
720 nCol = totalDays;
721 nCol++;
722 return true;
723 }
724
725 private string GetResourceFromColumn(int nCol)
726 {
727 if (this.m_sResourcesArray.Count == 1)
728 {
729 return this.m_sResourcesArray[0].ToString();
730 }
731 foreach (DictionaryEntry entry in this.m_ColumnInfoTable)
732 {
733 int num = (int) entry.Value;
734 num++;
735 if (num == nCol)
736 {
737 return entry.Key.ToString();
738 }
739 }
740 return "";
741 }
742
743 public bool GetSelectedTime(out DateTime dStart, out DateTime dEnd, out string sResource)
744 {
745 if (this.m_selectedRange.Cells.CellCount == 0)
746 {
747 dEnd = new DateTime();
748 dStart = dEnd;
749 sResource = "";
750 return false;
751 }
752 CGCell startCell = this.m_selectedRange.StartCell;
753 CGCell endCell = this.m_selectedRange.EndCell;
754 if (startCell.CellRow > endCell.CellRow)
755 {
756 CGCell cell3 = startCell;
757 startCell = endCell;
758 endCell = cell3;
759 }
760 dStart = this.GetTimeFromCell(startCell);
761 dEnd = this.GetTimeFromCell(endCell);
762 dEnd = dEnd.AddMinutes((double) this.m_nTimeScale);
763 sResource = this.GetResourceFromColumn(startCell.CellColumn);
764 return true;
765 }
766
767 public bool GetSelectedType(out int nAccessTypeID)
768 {
769 nAccessTypeID = 0;
770 if (this.m_selectedRange.Cells.CellCount == 0)
771 {
772 return false;
773 }
774 CGCell startCell = this.m_selectedRange.StartCell;
775 CGCell endCell = this.m_selectedRange.EndCell;
776 if (startCell.CellRow > endCell.CellRow)
777 {
778 CGCell cell3 = startCell;
779 startCell = endCell;
780 endCell = cell3;
781 }
782 DateTime timeFromCell = this.GetTimeFromCell(startCell);
783 DateTime time2 = this.GetTimeFromCell(endCell).AddMinutes((double) this.m_nTimeScale);
784 foreach (CGAvailability availability in this.m_pAvArray)
785 {
786 if (this.TimesOverlap(availability.StartTime, availability.EndTime, timeFromCell, time2))
787 {
788 nAccessTypeID = availability.AvailabilityType;
789 break;
790 }
791 }
792 return (nAccessTypeID > 0);
793 }
794
795 public DateTime GetTimeFromCell(CGCell cgCell)
796 {
797 int cellRow = cgCell.CellRow;
798 int cellColumn = cgCell.CellColumn;
799 DateTime dtStart = this.m_dtStart;
800 int num3 = (cellRow - 1) * this.m_nTimeScale;
801 int num4 = num3 / 60;
802 if (num4 > 0)
803 {
804 num3 = num3 % (num4 * 60);
805 }
806 dtStart = dtStart.AddHours((double) num4).AddMinutes((double) num3);
807 if (this.m_sResourcesArray.Count == 1)
808 {
809 dtStart = dtStart.AddDays((double) (cellColumn - 1));
810 }
811 return dtStart;
812 }
813
814 public bool GetTypeFromCell(CGCell cgCell, out int nAccessTypeID)
815 {
816 nAccessTypeID = 0;
817 CGCell cell = cgCell;
818 CGCell cell2 = cgCell;
819 if (cell.CellRow > cell2.CellRow)
820 {
821 CGCell cell3 = cell;
822 cell = cell2;
823 cell2 = cell3;
824 }
825 DateTime timeFromCell = this.GetTimeFromCell(cell);
826 DateTime time2 = this.GetTimeFromCell(cell2).AddMinutes((double) this.m_nTimeScale);
827 foreach (CGAvailability availability in this.m_pAvArray)
828 {
829 if (this.TimesOverlap(availability.StartTime, availability.EndTime, timeFromCell, time2))
830 {
831 nAccessTypeID = availability.AvailabilityType;
832 break;
833 }
834 }
835 return (nAccessTypeID > 0);
836 }
837
838 private bool HitTest(int X, int Y, ref int nRow, ref int nCol)
839 {
840 Y -= base.AutoScrollPosition.Y;
841 X -= base.AutoScrollPosition.X;
842 foreach (DictionaryEntry entry in this.m_gridCells)
843 {
844 CGCell cell = (CGCell) entry.Value;
845 if (cell.CellRectangle.Contains(X, Y))
846 {
847 nRow = cell.CellRow;
848 nCol = cell.CellColumn;
849 return true;
850 }
851 }
852 return false;
853 }
854
855 public void InitializeCalendarGrid()
856 {
857 this.AllowDrop = true;
858 }
859
860 private void InitializeComponent()
861 {
[821]862 this.components = new System.ComponentModel.Container();
863 this.m_toolTip = new System.Windows.Forms.ToolTip(this.components);
864 this.SuspendLayout();
865 //
866 // CalendarGrid
867 //
[622]868 this.AutoScroll = true;
[821]869 this.AutoScrollMinSize = new System.Drawing.Size(600, 400);
870 this.BackColor = System.Drawing.SystemColors.Window;
871 this.Paint += new System.Windows.Forms.PaintEventHandler(this.CalendarGrid_Paint);
872 this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.CalendarGrid_MouseMove);
873 this.DragDrop += new System.Windows.Forms.DragEventHandler(this.CalendarGrid_DragDrop);
874 this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.CalendarGrid_MouseDown);
875 this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.CalendarGrid_MouseUp);
876 this.DragEnter += new System.Windows.Forms.DragEventHandler(this.CalendarGrid_DragEnter);
877 this.ResumeLayout(false);
878
[622]879 }
880
881 private int MinSince80(DateTime d)
882 {
[821]883 DateTime time = new DateTime(1980, 1, 1, 0, 0, 0);
[622]884 TimeSpan span = (TimeSpan) (d - time);
885 return (int) span.TotalMinutes;
886 }
887
888 private void OnLButtonDown(int X, int Y, bool bStart)
889 {
890 this.m_bDragDropStart = false;
891 this.m_nSelectID = 0;
892 if (!this.m_bSelectingRange)
893 {
894 int y = Y - base.AutoScrollPosition.Y;
895 int x = X - base.AutoScrollPosition.X;
896 Point pt = new Point(x, y);
897 if (Control.ModifierKeys == Keys.Control)
898 {
899 this.m_bMouseDown = false;
900 foreach (CGAppointment appointment in this.m_Appointments.AppointmentTable.Values)
901 {
902 if (!appointment.GridRectangle.Contains(pt))
903 {
904 continue;
905 }
906 if (this.m_SelectedAppointments.AppointmentTable.ContainsKey(appointment.AppointmentKey))
907 {
908 this.m_SelectedAppointments.RemoveAppointment(appointment.AppointmentKey);
909 if (this.m_SelectedAppointments.AppointmentTable.Count == 0)
910 {
911 this.m_nSelectID = 0;
912 }
913 else
914 {
915 foreach (CGAppointment appointment2 in this.m_Appointments.AppointmentTable.Values)
916 {
917 this.m_nSelectID = appointment2.AppointmentKey;
918 }
919 }
920 }
921 else
922 {
923 this.m_SelectedAppointments.AddAppointment(appointment);
924 this.m_nSelectID = appointment.AppointmentKey;
925 }
926 appointment.Selected = !appointment.Selected;
927 break;
928 }
929 base.Invalidate();
930 return;
931 }
932 foreach (CGAppointment appointment3 in this.m_Appointments.AppointmentTable.Values)
933 {
934 if (!appointment3.GridRectangle.Contains(pt))
935 {
936 continue;
937 }
938 this.m_bMouseDown = false;
939 if (appointment3.Selected)
940 {
941 appointment3.Selected = false;
942 this.m_SelectedAppointments.ClearAllAppointments();
943 this.m_nSelectID = 0;
944 }
945 else
946 {
947 foreach (CGAppointment appointment4 in this.m_Appointments.AppointmentTable.Values)
948 {
949 appointment4.Selected = false;
950 }
951 this.m_SelectedAppointments.ClearAllAppointments();
952 this.m_SelectedAppointments.AddAppointment(appointment3);
953 appointment3.Selected = true;
954 this.m_nSelectID = appointment3.AppointmentKey;
955 this.m_bMouseDown = true;
956 this.m_bGridEnter = true;
957 }
958 base.Invalidate();
959 return;
960 }
961 }
962 int nRow = -1;
963 int nCol = -1;
964 if (this.HitTest(X, Y, ref nRow, ref nCol))
965 {
966 CGCell cellFromRowCol = this.m_gridCells.GetCellFromRowCol(nRow, nCol);
967 if (cellFromRowCol != null)
968 {
969 if (bStart)
970 {
971 this.m_currentCell = cellFromRowCol;
972 this.m_selectedRange.StartCell = null;
973 this.m_selectedRange.EndCell = null;
974 this.m_selectedRange.CreateRange(this.m_gridCells, cellFromRowCol, cellFromRowCol);
975 bStart = false;
976 this.m_bMouseDown = true;
977 this.m_bSelectingRange = true;
978 }
979 else if (cellFromRowCol != this.m_currentCell)
980 {
981 if (!this.m_selectedRange.Cells.CellHashTable.ContainsKey(cellFromRowCol.Key))
982 {
983 this.m_selectedRange.AppendCell(this.m_gridCells, cellFromRowCol);
984 }
985 else
986 {
987 bool bUp = cellFromRowCol.CellRow < this.m_currentCell.CellRow;
988 this.m_selectedRange.SubtractCell(this.m_gridCells, cellFromRowCol, bUp);
989 }
990 this.m_currentCell = cellFromRowCol;
991 }
992 cellFromRowCol.IsSelected = true;
993 base.Invalidate();
994 }
995 }
996 }
997
998 public void OnUpdateArrays()
999 {
1000 try
1001 {
1002 this.m_gridCells.ClearAllCells();
1003 this.SetColumnInfo();
1004 this.SetOverlapTable();
1005 Graphics g = base.CreateGraphics();
1006 this.BuildGridCellsArray(g);
1007 this.SetAppointmentTypes();
1008 }
1009 catch (Exception exception)
1010 {
1011 string message = exception.Message;
1012 }
1013 }
1014
1015 private void SetAppointmentTypes()
1016 {
1017 if (this.m_gridCells.CellCount != 0)
1018 {
1019 foreach (DictionaryEntry entry in this.m_gridCells.CellHashTable)
1020 {
1021 CGCell cell = (CGCell) entry.Value;
1022 cell.AppointmentTypeColor = (this.m_GridBackColor == "blue") ? Brushes.CornflowerBlue : Brushes.Khaki;
1023 }
1024 if ((this.m_pAvArray != null) && (this.m_pAvArray.Count != 0))
1025 {
1026 foreach (CGAvailability availability in this.m_pAvArray)
1027 {
1028 int nRow = 0;
1029 int nCol = 0;
1030 int num3 = 0;
1031 int num4 = 0;
1032 Brush brush = new SolidBrush(Color.FromArgb(availability.Red, availability.Green, availability.Blue));
1033 this.GetCellFromTime(availability.StartTime, ref nRow, ref nCol, true, availability.ResourceList);
1034 this.GetCellFromTime(availability.EndTime, ref num3, ref num4, false, availability.ResourceList);
1035 for (int i = nCol; i <= num4; i++)
1036 {
1037 for (int j = nRow; (i == num4) && (j <= num3); j++)
1038 {
1039 string str = "r" + j.ToString() + "c" + i.ToString();
1040 CGCell cell2 = (CGCell) this.m_gridCells.CellHashTable[str];
1041 if (cell2 != null)
1042 {
1043 cell2.AppointmentTypeColor = brush;
1044 }
1045 }
1046 }
1047 }
1048 }
1049 }
1050 }
1051
1052 private void SetColumnInfo()
1053 {
1054 this.m_ColumnInfoTable.Clear();
1055 for (int i = 0; i < this.m_sResourcesArray.Count; i++)
1056 {
1057 this.m_ColumnInfoTable.Add(this.m_sResourcesArray[i], i);
1058 }
1059 if (this.m_sResourcesArray.Count > 1)
1060 {
1061 this.m_nColumns = this.m_sResourcesArray.Count;
1062 }
1063 }
1064
1065 public void SetOverlapTable()
1066 {
1067 Hashtable hashtable = new Hashtable();
1068 int y = 0;
1069 int num2 = 0;
1070 int x = 0;
1071 foreach (CGAppointment appointment in this.m_Appointments.AppointmentTable.Values)
1072 {
1073 if (!appointment.WalkIn || this.m_bDrawWalkIns)
1074 {
1075 string resource = appointment.Resource;
1076 y = appointment.StartTime.Minute + (60 * appointment.StartTime.Hour);
1077 num2 = appointment.EndTime.Minute + (60 * appointment.EndTime.Hour);
1078 x = (this.m_sResourcesArray.Count > 1) ? (((int) this.m_ColumnInfoTable[resource]) + 1) : appointment.StartTime.DayOfYear;
1079 Rectangle rectangle = new Rectangle(x, y, 1, num2 - y);
1080 hashtable.Add(appointment.m_nKey, rectangle);
1081 }
1082 }
1083 this.m_ApptOverlapTable.Clear();
1084 foreach (int num4 in hashtable.Keys)
1085 {
1086 this.m_ApptOverlapTable.Add(num4, 0);
1087 }
[821]1088 // Here it draws the Dates on Top
[622]1089 if (this.m_ApptOverlapTable.Count != 0)
1090 {
1091 int num5 = (this.m_sResourcesArray.Count > 1) ? 1 : this.StartDate.DayOfYear;
1092 int num6 = (this.m_sResourcesArray.Count > 1) ? (this.m_sResourcesArray.Count + 1) : (this.Columns + this.StartDate.DayOfYear);
1093 for (int i = num5; i < num6; i++)
1094 {
1095 ArrayList list = new ArrayList();
1096 for (int j = 1; j < this.Rows; j++)
1097 {
1098 Rectangle rectangle2 = new Rectangle(i, j * this.m_nTimeScale, 1, this.m_nTimeScale);
1099 int num9 = -1;
1100 list.Clear();
1101 foreach (int num10 in hashtable.Keys)
1102 {
1103 Rectangle rect = (Rectangle) hashtable[num10];
1104 if (rectangle2.IntersectsWith(rect))
1105 {
1106 num9++;
1107 list.Add(num10);
1108 }
1109 }
1110 if (num9 > 0)
1111 {
1112 foreach (object obj2 in list)
1113 {
1114 int num11 = (int) obj2;
1115 if (((int) this.m_ApptOverlapTable[num11]) < num9)
1116 {
1117 this.m_ApptOverlapTable[num11] = num9;
1118 }
1119 }
1120 }
1121 }
1122 }
1123 }
1124 }
1125
1126 private void tickEventHandler(object o, EventArgs e)
1127 {
1128 Point point = new Point(base.AutoScrollPosition.X, base.AutoScrollPosition.Y);
1129 int x = point.X;
1130 int num = point.Y * -1;
1131 num = this.m_bScrollDown ? (num + 5) : (num - 5);
1132 point.Y = num;
1133 base.AutoScrollPosition = point;
1134 base.Invalidate();
1135 }
1136
1137 private bool TimesOverlap(DateTime dStart1, DateTime dEnd1, DateTime dStart2, DateTime dEnd2)
1138 {
1139 long ticks = dEnd1.Ticks - dStart1.Ticks;
1140 TimeSpan ts = new TimeSpan(ticks);
1141 ticks = dEnd2.Ticks - dStart2.Ticks;
1142 new TimeSpan(ticks).Subtract(ts);
1143 Rectangle rect = new Rectangle();
1144 Rectangle rectangle2 = new Rectangle();
1145 rect.X = 0;
1146 rectangle2.X = 0;
1147 rect.Width = 1;
1148 rectangle2.Width = 1;
1149 rect.Y = this.MinSince80(dStart1);
1150 rect.Height = this.MinSince80(dEnd1) - rect.Y;
1151 rectangle2.Y = this.MinSince80(dStart2);
1152 rectangle2.Height = this.MinSince80(dEnd2) - rectangle2.Y;
1153 return rectangle2.IntersectsWith(rect);
1154 }
1155
[821]1156 /// <summary>
1157 /// The purpose of this is to properly draw the date boxes at the top of the calendar grid.
1158 /// Otherwise, when scrolling, it gets garbled.
1159 /// </summary>
1160 /// <param name="msg">Handles two messages:
1161 /// WM_VSCROLL (0x115 - Vertical Scrolling)
1162 /// WM_HSCROLL (0x114 - Horizontal Scrolling)
1163 /// </param>
[622]1164 protected override void WndProc(ref Message msg)
1165 {
1166 try
1167 {
[821]1168 if (msg.Msg == WM_VSCROLL)
[622]1169 {
1170 this.m_bScroll = true;
1171 base.Invalidate(false);
1172 this.m_bScroll = false;
1173 }
[821]1174 if (msg.Msg == WM_HSCROLL)
[622]1175 {
1176 base.Invalidate(false);
1177 }
1178 base.WndProc(ref msg);
1179 }
1180 catch (Exception exception)
1181 {
1182 MessageBox.Show("CalendarGrid::WndProc: " + exception.Message + "\nStack: " + exception.StackTrace);
1183 }
1184 }
1185
1186 public CGAppointments Appointments
1187 {
1188 get
1189 {
1190 return this.m_Appointments;
1191 }
1192 set
1193 {
1194 this.m_Appointments = value;
1195 }
1196 }
1197
1198 public string ApptDragSource
1199 {
1200 get
1201 {
1202 return this.m_sDragSource;
1203 }
1204 set
1205 {
1206 this.m_sDragSource = value;
1207 }
1208 }
1209
1210 public ArrayList AvailabilityArray
1211 {
1212 get
1213 {
1214 return this.m_pAvArray;
1215 }
1216 set
1217 {
1218 this.m_pAvArray = value;
1219 }
1220 }
1221
1222 public int CellHeight
1223 {
1224 get
1225 {
1226 return this.m_cellHeight;
1227 }
1228 }
1229
1230 public ToolTip CGToolTip
1231 {
1232 get
1233 {
1234 return this.m_toolTip;
1235 }
1236 }
1237
1238 public int Columns
1239 {
1240 get
1241 {
1242 return this.m_nColumns;
1243 }
1244 set
1245 {
1246 if ((value > 0) && (value < 11))
1247 {
1248 this.m_nColumns = value;
1249 this.m_gridCells.ClearAllCells();
1250 this.m_selectedRange.Cells.ClearAllCells();
1251 Graphics g = base.CreateGraphics();
1252 this.BuildGridCellsArray(g);
1253 this.SetAppointmentTypes();
1254 base.Invalidate();
1255 }
1256 }
1257 }
1258
1259 public bool DrawWalkIns
1260 {
1261 get
1262 {
1263 return this.m_bDrawWalkIns;
1264 }
1265 set
1266 {
1267 this.m_bDrawWalkIns = value;
1268 }
1269 }
1270
1271 public string GridBackColor
1272 {
1273 get
1274 {
1275 return this.m_GridBackColor;
1276 }
1277 set
1278 {
1279 this.m_GridBackColor = value;
1280 }
1281 }
1282
1283 public bool GridEnter
1284 {
1285 get
1286 {
1287 return this.m_bGridEnter;
1288 }
1289 set
1290 {
1291 this.m_bGridEnter = value;
1292 }
1293 }
1294
1295 public ArrayList Resources
1296 {
1297 get
1298 {
1299 return this.m_sResourcesArray;
1300 }
1301 set
1302 {
1303 this.m_sResourcesArray = value;
1304 }
1305 }
1306
1307 public int Rows
1308 {
1309 get
1310 {
1311 return (0x5a0 / this.m_nTimeScale);
1312 }
1313 }
1314
1315 public int SelectedAppointment
1316 {
1317 get
1318 {
1319 return this.m_nSelectID;
1320 }
1321 set
1322 {
1323 this.m_nSelectID = value;
1324 }
1325 }
1326
1327 public CGAppointments SelectedAppointments
1328 {
1329 get
1330 {
1331 return this.m_SelectedAppointments;
1332 }
1333 }
1334
1335 public CGRange SelectedRange
1336 {
1337 get
1338 {
1339 return this.m_selectedRange;
1340 }
1341 }
1342
1343 public DateTime StartDate
1344 {
1345 get
1346 {
1347 return this.m_dtStart;
1348 }
1349 set
1350 {
1351 this.m_dtStart = value;
1352 }
1353 }
1354
1355 public int TimeScale
1356 {
1357 get
1358 {
1359 return this.m_nTimeScale;
1360 }
1361 set
1362 {
1363 if ((((value == 5) || (value == 10)) || ((value == 15) || (value == 20))) || ((value == 30) || (value == 60)))
1364 {
1365 this.m_nTimeScale = value;
1366 this.m_gridCells.ClearAllCells();
1367 this.m_selectedRange.Cells.ClearAllCells();
1368 Graphics g = base.CreateGraphics();
1369 this.BuildGridCellsArray(g);
1370 this.SetAppointmentTypes();
1371 base.Invalidate();
1372 }
1373 }
1374 }
[821]1375
[622]1376 }
1377}
1378
Note: See TracBrowser for help on using the repository browser.