Free cookie consent management tool by TermsFeed Policy Generator

source: branches/3.3-HiveMigration/sources/HeuristicLab.Hive/HeuristicLab.Calendar/3.3/DayView.cs @ 4105

Last change on this file since 4105 was 4105, checked in by cneumuel, 14 years ago

added HeuristicLab.Calendar (calendar GUI implementation from hive project) (#1107)

File size: 46.2 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Text;
4using System.Windows.Forms;
5using System.Drawing;
6using System.ComponentModel;
7using System.Drawing.Drawing2D;
8
9namespace HeuristicLab.Calendar
10{
11    public class DayView : Control
12    {
13        public DayView()
14        {
15            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
16            SetStyle(ControlStyles.ResizeRedraw, true);
17            SetStyle(ControlStyles.Selectable, true);
18      SetStyle(ControlStyles.AllPaintingInWmPaint, true);
19      SetStyle(ControlStyles.UserPaint, true);
20
21            scrollbar = new VScrollBar();
22            scrollbar.SmallChange = appointmentSlotHeight;
23            scrollbar.LargeChange = appointmentSlotHeight * 2;
24            scrollbar.Dock = DockStyle.Right;
25            scrollbar.Visible = allowScroll;
26            scrollbar.Scroll += new ScrollEventHandler(scrollbar_Scroll);
27            AdjustScrollbar();
28            scrollbar.Value = (startHour * 2 * appointmentSlotHeight);
29
30            this.Controls.Add(scrollbar);
31
32            editbox = new TextBox();
33            editbox.Multiline = true;
34            editbox.Visible = false;
35            editbox.BorderStyle = BorderStyle.None;
36            editbox.KeyUp += new KeyEventHandler(editbox_KeyUp);
37            editbox.Margin = Padding.Empty;
38
39            this.Controls.Add(editbox);
40
41            drawTool = new DrawTool();
42            drawTool.DayView = this;
43
44            selectionTool = new SelectionTool();
45            selectionTool.DayView = this;
46            selectionTool.Complete += new EventHandler(selectionTool_Complete);
47
48            activeTool = drawTool;
49
50            UpdateWorkingHours();
51
52            this.Renderer = new Office12Renderer();
53        }
54
55    #region " Private Fields "
56    private TextBox editbox;
57    private VScrollBar scrollbar;
58    private DrawTool drawTool;
59    private SelectionTool selectionTool;
60    private int allDayEventsHeaderHeight = 20;
61
62    private DateTime workStart;
63    private DateTime workEnd;
64
65    private int hourLabelWidth = 50;
66    private int hourLabelIndent = 2;
67    private int dayHeadersHeight = 20;
68    private int appointmentGripWidth = 5;
69    private int dayGripWidth = 5;
70    private int horizontalAppointmentHeight = 20;
71
72    private AppHeightDrawMode appHeightMode = AppHeightDrawMode.TrueHeightAll;
73    private int appointmentSlotHeight = 24;
74    private AbstractRenderer renderer;
75    private bool ampmdisplay = false;
76    private bool drawAllAppBorder = false;
77    private bool minHalfHourApp = false;
78    private int daysToShow = 1;
79    private SelectionType selection;
80    private DateTime startDate;
81    private int startHour = 8;
82    private Appointment selectedAppointment;
83    private DateTime selectionStart;
84    private DateTime selectionEnd;
85    private ITool activeTool;
86    private int workingHourStart = 8;
87    private int workingMinuteStart = 30;
88    private int workingHourEnd = 18;
89    private int workingMinuteEnd = 30;
90    private bool selectedAppointmentIsNew;
91    private bool allowScroll = true;
92    private bool allowInplaceEditing = true;
93    private bool allowNew = true;
94    private bool enableShadows = true;
95    private bool enableRoundCorners = false;
96    private bool enableTimeIndicator = false;
97    private bool enableDurationDisplay = false;
98    private AppointmentSlotDuration appointmentSlotDuration = AppointmentSlotDuration.ThirtyMinutes;
99
100    internal System.Collections.Hashtable cachedAppointments = new System.Collections.Hashtable();
101    internal Dictionary<Appointment, AppointmentView> appointmentViews = new Dictionary<Appointment, AppointmentView>();
102    internal Dictionary<Appointment, AppointmentView> longappointmentViews = new Dictionary<Appointment, AppointmentView>();
103    #endregion
104
105    #region Properties
106    [Category("DailyView")]
107    [System.ComponentModel.DefaultValue(5)]
108    public int DayGripWidth
109    {
110      get
111      {
112        return dayGripWidth;
113      }
114      set
115      {
116        if (dayGripWidth == value)
117          return;
118
119        dayGripWidth = value;
120        this.Invalidate();
121      }
122    }
123
124    [Category("DailyView")]
125    [System.ComponentModel.DefaultValue(20)]
126    public int DayHeadersHeight
127    {
128      get
129      {
130        return dayHeadersHeight;
131      }
132      set
133      {
134        if (dayHeadersHeight == value)
135          return;
136
137        dayHeadersHeight = value;
138        this.Invalidate();
139      }
140    }
141   
142    [Category("DailyView")]
143    public bool AmPmDisplay
144        {
145            get
146            {
147                return ampmdisplay;
148            }
149            set
150            {
151        if (ampmdisplay == value)
152          return;
153                ampmdisplay = value;
154                this.Invalidate();
155            }
156        }
157
158    [Category("DailyView")]
159    public bool MinHalfHourApp
160        {
161            get
162            {
163                return minHalfHourApp;
164            }
165            set
166            {
167        if (minHalfHourApp == value)
168          return;
169
170                minHalfHourApp = value;
171                this.Invalidate();
172            }
173        }
174
175    [Category("DailyView")]
176        [System.ComponentModel.DefaultValue(1)]
177        public int DaysToShow
178        {
179            get
180            {
181                return daysToShow;
182            }
183            set
184            {
185        if (daysToShow == value)
186          return;
187                daysToShow = value;
188       
189        if (this.CurrentlyEditing)
190          FinishEditing(true);
191
192        this.Invalidate();
193            }
194        }
195
196    [Category("DailyView")]
197        public DateTime StartDate
198        {
199            get
200            {
201                return startDate;
202            }
203            set
204            {
205        if (startDate == value)
206          return;
207                startDate = value;
208
209        startDate = startDate.Date;
210
211        selectedAppointment = null;
212        selectedAppointmentIsNew = false;
213        selection = SelectionType.DateRange;
214
215        this.Invalidate();
216            }
217        }
218
219    [Category("DailyView")]
220        [System.ComponentModel.DefaultValue(8)]
221        public int StartHour
222        {
223            get
224            {
225                return startHour;
226            }
227            set
228            {
229                startHour = value;
230                OnStartHourChanged();
231            }
232        }
233
234    [Category("DailyView")]
235        [System.ComponentModel.DefaultValue(8)]
236        public int WorkingHourStart
237        {
238            get
239            {
240                return workingHourStart;
241            }
242            set
243            {
244                workingHourStart = value;
245                UpdateWorkingHours();
246            }
247        }
248
249    [Category("DailyView")]
250        [System.ComponentModel.DefaultValue(30)]
251        public int WorkingMinuteStart
252        {
253            get
254            {
255                return workingMinuteStart;
256            }
257            set
258            {
259                workingMinuteStart = value;
260                UpdateWorkingHours();
261            }
262        }
263
264    [Category("DailyView")]
265        [System.ComponentModel.DefaultValue(18)]
266        public int WorkingHourEnd
267        {
268            get
269            {
270                return workingHourEnd;
271            }
272            set
273            {
274                workingHourEnd = value;
275                UpdateWorkingHours();
276            }
277        }
278
279    [Category("DailyView")]
280        [System.ComponentModel.DefaultValue(30)]
281        public int WorkingMinuteEnd
282        {
283            get { return workingMinuteEnd; }
284            set
285            {
286                workingMinuteEnd = value;
287                UpdateWorkingHours();
288            }
289        }
290
291    [Category("DailyView")]
292        [DefaultValue(true)]
293        public bool AllowScroll
294        {
295            get
296            {
297                return allowScroll;
298            }
299            set
300            {
301        if (allowScroll == value)
302          return;
303
304                allowScroll = value;
305
306        this.scrollbar.Visible = this.AllowScroll;
307        this.Invalidate();
308            }
309        }
310
311    [Category("DailyView")]
312        [DefaultValue(true)]
313        public bool AllowInplaceEditing
314        {
315            get
316            {
317                return allowInplaceEditing;
318            }
319            set
320            {
321                allowInplaceEditing = value;
322            }
323        }
324
325    [Category("DailyView.Appointment")]
326    [System.ComponentModel.DefaultValue(24)]
327    public int AppointmentSlotHeight
328    {
329      get
330      {
331        return appointmentSlotHeight;
332      }
333      set
334      {
335        if (appointmentSlotHeight == value)
336          return;
337
338        appointmentSlotHeight = value;
339        AdjustScrollbar();
340        this.Invalidate();
341      }
342    }
343
344    [Category("DailyView.Appointment")]
345    [System.ComponentModel.DefaultValue(5)]
346    public int AppointmentGripWidth
347    {
348      get
349      {
350        return appointmentGripWidth;
351      }
352      set
353      {
354        if (appointmentGripWidth == value)
355          return;
356
357        appointmentGripWidth = value;
358        this.Invalidate();
359      }
360    }
361
362    [Category("DailyView.Appointment")]
363    public bool DrawAllAppBorder
364    {
365      get
366      {
367        return drawAllAppBorder;
368      }
369      set
370      {
371        if (drawAllAppBorder == value)
372          return;
373        drawAllAppBorder = value;
374        this.Invalidate();
375      }
376    }
377
378    [Category("DailyView.Appointment")]
379    [System.ComponentModel.DefaultValue(20)]
380    public int HorizontalAppointmentHeight
381    {
382      get
383      {
384        return horizontalAppointmentHeight;
385      }
386      set
387      {
388        if (horizontalAppointmentHeight == value)
389          return;
390
391        horizontalAppointmentHeight = value;
392        this.Invalidate();
393      }
394    }
395
396    [Category("DailyView.Appointment")]
397    public AppHeightDrawMode AppointmentHeightMode
398    {
399      get { return appHeightMode; }
400      set { appHeightMode = value; }
401    }
402   
403    [Category("DailyView.Appointment")]
404        [DefaultValue(true)]
405        public bool AllowNew
406        {
407            get
408            {
409                return allowNew;
410            }
411            set
412            {
413                allowNew = value;
414            }
415        }
416
417    [Category("DailyView.Appointment")]
418    public bool EnableShadows
419    {
420      get
421      {
422        return enableShadows;
423      }
424      set
425      {
426        if (enableShadows == value)
427          return;
428        enableShadows = value;
429        this.Invalidate();
430      }
431    }
432
433    [Category("DailyView.Appointment")]
434    public bool EnableRoundedCorners
435    {
436      get
437      {
438        return enableRoundCorners;
439      }
440      set
441      {
442        if (enableRoundCorners == value)
443          return;
444        enableRoundCorners = value;
445        this.Invalidate();
446      }
447    }
448
449    [Category("DailyView.Appointment")]
450    public bool EnableTimeIndicator
451    {
452      get
453      {
454        return enableTimeIndicator;
455      }
456      set
457      {
458        if (value == enableTimeIndicator)
459          return;
460        enableTimeIndicator = value;
461        this.Invalidate();
462      }
463    }
464
465    [Category("DailyView.Appointment")]
466    public bool EnableDurationDisplay
467    {
468      get
469      {
470        return enableDurationDisplay;
471      }
472      set
473      {
474        if (value == enableDurationDisplay)
475          return;
476        enableDurationDisplay = value;
477        this.Invalidate();
478      }
479    }
480
481    [Category("DailyView.Appointment")]
482    [System.ComponentModel.DefaultValue(AppointmentSlotDuration.ThirtyMinutes)]
483    public AppointmentSlotDuration AppointmentDuration
484    {
485      get
486      {
487        return appointmentSlotDuration;
488      }
489      set
490      {
491        if (appointmentSlotDuration == value)
492          return;
493        appointmentSlotDuration = value;
494        this.Invalidate();
495      }
496    }
497    #endregion
498
499    #region " Property Overrides "
500    [System.ComponentModel.Browsable(false)]
501    public override Color BackColor
502    {
503      get
504      {
505        return base.BackColor;
506      }
507      set
508      {
509        base.BackColor = value;
510      }
511    }
512    [System.ComponentModel.Browsable(false)]
513    public override string Text
514    {
515      get
516      {
517        return base.Text;
518      }
519      set
520      {
521        base.Text = value;
522      }
523    }
524    [System.ComponentModel.Browsable(false)]
525    public override Image BackgroundImage
526    {
527      get
528      {
529        return base.BackgroundImage;
530      }
531      set
532      {
533        base.BackgroundImage = value;
534      }
535    }
536    [System.ComponentModel.Browsable(false)]
537    public override ImageLayout BackgroundImageLayout
538    {
539      get
540      {
541        return base.BackgroundImageLayout;
542      }
543      set
544      {
545        base.BackgroundImageLayout = value;
546      }
547    }
548    [System.ComponentModel.Browsable(false)]
549    public override System.Drawing.Color ForeColor
550    {
551      get
552      {
553        return base.ForeColor;
554      }
555      set
556      {
557        base.ForeColor = value;
558      }
559    }
560    [System.ComponentModel.Browsable(false)]
561    public override Font Font
562    {
563      get
564      {
565        return base.Font;
566      }
567      set
568      {
569        base.Font = value;
570      }
571    }
572    [System.ComponentModel.Browsable(false)]
573    public override RightToLeft RightToLeft
574    {
575      get
576      {
577        return base.RightToLeft;
578      }
579      set
580      {
581        base.RightToLeft = value;
582      }
583    }
584    #endregion
585
586    #region " Private Properties "
587    [System.ComponentModel.Browsable(false)]
588    public DateTime SelectionStart
589    {
590      get { return selectionStart; }
591      set { selectionStart = value; }
592    }
593
594    [System.ComponentModel.Browsable(false)]
595    public DateTime SelectionEnd
596    {
597      get { return selectionEnd; }
598      set { selectionEnd = value; }
599    }
600   
601    [System.ComponentModel.Browsable(false)]
602    public bool SelectedAppointmentIsNew
603    {
604      get
605      {
606        return selectedAppointmentIsNew;
607      }
608    }
609
610    [System.ComponentModel.Browsable(false)]
611    public int VScrollBarWith
612    {
613      get
614      {
615        if (scrollbar.Visible)
616          return scrollbar.Width;
617        else
618          return 0;
619      }
620    }
621
622    [System.ComponentModel.Browsable(false)]
623    public ITool ActiveTool
624    {
625      get { return activeTool; }
626      set { activeTool = value; }
627    }
628
629    [System.ComponentModel.Browsable(false)]
630    public bool CurrentlyEditing
631    {
632      get
633      {
634        return editbox.Visible;
635      }
636    }
637
638    [System.ComponentModel.Browsable(false)]
639    public Appointment SelectedAppointment
640    {
641      get { return selectedAppointment; }
642    }
643
644    [System.ComponentModel.Browsable(false)]
645    public SelectionType Selection
646    {
647      get
648      {
649        return selection;
650      }
651    }
652
653    [System.ComponentModel.Browsable(false)]
654    [System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)]
655    public AbstractRenderer Renderer
656    {
657      get
658      {
659        return renderer;
660      }
661      set
662      {
663        if (renderer == value)
664          return;
665
666        renderer = value;
667        this.Font = renderer.BaseFont;
668        this.Invalidate();
669      }
670    }
671   
672    [System.ComponentModel.Browsable(false)]
673    private int HeaderHeight
674    {
675      get
676      {
677        return dayHeadersHeight + allDayEventsHeaderHeight;
678      }
679    }
680    #endregion
681
682    #region Event Handlers
683    private void editbox_KeyUp(object sender, KeyEventArgs e)
684        {
685            if (e.KeyCode == Keys.Escape)
686            {
687                e.Handled = true;
688                FinishEditing(true);
689            }
690            else if (e.KeyCode == Keys.Enter)
691            {
692                e.Handled = true;
693                FinishEditing(false);
694            }
695        }
696
697    private void selectionTool_Complete(object sender, EventArgs e)
698        {
699            if (selectedAppointment != null)
700            {
701                System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(EnterEditMode));
702            }
703        }
704
705    private void scrollbar_Scroll(object sender, ScrollEventArgs e)
706        {
707            Invalidate();
708     
709      //scroll text box too
710            if (editbox.Visible)
711                editbox.Top += e.OldValue - e.NewValue;
712        }
713
714        protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
715        {
716            base.SetBoundsCore(x, y, width, height, specified);
717            AdjustScrollbar();
718        }
719
720        protected override void OnPaintBackground(PaintEventArgs pevent)
721        {
722            // Flicker free
723        }
724
725        protected override void OnMouseDown(MouseEventArgs e)
726        {
727            // Capture focus
728            this.Focus();
729
730            if (CurrentlyEditing)
731            {
732                FinishEditing(false);
733            }
734
735            if (selectedAppointmentIsNew)
736            {
737                RaiseNewAppointment();
738            }
739
740            ITool newTool = null;
741
742            Appointment appointment = GetAppointmentAt(e.X, e.Y);
743
744            if (e.Y < HeaderHeight && e.Y > dayHeadersHeight && appointment == null)
745            {
746                if (selectedAppointment != null)
747                {
748                    selectedAppointment = null;
749                    Invalidate();
750                }
751
752                newTool = drawTool;
753                selection = SelectionType.None;
754
755                base.OnMouseDown(e);
756                return;
757            }
758
759            if (appointment == null)
760            {
761                if (selectedAppointment != null)
762                {
763                    selectedAppointment = null;
764                    Invalidate();
765                }
766
767                newTool = drawTool;
768                selection = SelectionType.DateRange;
769            }
770            else
771            {
772                newTool = selectionTool;
773                selectedAppointment = appointment;
774                selection = SelectionType.Appointment;
775
776                Invalidate();
777            }
778
779            if (activeTool != null)
780            {
781                activeTool.MouseDown(e);
782            }
783
784            if ((activeTool != newTool) && (newTool != null))
785            {
786                newTool.Reset();
787                newTool.MouseDown(e);
788            }
789
790            activeTool = newTool;
791
792            base.OnMouseDown(e);
793        }
794
795        protected override void OnMouseMove(MouseEventArgs e)
796        {
797            if (activeTool != null)
798                activeTool.MouseMove(e);
799
800            base.OnMouseMove(e);
801        }
802
803        protected override void OnMouseUp(MouseEventArgs e)
804        {
805            if (activeTool != null)
806                activeTool.MouseUp(e);
807
808            base.OnMouseUp(e);
809        }
810
811        protected override void OnMouseWheel(MouseEventArgs e)
812        {
813            base.OnMouseWheel(e);
814
815            if (e.Delta < 0)
816            {//mouse wheel scroll down
817                ScrollMe(true);
818            }
819            else
820            {//mouse wheel scroll up
821                ScrollMe(false);
822            }
823        }
824
825    protected override void OnKeyPress(KeyPressEventArgs e)
826        {
827            if ((allowNew) && char.IsLetterOrDigit(e.KeyChar))
828            {
829                if ((this.Selection == SelectionType.DateRange))
830                {
831                    if (!selectedAppointmentIsNew)
832                        EnterNewAppointmentMode(e.KeyChar);
833                }
834            }
835        }
836
837    protected virtual void ResolveAppointments(ResolveAppointmentsEventArgs args)
838    {
839      //System.Diagnostics.Debug.WriteLine("Resolve app");
840
841      if (OnResolveAppointments != null)
842        OnResolveAppointments(this, args);
843
844      this.allDayEventsHeaderHeight = 0;
845
846      // cache resolved appointments in hashtable by days.
847      cachedAppointments.Clear();
848
849      if ((selectedAppointmentIsNew) && (selectedAppointment != null))
850      {
851        if ((selectedAppointment.StartDate > args.StartDate) && (selectedAppointment.StartDate < args.EndDate))
852        {
853          args.Appointments.Add(selectedAppointment);
854        }
855      }
856
857      foreach (Appointment appointment in args.Appointments)
858      {
859        int key = -1;
860        AppointmentList list;
861
862        if (appointment.StartDate.Day == appointment.EndDate.Day && appointment.AllDayEvent == false)
863        {
864          key = appointment.StartDate.Day;
865        }
866        else
867        {
868          key = -1;
869        }
870
871        list = (AppointmentList)cachedAppointments[key];
872
873        if (list == null)
874        {
875          list = new AppointmentList();
876          cachedAppointments[key] = list;
877        }
878
879        list.Add(appointment);
880      }
881    }
882    #endregion
883
884        #region " Public Methods "
885
886        public void ScrollMe(bool down)
887        {
888      if (this.AllowScroll == false)
889        return;
890
891      int newScrollValue;
892
893            if (down)
894            {//mouse wheel scroll down
895                newScrollValue = this.scrollbar.Value + this.scrollbar.SmallChange;
896
897                if (newScrollValue < this.scrollbar.Maximum)
898                    this.scrollbar.Value = newScrollValue;
899                else
900                    this.scrollbar.Value = this.scrollbar.Maximum;
901            }
902            else
903            {//mouse wheel scroll up
904                newScrollValue = this.scrollbar.Value - this.scrollbar.SmallChange;
905
906                if (newScrollValue > this.scrollbar.Minimum)
907                    this.scrollbar.Value = newScrollValue;
908                else
909                    this.scrollbar.Value = this.scrollbar.Minimum;
910            }
911
912      this.Invalidate();
913        }
914
915        public Rectangle GetTrueRectangle()
916        {
917            Rectangle truerect;
918            truerect = this.ClientRectangle;
919            truerect.X += hourLabelWidth + hourLabelIndent;
920      truerect.Width -= VScrollBarWith + hourLabelWidth + hourLabelIndent;
921            truerect.Y += this.HeaderHeight;
922            truerect.Height -= this.HeaderHeight;
923
924            return truerect;
925        }
926
927        public Rectangle GetFullDayApptsRectangle()
928        {
929            Rectangle fulldayrect;
930            fulldayrect = this.ClientRectangle;
931            fulldayrect.Height = this.HeaderHeight - dayHeadersHeight;
932            fulldayrect.Y += dayHeadersHeight;
933      fulldayrect.Width -= (hourLabelWidth + hourLabelIndent + this.VScrollBarWith);
934            fulldayrect.X += hourLabelWidth + hourLabelIndent;
935
936            return fulldayrect;
937        }
938       
939        public void StartEditing()
940        {
941            if (!selectedAppointment.Locked && appointmentViews.ContainsKey(selectedAppointment))
942            {
943                Rectangle editBounds = appointmentViews[selectedAppointment].Rectangle;
944
945                editBounds.Inflate(-3, -3);
946                editBounds.X += appointmentGripWidth - 2;
947                editBounds.Width -= appointmentGripWidth - 5;
948
949                editbox.Bounds = editBounds;
950                editbox.Text = selectedAppointment.Subject;
951                editbox.Visible = true;
952                editbox.SelectionStart = editbox.Text.Length;
953                editbox.SelectionLength = 0;
954
955                editbox.Focus();
956            }
957        }
958
959        public void FinishEditing(bool cancel)
960        {
961            editbox.Visible = false;
962
963            if (!cancel)
964            {
965                if (selectedAppointment != null)
966                    selectedAppointment.Subject = editbox.Text;
967            }
968            else
969            {
970                if (selectedAppointmentIsNew)
971                {
972                    selectedAppointment = null;
973                    selectedAppointmentIsNew = false;
974                }
975            }
976
977            Invalidate();
978            this.Focus();
979        }
980
981        public DateTime GetTimeAt(int x, int y)
982        {
983      int dayWidth = (this.Width - (VScrollBarWith + hourLabelWidth + hourLabelIndent)) / daysToShow;
984
985            int hour = (y - this.HeaderHeight + scrollbar.Value) / appointmentSlotHeight;
986            x -= hourLabelWidth;
987
988            DateTime date = startDate;
989
990            date = date.Date;
991            date = date.AddDays(x / dayWidth);
992
993            if ((hour > 0) && (hour < 24 * 2))
994                date = date.AddMinutes((hour * 30));
995
996            return date;
997        }
998
999        public Appointment GetAppointmentAt(int x, int y)
1000        {
1001            foreach (AppointmentView view in appointmentViews.Values)
1002                if (view.Rectangle.Contains(x, y))
1003                    return view.Appointment;
1004
1005            foreach (AppointmentView view in longappointmentViews.Values)
1006                if (view.Rectangle.Contains(x, y))
1007                    return view.Appointment;
1008
1009            return null;
1010    }
1011
1012    private Rectangle GetHourRangeRectangle(DateTime start, DateTime end, Rectangle baseRectangle)
1013    {
1014      Rectangle rect = baseRectangle;
1015
1016      int startY;
1017      int endY;
1018
1019      startY = (start.Hour * appointmentSlotHeight * 2) + ((start.Minute * appointmentSlotHeight) / 30);
1020      endY = (end.Hour * appointmentSlotHeight * 2) + ((end.Minute * appointmentSlotHeight) / 30);
1021
1022      rect.Y = startY - scrollbar.Value + this.HeaderHeight;
1023
1024      rect.Height = System.Math.Max(1, endY - startY);
1025
1026      return rect;
1027    }
1028    #endregion
1029   
1030    #region " Private Methods "
1031    private void AdjustScrollbar()
1032    {
1033      scrollbar.Maximum = (2 * appointmentSlotHeight * 25) - this.Height + this.HeaderHeight;
1034      scrollbar.Minimum = 0;
1035    }
1036    protected virtual void OnStartHourChanged()
1037    {
1038      // Fix : http://www.codeproject.com/cs/miscctrl/Calendardayview.asp?forumid=232232&select=1901930&df=100#xx1901930xx
1039
1040      if ((startHour * 2 * appointmentSlotHeight) > scrollbar.Maximum) //maximum is lower on larger forms
1041      {
1042        scrollbar.Value = scrollbar.Maximum;
1043      }
1044      else
1045      {
1046        scrollbar.Value = (startHour * 2 * appointmentSlotHeight);
1047      }
1048
1049      Invalidate();
1050    }
1051    private void UpdateWorkingHours()
1052    {
1053      workStart = new DateTime(1, 1, 1, workingHourStart, workingMinuteStart, 0);
1054      workEnd = new DateTime(1, 1, 1, workingHourEnd, workingMinuteEnd, 0);
1055
1056      Invalidate();
1057    }
1058    private void EnterNewAppointmentMode(char key)
1059    {
1060      Appointment appointment = new Appointment();
1061      appointment.StartDate = selectionStart;
1062      appointment.EndDate = selectionEnd;
1063      appointment.Subject = key.ToString();
1064
1065      selectedAppointment = appointment;
1066      selectedAppointmentIsNew = true;
1067
1068      activeTool = selectionTool;
1069
1070      Invalidate();
1071
1072      System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(EnterEditMode));
1073    }
1074
1075    private delegate void StartEditModeDelegate(object state);
1076    private void EnterEditMode(object state)
1077    {
1078      if (!allowInplaceEditing)
1079        return;
1080
1081      if (this.InvokeRequired)
1082      {
1083        Appointment selectedApp = selectedAppointment;
1084
1085        System.Threading.Thread.Sleep(200);
1086
1087        if (selectedApp == selectedAppointment)
1088          this.Invoke(new StartEditModeDelegate(EnterEditMode), state);
1089      }
1090      else
1091      {
1092        StartEditing();
1093      }
1094    }
1095    #endregion
1096
1097    #region " Method Overrides "
1098    protected override void Dispose(bool disposing)
1099    {
1100      if (disposing)
1101      {
1102        editbox.Dispose();
1103        scrollbar.Dispose();
1104      }
1105      base.Dispose(disposing);
1106    }
1107    #endregion
1108
1109    #region " Drawing Methods "
1110    protected override void OnPaint(PaintEventArgs e)
1111        {
1112      e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
1113
1114      // resolve appointments on visible date range.
1115      ResolveAppointmentsEventArgs args = new ResolveAppointmentsEventArgs(this.StartDate, this.StartDate.AddDays(daysToShow));
1116      ResolveAppointments(args);
1117
1118      using (SolidBrush backBrush = new SolidBrush(renderer.BackColor))
1119        e.Graphics.FillRectangle(backBrush, this.ClientRectangle);
1120
1121      // Visible Rectangle
1122      Rectangle rectangle = new Rectangle(0, 0, this.Width - VScrollBarWith, this.Height);
1123
1124      DrawDays(ref e, rectangle);
1125
1126      DrawHourLabels(ref e, rectangle);
1127
1128      DrawDayHeaders(ref e, rectangle);
1129        }
1130
1131    private void DrawDays(ref PaintEventArgs e, Rectangle rectangle)
1132    {
1133      Rectangle rect = rectangle;
1134      rect.X += hourLabelWidth + hourLabelIndent;
1135      rect.Y += this.HeaderHeight;
1136      rect.Width -= (hourLabelWidth + hourLabelIndent);
1137
1138
1139      if (e.ClipRectangle.IntersectsWith(rect) == false)
1140        return;
1141
1142      int dayWidth = rect.Width / daysToShow;
1143
1144      #region " Multi Day Appointments "
1145      AppointmentList longAppointments = (AppointmentList)cachedAppointments[-1];
1146
1147      AppointmentList drawnLongApps = new AppointmentList();
1148
1149      AppointmentView view;
1150
1151      int y = dayHeadersHeight;
1152      bool intersect = false;
1153
1154      List<int> layers = new List<int>();
1155      if (longAppointments != null)
1156      {
1157
1158        foreach (Appointment appointment in longAppointments)
1159        {
1160          appointment.Layer = 0;
1161
1162          if (drawnLongApps.Count != 0)
1163          {
1164            foreach (Appointment app in drawnLongApps)
1165              if (!layers.Contains(app.Layer))
1166                layers.Add(app.Layer);
1167
1168            foreach (int lay in layers)
1169            {
1170              foreach (Appointment app in drawnLongApps)
1171              {
1172                if (app.Layer == lay)
1173                  if (appointment.StartDate.Date >= app.EndDate.Date || appointment.EndDate.Date <= app.StartDate.Date)
1174                    intersect = false;
1175                  else
1176                  {
1177                    intersect = true;
1178                    break;
1179                  }
1180                appointment.Layer = lay;
1181              }
1182
1183              if (!intersect)
1184                break;
1185            }
1186
1187            if (intersect)
1188              appointment.Layer = layers.Count;
1189          }
1190
1191          drawnLongApps.Add(appointment); // changed by Gimlei
1192        }
1193
1194        foreach (Appointment app in drawnLongApps)
1195          if (!layers.Contains(app.Layer))
1196            layers.Add(app.Layer);
1197
1198        allDayEventsHeaderHeight = layers.Count * (horizontalAppointmentHeight + 5) + 5;
1199
1200        Rectangle backRectangle = rect;
1201        backRectangle.Y = y;
1202        backRectangle.Height = allDayEventsHeaderHeight;
1203
1204        renderer.DrawAllDayBackground(e.Graphics, backRectangle);
1205
1206        foreach (Appointment appointment in longAppointments)
1207        {
1208          Rectangle appointmenRect = rect;
1209          int spanDays = appointment.EndDate.Subtract(appointment.StartDate).Days;
1210
1211          if (appointment.EndDate.Day != appointment.StartDate.Day && appointment.EndDate.TimeOfDay < appointment.StartDate.TimeOfDay)
1212            spanDays += 1;
1213
1214          appointmenRect.Width = dayWidth * spanDays - 5;
1215          appointmenRect.Height = horizontalAppointmentHeight;
1216          appointmenRect.X += (appointment.StartDate.Subtract(startDate).Days) * dayWidth; // changed by Gimlei
1217          appointmenRect.Y = y + appointment.Layer * (horizontalAppointmentHeight + 5) + 5; // changed by Gimlei
1218
1219          view = new AppointmentView();
1220          view.Rectangle = appointmenRect;
1221          view.Appointment = appointment;
1222
1223          longappointmentViews[appointment] = view;
1224
1225          Rectangle gripRect = appointmenRect;
1226          gripRect.Width = appointmentGripWidth;
1227
1228          renderer.DrawAppointment(e.Graphics, appointmenRect, appointment, appointment == selectedAppointment, gripRect, EnableShadows, EnableRoundedCorners);
1229
1230        }
1231      }
1232      #endregion
1233
1234      DateTime time = startDate;
1235      Rectangle rectangle2 = rect;
1236      rectangle2.Width = dayWidth;
1237      rectangle2.Y += allDayEventsHeaderHeight;
1238      rectangle2.Height -= allDayEventsHeaderHeight;
1239
1240      appointmentViews.Clear();
1241      layers.Clear();
1242
1243      for (int day = 0; day < daysToShow; day++)
1244      {
1245        DrawDay(ref e, rectangle2, time);
1246
1247        rectangle2.X += dayWidth;
1248
1249        time = time.AddDays(1);
1250      }
1251    }
1252
1253    private void DrawHourLabels(ref PaintEventArgs e, Rectangle rectangle)
1254        {
1255      Rectangle rect = rectangle;
1256      rect.Y += this.HeaderHeight;
1257
1258            e.Graphics.SetClip(rect);
1259
1260      int hourlabelheight = (int)AppointmentDuration * AppointmentSlotHeight;
1261
1262            for (int m_Hour = 0; m_Hour < 24; m_Hour++)
1263            {
1264                Rectangle hourRectangle = rect;
1265
1266                hourRectangle.Y = rect.Y + (m_Hour * 2 * appointmentSlotHeight) - scrollbar.Value;
1267                hourRectangle.X += hourLabelIndent;
1268                hourRectangle.Width = hourLabelWidth;
1269        hourRectangle.Height = hourlabelheight;
1270
1271                if (hourRectangle.Y > this.HeaderHeight / 2)
1272                    renderer.DrawHourLabel(e.Graphics, hourRectangle, m_Hour, this.AmPmDisplay, EnableTimeIndicator);
1273            }
1274
1275            e.Graphics.ResetClip();
1276        }
1277
1278    private void DrawDayHeaders(ref PaintEventArgs e, Rectangle rectangle)
1279        {
1280      Rectangle rect = rectangle;
1281      rect.X += hourLabelWidth + hourLabelIndent;
1282      rect.Width -= (hourLabelWidth + hourLabelIndent);
1283      rect.Height = dayHeadersHeight;
1284
1285      if (e.ClipRectangle.IntersectsWith(rect) == false)
1286        return;
1287
1288            int dayWidth = rect.Width / daysToShow;
1289
1290            //one day header rectangle
1291            Rectangle dayHeaderRectangle = new Rectangle(rect.Left, rect.Top, dayWidth, rect.Height);
1292            DateTime headerDate = startDate;
1293
1294            for (int day = 0; day < daysToShow; day++)
1295            {
1296                renderer.DrawDayHeader(e.Graphics, dayHeaderRectangle, headerDate);
1297
1298                dayHeaderRectangle.X += dayWidth;
1299                headerDate = headerDate.AddDays(1);
1300            }
1301      Rectangle scrollrect = rectangle;
1302      if (this.AllowScroll == false)
1303      {
1304        scrollrect.X = rect.Width + hourLabelWidth + hourLabelIndent;
1305        scrollrect.Width = VScrollBarWith;
1306        using (SolidBrush backBrush = new SolidBrush(renderer.BackColor))
1307          e.Graphics.FillRectangle(backBrush, scrollrect);
1308      }
1309        }
1310
1311        private void DrawDay(ref PaintEventArgs e, Rectangle rect, DateTime time)
1312        {
1313            Rectangle workingHoursRectangle = GetHourRangeRectangle(workStart, workEnd, rect);
1314
1315            if (workingHoursRectangle.Y < this.HeaderHeight)
1316            {
1317                // Fix : http://www.codeproject.com/cs/miscctrl/Calendardayview.asp?forumid=232232&select=1904152&df=100#xx1904152xx
1318               
1319                workingHoursRectangle.Height -= this.HeaderHeight - workingHoursRectangle.Y;
1320                workingHoursRectangle.Y = this.HeaderHeight;
1321            }
1322
1323            if (!((time.DayOfWeek == DayOfWeek.Saturday) || (time.DayOfWeek == DayOfWeek.Sunday))) //weekends off -> no working hours
1324                renderer.DrawHourRange(e.Graphics, workingHoursRectangle, false, false);
1325
1326            if ((selection == SelectionType.DateRange) && (time.Day == selectionStart.Day))
1327            {
1328                Rectangle selectionRectangle = GetHourRangeRectangle(selectionStart, selectionEnd, rect);
1329                if (selectionRectangle.Top + 1 > this.HeaderHeight)
1330                renderer.DrawHourRange(e.Graphics, selectionRectangle, false, true);
1331            }
1332
1333            e.Graphics.SetClip(rect);
1334
1335            for (int hour = 0; hour < 24 * 2; hour++)
1336            {
1337                int y = rect.Top + (hour * appointmentSlotHeight) - scrollbar.Value;
1338
1339        using (Pen pen = new Pen(((hour % 2) == 0 ? renderer.HalfHourSeperatorColor : renderer.HourSeperatorColor)))
1340                    e.Graphics.DrawLine(pen, rect.Left, y, rect.Right, y);
1341
1342                if (y > rect.Bottom)
1343                    break;
1344            }
1345
1346            renderer.DrawDayGripper(e.Graphics, rect, dayGripWidth);
1347
1348            e.Graphics.ResetClip();
1349
1350            AppointmentList appointments = (AppointmentList)cachedAppointments[time.Day];
1351
1352            if (appointments != null)
1353            {
1354                List<string> groups = new List<string>();
1355
1356                foreach (Appointment app in appointments)
1357                    if (!groups.Contains(app.Group))
1358                        groups.Add(app.Group);
1359
1360                Rectangle rect2 = rect;
1361                rect2.Width = rect2.Width / groups.Count;
1362
1363                //groups.Sort();
1364
1365                foreach (string group in groups)
1366                {
1367                    DrawAppointments(ref e, rect2, time, group);
1368
1369                    rect2.X += rect2.Width;
1370                }
1371            }
1372        }
1373
1374        private void DrawAppointments(ref PaintEventArgs e, Rectangle rect, DateTime time, string group)
1375        {
1376            DateTime timeStart = time.Date;
1377            DateTime timeEnd = timeStart.AddHours(24);
1378            timeEnd = timeEnd.AddSeconds(-1);
1379
1380            AppointmentList appointments = (AppointmentList)cachedAppointments[time.Day];
1381
1382            if (appointments != null)
1383            {
1384                HalfHourLayout[] layout = GetMaxParalelAppointments(appointments);
1385               
1386                List<Appointment> drawnItems = new List<Appointment>();
1387
1388                for (int halfHour = 0; halfHour < 24 * 2; halfHour++)
1389                {
1390                    HalfHourLayout hourLayout = layout[halfHour];
1391
1392                    if ((hourLayout != null) && (hourLayout.Count > 0))
1393                    {
1394                        for (int appIndex = 0; appIndex < hourLayout.Count; appIndex++)
1395                        {
1396                            Appointment appointment = hourLayout.Appointments[appIndex];
1397
1398                            if (appointment.Group != group)
1399                                continue;
1400
1401                            if (drawnItems.IndexOf(appointment) < 0)
1402                            {
1403                                Rectangle appRect = rect;
1404                                int appointmentWidth;
1405                                AppointmentView view;
1406
1407                                appointmentWidth = rect.Width / appointment.conflictCount;
1408
1409                int lastX = 0;
1410
1411                                foreach (Appointment app in hourLayout.Appointments)
1412                                {
1413                                    if ((app != null) && (app.Group == appointment.Group) && (appointmentViews.ContainsKey(app)))
1414                                    {
1415                                        view = appointmentViews[app];
1416
1417                                        if (lastX < view.Rectangle.X)
1418                                            lastX = view.Rectangle.X;
1419                                    }
1420                                }
1421
1422                                if ((lastX + (appointmentWidth * 2)) > (rect.X + rect.Width))
1423                                    lastX = 0;
1424
1425                                appRect.Width = appointmentWidth - 5;
1426
1427                                if (lastX > 0)
1428                                    appRect.X = lastX + appointmentWidth;
1429
1430                                DateTime appstart = appointment.StartDate;
1431                                DateTime append = appointment.EndDate;
1432
1433                                // Draw the appts boxes depending on the height display mode                           
1434                                // If small appts are to be drawn in half-hour blocks
1435                                if (this.AppointmentHeightMode == AppHeightDrawMode.FullHalfHourBlocksShort && appointment.EndDate.Subtract(appointment.StartDate).TotalMinutes < 30)
1436                                {
1437                                    // Round the start/end time to the last/next halfhour
1438                                    appstart = appointment.StartDate.AddMinutes(-appointment.StartDate.Minute);
1439                                    append = appointment.EndDate.AddMinutes(30 - appointment.EndDate.Minute);
1440                                   
1441                                    // Make sure we've rounded it to the correct halfhour :)
1442                                    if (appointment.StartDate.Minute >= 30)
1443                                        appstart = appstart.AddMinutes(30);
1444                                    if (appointment.EndDate.Minute > 30)
1445                                        append = append.AddMinutes(30);
1446                                }
1447
1448                                // This is basically the same as previous mode, but for all appts
1449                                else if (this.AppointmentHeightMode == AppHeightDrawMode.FullHalfHourBlocksAll)
1450                                {
1451                                    appstart = appointment.StartDate.AddMinutes(-appointment.StartDate.Minute);
1452                                    if (appointment.EndDate.Minute != 0 && appointment.EndDate.Minute != 30)
1453                                        append = appointment.EndDate.AddMinutes(30 - appointment.EndDate.Minute);
1454                                    else
1455                                        append = appointment.EndDate;
1456
1457                                    if (appointment.StartDate.Minute >= 30)
1458                                        appstart = appstart.AddMinutes(30);
1459                                    if (appointment.EndDate.Minute > 30)
1460                                        append = append.AddMinutes(30);
1461                                }
1462
1463                                // Based on previous code
1464                                else if (this.AppointmentHeightMode == AppHeightDrawMode.EndHalfHourBlocksShort && appointment.EndDate.Subtract(appointment.StartDate).TotalMinutes < 30)
1465                                {
1466                                    // Round the end time to the next halfhour
1467                                    append = appointment.EndDate.AddMinutes(30 - appointment.EndDate.Minute);
1468
1469                                    // Make sure we've rounded it to the correct halfhour :)
1470                                    if (appointment.EndDate.Minute > 30)
1471                                        append = append.AddMinutes(30);
1472                                }
1473
1474                                else if (this.AppointmentHeightMode == AppHeightDrawMode.EndHalfHourBlocksAll)
1475                                {
1476                                    // Round the end time to the next halfhour
1477                                    if (appointment.EndDate.Minute != 0 && appointment.EndDate.Minute != 30)
1478                                        append = appointment.EndDate.AddMinutes(30 - appointment.EndDate.Minute);
1479                                    else
1480                                        append = appointment.EndDate;
1481                                    // Make sure we've rounded it to the correct halfhour :)
1482                                    if (appointment.EndDate.Minute > 30)
1483                                        append = append.AddMinutes(30);
1484                                }
1485
1486                                appRect = GetHourRangeRectangle(appstart, append, appRect);
1487
1488                                view = new AppointmentView();
1489                                view.Rectangle = appRect;
1490                                view.Appointment = appointment;
1491
1492                                appointmentViews[appointment] = view;
1493
1494                                e.Graphics.SetClip(rect);
1495
1496                                if (this.DrawAllAppBorder)
1497                                    appointment.DrawBorder = true;
1498
1499                                // Procedure for gripper rectangle is always the same
1500                Rectangle gripRect = appRect;
1501                                gripRect.Width = appointmentGripWidth;
1502                               
1503                                renderer.DrawAppointment(e.Graphics, appRect, appointment, appointment == selectedAppointment, gripRect, this.EnableShadows, this.enableRoundCorners);
1504
1505                                e.Graphics.ResetClip();
1506
1507                                drawnItems.Add(appointment);
1508                            }
1509                        }
1510                    }
1511                }
1512            }
1513        }
1514
1515        private static HalfHourLayout[] GetMaxParalelAppointments(List<Appointment> appointments)
1516        {
1517            HalfHourLayout[] appLayouts = new HalfHourLayout[24 * 2];
1518
1519            foreach (Appointment appointment in appointments)
1520            {
1521                appointment.conflictCount = 1;
1522            }
1523
1524            foreach (Appointment appointment in appointments)
1525            {
1526                int firstHalfHour = appointment.StartDate.Hour * 2 + (appointment.StartDate.Minute / 30);
1527                int lastHalfHour = appointment.EndDate.Hour * 2 + (appointment.EndDate.Minute / 30);
1528
1529                // Added to allow small parts been displayed
1530                if (lastHalfHour == firstHalfHour)
1531                {
1532                    if (lastHalfHour < 24 * 2)
1533                        lastHalfHour++;
1534                    else
1535                        firstHalfHour--;
1536                }
1537
1538                for (int halfHour = firstHalfHour; halfHour < lastHalfHour; halfHour++)
1539                {
1540                    HalfHourLayout layout = appLayouts[halfHour];
1541
1542                    if (layout == null)
1543                    {
1544                        layout = new HalfHourLayout();
1545                        layout.Appointments = new Appointment[20];
1546                        appLayouts[halfHour] = layout;
1547                    }
1548
1549                    layout.Appointments[layout.Count] = appointment;
1550
1551                    layout.Count++;
1552
1553                    List<string> groups = new List<string>();
1554
1555                    foreach (Appointment app2 in layout.Appointments)
1556                    {
1557                        if ((app2 != null) && (!groups.Contains(app2.Group)))
1558                            groups.Add(app2.Group);
1559                    }
1560
1561                    layout.Groups = groups;
1562
1563                    // update conflicts
1564                    foreach (Appointment app2 in layout.Appointments)
1565                    {
1566                        if ((app2 != null) && (app2.Group == appointment.Group))
1567                            if (app2.conflictCount < layout.Count)
1568                                app2.conflictCount = layout.Count - (layout.Groups.Count - 1);
1569                    }
1570                }
1571            }
1572
1573            return appLayouts;
1574        }
1575        #endregion
1576
1577        #region " Internal Utility Classes "
1578
1579        internal class HalfHourLayout
1580        {
1581            public int Count;
1582            public List<string> Groups;
1583            public Appointment[] Appointments;
1584        }
1585
1586        internal class AppointmentView
1587        {
1588            public Appointment Appointment;
1589            public Rectangle Rectangle;
1590        }
1591
1592        internal class AppointmentList : List<Appointment>
1593        {
1594        }
1595
1596        #endregion
1597
1598        #region " Events "
1599        public event EventHandler<EventArgs> OnSelectionChanged;
1600    public event EventHandler<ResolveAppointmentsEventArgs> OnResolveAppointments;
1601    public event EventHandler<NewAppointmentEventArgs> OnNewAppointment;
1602        public event EventHandler<AppointmentEventArgs> OnAppointmentMove;
1603
1604    internal void RaiseNewAppointment()
1605    {
1606      NewAppointmentEventArgs args = new NewAppointmentEventArgs(selectedAppointment.Subject, selectedAppointment.StartDate, selectedAppointment.EndDate);
1607
1608      if (OnNewAppointment != null)
1609      {
1610        OnNewAppointment(this, args);
1611      }
1612
1613      selectedAppointment = null;
1614      selectedAppointmentIsNew = false;
1615
1616      Invalidate();
1617    }
1618
1619    internal void RaiseSelectionChanged(EventArgs e)
1620    {
1621      if (OnSelectionChanged != null)
1622        OnSelectionChanged(this, e);
1623    }
1624
1625    internal void RaiseAppointmentMove(AppointmentEventArgs e)
1626    {
1627      if (OnAppointmentMove != null)
1628        OnAppointmentMove(this, e);
1629    }
1630        #endregion
1631    }
1632}
Note: See TracBrowser for help on using the repository browser.