Added double-click enabled calendar control and comments

This commit is contained in:
gamosoft_cp 2013-03-29 18:03:00 +00:00
parent 837924b0bf
commit 4501a61b08
8 changed files with 212 additions and 89 deletions

View File

@ -31,7 +31,7 @@
this.components = new System.ComponentModel.Container(); this.components = new System.ComponentModel.Container();
this.numRangeDays = new System.Windows.Forms.NumericUpDown(); this.numRangeDays = new System.Windows.Forms.NumericUpDown();
this.lblRangeDays = new System.Windows.Forms.Label(); this.lblRangeDays = new System.Windows.Forms.Label();
this.apptCalendar = new System.Windows.Forms.MonthCalendar(); this.apptCalendar = new Outlook2013TodoAddIn.DoubleClickMonthCalendar();
this.ctxMenuAppointments = new System.Windows.Forms.ContextMenuStrip(this.components); this.ctxMenuAppointments = new System.Windows.Forms.ContextMenuStrip(this.components);
this.mnuItemReplyAllEmail = new System.Windows.Forms.ToolStripMenuItem(); this.mnuItemReplyAllEmail = new System.Windows.Forms.ToolStripMenuItem();
this.hdrDate = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.hdrDate = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
@ -86,6 +86,7 @@
this.apptCalendar.MaxSelectionCount = 1; this.apptCalendar.MaxSelectionCount = 1;
this.apptCalendar.Name = "apptCalendar"; this.apptCalendar.Name = "apptCalendar";
this.apptCalendar.TabIndex = 4; this.apptCalendar.TabIndex = 4;
this.apptCalendar.DoubleClickEx += new System.EventHandler(this.apptCalendar_DoubleClickEx);
this.apptCalendar.DateChanged += new System.Windows.Forms.DateRangeEventHandler(this.monthCalendar1_DateChanged); this.apptCalendar.DateChanged += new System.Windows.Forms.DateRangeEventHandler(this.monthCalendar1_DateChanged);
// //
// ctxMenuAppointments // ctxMenuAppointments
@ -186,7 +187,7 @@
private System.Windows.Forms.NumericUpDown numRangeDays; private System.Windows.Forms.NumericUpDown numRangeDays;
private System.Windows.Forms.Label lblRangeDays; private System.Windows.Forms.Label lblRangeDays;
private System.Windows.Forms.MonthCalendar apptCalendar; private DoubleClickMonthCalendar apptCalendar;
private System.Windows.Forms.ContextMenuStrip ctxMenuAppointments; private System.Windows.Forms.ContextMenuStrip ctxMenuAppointments;
private System.Windows.Forms.ToolStripMenuItem mnuItemReplyAllEmail; private System.Windows.Forms.ToolStripMenuItem mnuItemReplyAllEmail;
private System.Windows.Forms.ColumnHeader hdrDate; private System.Windows.Forms.ColumnHeader hdrDate;

View File

@ -7,22 +7,38 @@ using Outlook = Microsoft.Office.Interop.Outlook;
namespace Outlook2013TodoAddIn namespace Outlook2013TodoAddIn
{ {
/// User control to hold the calendar, etc...
/// </summary>
public partial class AppointmentsControl : UserControl public partial class AppointmentsControl : UserControl
{ {
#region "Variables"
/// <summary>
/// <summary>
/// Used to retrieve the email address of a contact
/// </summary>
private const string PR_SMTP_ADDRESS = "http://schemas.microsoft.com/mapi/proptag/0x39FE001E"; private const string PR_SMTP_ADDRESS = "http://schemas.microsoft.com/mapi/proptag/0x39FE001E";
#endregion "Variables"
#region "Properties"
/// <summary>
/// Number of days (including today) to retrieve appointments from in the future
/// </summary>
public decimal NumDays public decimal NumDays
{ {
get get { return this.numRangeDays.Value; }
{ set { this.numRangeDays.Value = value; }
return this.numRangeDays.Value;
}
set
{
this.numRangeDays.Value = value;
}
} }
#endregion "Properties"
#region "Methods"
/// <summary>
/// Default constructor
/// </summary>
public AppointmentsControl() public AppointmentsControl()
{ {
InitializeComponent(); InitializeComponent();
@ -43,22 +59,40 @@ namespace Outlook2013TodoAddIn
// MessageBox.Show("Test"); // MessageBox.Show("Test");
//} //}
/// <summary>
/// Respond to calendar changes
/// </summary>
/// <param name="sender">Sender</param>
/// <param name="e">DateRangeEventArgs</param>
private void monthCalendar1_DateChanged(object sender, DateRangeEventArgs e) private void monthCalendar1_DateChanged(object sender, DateRangeEventArgs e)
{ {
this.RetrieveAppointments(); this.RetrieveAppointments();
} }
/// <summary>
/// Change days to retrieve appointments in the future
/// </summary>
/// <param name="sender">Sender</param>
/// <param name="e">EventArgs</param>
private void numRangeDays_ValueChanged(object sender, EventArgs e) private void numRangeDays_ValueChanged(object sender, EventArgs e)
{ {
Properties.Settings.Default.NumDays = this.numRangeDays.Value; Properties.Settings.Default.NumDays = this.numRangeDays.Value;
this.RetrieveAppointments(); this.RetrieveAppointments();
} }
/// <summary>
/// Manual refresh
/// </summary>
/// <param name="sender">Sender</param>
/// <param name="e">EventArgs</param>
private void btnRefresh_Click(object sender, EventArgs e) private void btnRefresh_Click(object sender, EventArgs e)
{ {
this.RetrieveAppointments(); this.RetrieveAppointments();
} }
/// <summary>
/// Retrieve all appointments for the current configurations
/// </summary>
public void RetrieveAppointments() public void RetrieveAppointments()
{ {
// Get the Outlook folder for the calendar to retrieve the appointments // Get the Outlook folder for the calendar to retrieve the appointments
@ -123,20 +157,15 @@ namespace Outlook2013TodoAddIn
case Outlook.OlBusyStatus.olBusy: case Outlook.OlBusyStatus.olBusy:
current.ForeColor = Color.Purple; current.ForeColor = Color.Purple;
break; break;
case Outlook.OlBusyStatus.olFree: case Outlook.OlBusyStatus.olFree:
break; break;
case Outlook.OlBusyStatus.olOutOfOffice: case Outlook.OlBusyStatus.olOutOfOffice:
current.ForeColor = Color.Brown; current.ForeColor = Color.Brown;
break; break;
case Outlook.OlBusyStatus.olTentative: case Outlook.OlBusyStatus.olTentative:
break; break;
case Outlook.OlBusyStatus.olWorkingElsewhere: case Outlook.OlBusyStatus.olWorkingElsewhere:
break; break;
default: default:
break; break;
} }
@ -159,11 +188,11 @@ namespace Outlook2013TodoAddIn
} }
/// <summary> /// <summary>
/// Get recurring appointments in date range. /// Get recurring appointments in a date range.
/// </summary> /// </summary>
/// <param name="folder"></param> /// <param name="folder">Outlook folder</param>
/// <param name="startTime"></param> /// <param name="startTime">Start time</param>
/// <param name="endTime"></param> /// <param name="endTime">End time</param>
/// <returns>Outlook.Items</returns> /// <returns>Outlook.Items</returns>
private Outlook.Items GetAppointmentsInRange(Outlook.Folder folder, DateTime startTime, DateTime endTime) private Outlook.Items GetAppointmentsInRange(Outlook.Folder folder, DateTime startTime, DateTime endTime)
{ {
@ -190,6 +219,11 @@ namespace Outlook2013TodoAddIn
catch { return null; } catch { return null; }
} }
/// <summary>
/// Open the appointment, having in mind it might be a recurring event
/// </summary>
/// <param name="sender">Sender</param>
/// <param name="e">EventArgs</param>
private void listView1_DoubleClick(object sender, EventArgs e) private void listView1_DoubleClick(object sender, EventArgs e)
{ {
if (this.listView1.SelectedIndices.Count != 0) if (this.listView1.SelectedIndices.Count != 0)
@ -222,13 +256,17 @@ namespace Outlook2013TodoAddIn
// Open up the appointment in a new window // Open up the appointment in a new window
appt.Display(true); // Modal yes/no appt.Display(true); // Modal yes/no
} }
// At the end, synchronously "refresh" items in case they have changed // At the end, synchronously "refresh" items in case they have changed
this.RetrieveAppointments(); this.RetrieveAppointments();
} }
} }
} }
/// <summary>
/// Creates a new mail item to reply all recipients of an appointment (except the current user)
/// </summary>
/// <param name="sender">Sender</param>
/// <param name="e">EventArgs</param>
private void mnuItemReplyAllEmail_Click(object sender, EventArgs e) private void mnuItemReplyAllEmail_Click(object sender, EventArgs e)
{ {
if (this.listView1.SelectedIndices.Count != 0) if (this.listView1.SelectedIndices.Count != 0)
@ -237,7 +275,6 @@ namespace Outlook2013TodoAddIn
if (appt != null) if (appt != null)
{ {
Outlook.MailItem mail = Globals.ThisAddIn.Application.CreateItem(Outlook.OlItemType.olMailItem) as Outlook.MailItem; Outlook.MailItem mail = Globals.ThisAddIn.Application.CreateItem(Outlook.OlItemType.olMailItem) as Outlook.MailItem;
string curUserAddress = GetEmailAddress(Globals.ThisAddIn.Application.Session.CurrentUser); string curUserAddress = GetEmailAddress(Globals.ThisAddIn.Application.Session.CurrentUser);
foreach (Outlook.Recipient rcpt in appt.Recipients) foreach (Outlook.Recipient rcpt in appt.Recipients)
{ {
@ -245,8 +282,6 @@ namespace Outlook2013TodoAddIn
if (curUserAddress != smtpAddress) if (curUserAddress != smtpAddress)
{ {
mail.Recipients.Add(smtpAddress); mail.Recipients.Add(smtpAddress);
//mail.Recipients.Add(rcpt.AddressEntry.Name);
} }
} }
mail.Body = Environment.NewLine + Environment.NewLine + appt.Body; mail.Body = Environment.NewLine + Environment.NewLine + appt.Body;
@ -256,10 +291,44 @@ namespace Outlook2013TodoAddIn
} }
} }
/// <summary>
/// Resolves Outlook recipient email address
/// </summary>
/// <param name="rcpt">Recipient</param>
/// <returns>Email address of the contact</returns>
private string GetEmailAddress(Outlook.Recipient rcpt) private string GetEmailAddress(Outlook.Recipient rcpt)
{ {
Outlook.PropertyAccessor pa = rcpt.PropertyAccessor; Outlook.PropertyAccessor pa = rcpt.PropertyAccessor;
return pa.GetProperty(PR_SMTP_ADDRESS).ToString(); return pa.GetProperty(PR_SMTP_ADDRESS).ToString();
} }
/// <summary>
/// Switch to the calendar view when double-clicking a date
/// </summary>
/// <param name="sender">Sender</param>
/// <param name="e">EventArgs</param>
private void apptCalendar_DoubleClickEx(object sender, EventArgs e)
{
// TODO: Clicking in days outside of the current month will cause the calendar to refresh to that day, reposition all days and
// select the wrong one
//MessageBox.Show(this.apptCalendar.SelectionStart.ToShortDateString());
// Get the Outlook folder for the calendar to retrieve the appointments
Outlook.Folder calFolder =
Globals.ThisAddIn.Application.Session.GetDefaultFolder(
Outlook.OlDefaultFolders.olFolderCalendar)
as Outlook.Folder;
//Outlook.View view = Globals.ThisAddIn.Application.ActiveExplorer().CurrentView;
foreach (Outlook.View view in Globals.ThisAddIn.Application.ActiveExplorer().CurrentFolder.Views)
{
MessageBox.Show("New view: {0}", view.Name);
}
//calFolder.Display();
}
#endregion "Methods"
} }
} }

View File

@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Outlook2013TodoAddIn
{
public class DoubleClickMonthCalendar : MonthCalendar
{
public event EventHandler DoubleClickEx;
public DoubleClickMonthCalendar()
{
lastClickTick = Environment.TickCount - SystemInformation.DoubleClickTime;
}
protected override void OnMouseDown(MouseEventArgs e)
{
int tick = Environment.TickCount;
if (tick - lastClickTick <= SystemInformation.DoubleClickTime)
{
EventHandler handler = DoubleClickEx;
if (handler != null) handler(this, EventArgs.Empty);
}
else
{
base.OnMouseDown(e);
lastClickTick = tick;
}
}
private int lastClickTick;
}
}

View File

@ -2,21 +2,33 @@
namespace Outlook2013TodoAddIn namespace Outlook2013TodoAddIn
{ {
/// <summary>
/// Mimic Outlook's popup to open one instance or the whole series
/// </summary>
public partial class FormRecurringOpen : Form public partial class FormRecurringOpen : Form
{ {
public DialogResult ButtonPressed { get; set; } #region "Properties"
/// <summary>
/// Whether the user wants to retrieve all instances or not
/// </summary>
public bool OpenRecurring public bool OpenRecurring
{ {
get get { return this.rbtnAll.Checked; }
{
return this.rbtnAll.Checked;
}
} }
#endregion "Properties"
#region "Methods"
/// <summary>
/// Open the form
/// </summary>
public FormRecurringOpen() public FormRecurringOpen()
{ {
InitializeComponent(); InitializeComponent();
} }
#endregion "Methods"
} }
} }

View File

@ -178,6 +178,7 @@
can be found. can be found.
--> -->
<ItemGroup> <ItemGroup>
<Compile Include="DoubleClickMonthCalendar.cs" />
<Compile Include="FormRecurringOpen.cs"> <Compile Include="FormRecurringOpen.cs">
<SubType>Form</SubType> <SubType>Form</SubType>
</Compile> </Compile>

View File

@ -5,69 +5,69 @@ using Office = Microsoft.Office.Core;
namespace Outlook2013TodoAddIn namespace Outlook2013TodoAddIn
{ {
/// <summary>
/// Class for the add-in
/// </summary>
public partial class ThisAddIn public partial class ThisAddIn
{ {
private AppointmentsControl appControl; #region "Properties"
/// <summary>
/// Control with calendar, etc...
/// </summary>
public AppointmentsControl AppControl { get; set; }
/// <summary>
/// Custom task pane
/// </summary>
public Microsoft.Office.Tools.CustomTaskPane ToDoTaskPane { get; set; } public Microsoft.Office.Tools.CustomTaskPane ToDoTaskPane { get; set; }
//private Dictionary<Outlook.Inspector, InspectorWrapper> inspectorWrappersValue = new Dictionary<Outlook.Inspector, InspectorWrapper>(); #endregion "Properties"
//private Outlook.Inspectors inspectors;
//void Inspectors_NewInspector(Outlook.Inspector Inspector) #region "Methods"
//{
// if (Inspector.CurrentItem is Outlook.MailItem)
// {
// inspectorWrappersValue.Add(Inspector, new InspectorWrapper(Inspector));
// }
//}
//public Dictionary<Outlook.Inspector, InspectorWrapper> InspectorWrappers
//{
// get
// {
// return inspectorWrappersValue;
// }
//}
/// <summary>
/// Initialize settings upon add-in startup
/// </summary>
/// <param name="sender">Sender</param>
/// <param name="e">EventArgs</param>
private void ThisAddIn_Startup(object sender, System.EventArgs e) private void ThisAddIn_Startup(object sender, System.EventArgs e)
{ {
//inspectors = this.Application.Inspectors; this.AddRegistryNotification();
//inspectors.NewInspector +=
// new Outlook.InspectorsEvents_NewInspectorEventHandler(
// Inspectors_NewInspector);
//foreach (Outlook.Inspector inspector in inspectors) this.AppControl = new AppointmentsControl();
//{ this.AppControl.NumDays = Properties.Settings.Default.NumDays; // Setting the value will load the appointments
// Inspectors_NewInspector(inspector); this.AppControl.RetrieveAppointments();
//}
appControl = new AppointmentsControl(); ToDoTaskPane = this.CustomTaskPanes.Add(this.AppControl, "Appointments");
appControl.NumDays = Properties.Settings.Default.NumDays; // Setting the value will load the appointments // TODO: Fix this
// ToDoTaskPane.Visible = Properties.Settings.Default.Visible;
//Properties.Settings.Default.Properties[] ToDoTaskPane.Visible = true;
// appControl.Dock = System.Windows.Forms.DockStyle.Right;
ToDoTaskPane = this.CustomTaskPanes.Add(appControl, "Appointments");
ToDoTaskPane.Visible = Properties.Settings.Default.Visible;
//ToDoTaskPane.Visible = true;
//ToDoTaskPane.Width = 285; // appControl.Width;
ToDoTaskPane.Width = Properties.Settings.Default.Width; ToDoTaskPane.Width = Properties.Settings.Default.Width;
ToDoTaskPane.DockPosition = Office.MsoCTPDockPosition.msoCTPDockPositionRight; ToDoTaskPane.DockPosition = Office.MsoCTPDockPosition.msoCTPDockPositionRight;
ToDoTaskPane.DockPositionRestrict = Office.MsoCTPDockPositionRestrict.msoCTPDockPositionRestrictNoHorizontal; ToDoTaskPane.DockPositionRestrict = Office.MsoCTPDockPositionRestrict.msoCTPDockPositionRestrictNoHorizontal;
ToDoTaskPane.VisibleChanged += ToDoTaskPane_VisibleChanged; ToDoTaskPane.VisibleChanged += ToDoTaskPane_VisibleChanged;
appControl.SizeChanged += appControl_SizeChanged; this.AppControl.SizeChanged += appControl_SizeChanged;
this.AddRegistryNotification();
} }
/// <summary>
/// Store the new size setting upon resizing
/// </summary>
/// <param name="sender">Sender</param>
/// <param name="e">EventArgs</param>
private void appControl_SizeChanged(object sender, EventArgs e) private void appControl_SizeChanged(object sender, EventArgs e)
{ {
Properties.Settings.Default.Width = ToDoTaskPane.Width; Properties.Settings.Default.Width = ToDoTaskPane.Width;
} }
/// <summary>
/// Toggle ribbon button's status
/// </summary>
/// <param name="sender">Sender</param>
/// <param name="e">EventArgs</param>
private void ToDoTaskPane_VisibleChanged(object sender, EventArgs e) private void ToDoTaskPane_VisibleChanged(object sender, EventArgs e)
{ {
// TODO: Save visibility ONLY when not closing the form
// Properties.Settings.Default.Visible = ToDoTaskPane.Visible; // Properties.Settings.Default.Visible = ToDoTaskPane.Visible;
TodoRibbonAddIn rbn = Globals.Ribbons.FirstOrDefault(r => r is TodoRibbonAddIn) as TodoRibbonAddIn; TodoRibbonAddIn rbn = Globals.Ribbons.FirstOrDefault(r => r is TodoRibbonAddIn) as TodoRibbonAddIn;
if (rbn != null) if (rbn != null)
@ -77,45 +77,42 @@ namespace Outlook2013TodoAddIn
} }
/// <summary> /// <summary>
/// This is NEVER executed anymore /// This is not executed by default
/// http://msdn.microsoft.com/en-us/library/office/ee720183.aspx#OL2010AdditionalShutdownChanges_AddinShutdownChangesinOL2010Beta /// http://msdn.microsoft.com/en-us/library/office/ee720183.aspx#OL2010AdditionalShutdownChanges_AddinShutdownChangesinOL2010Beta
/// We MANUALLY add notification to the registry of each user /// We MANUALLY add notification to the registry of each user below
/// </summary> /// </summary>
/// <param name="sender"></param> /// <param name="sender">Sender</param>
/// <param name="e"></param> /// <param name="e">EventArgs</param>
private void ThisAddIn_Shutdown(object sender, System.EventArgs e) private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
{ {
//inspectors.NewInspector -= // Can't call property setters such as: Properties.Settings.Default.NumDays = XXX because the pane is already disposed.
// new Outlook.InspectorsEvents_NewInspectorEventHandler( // Settings will be set while the app is running and saved here.
// Inspectors_NewInspector);
//inspectors = null;
//inspectorWrappersValue = null;
// Can't call these because the object is already disposed. Settings will be set while the app is running
//Properties.Settings.Default.Visible = ToDoTaskPane.Visible;
//Properties.Settings.Default.Width = ToDoTaskPane.Width;
//Properties.Settings.Default.NumDays = appControl.NumDays;
Properties.Settings.Default.Save(); Properties.Settings.Default.Save();
} }
/// <summary>
/// Implement shutdown notification for this particular add-in
/// http://msdn.microsoft.com/en-us/library/office/ee720183.aspx#OL2010AdditionalShutdownChanges_AddinShutdownChangesinOL2010Beta
/// HKEY_CURRENT_USER\Software\Microsoft\Office\Outlook\Addins\<ProgID>\[RequireShutdownNotification]=dword:0x1
/// </summary>
private void AddRegistryNotification() private void AddRegistryNotification()
{ {
// http://msdn.microsoft.com/en-us/library/office/ee720183.aspx#OL2010AdditionalShutdownChanges_AddinShutdownChangesinOL2010Beta // TODO: Make sure there are no memory leaks (dispose COM obejcts)
// HKEY_CURRENT_USER\Software\Microsoft\Office\Outlook\Addins\<ProgID>\[RequireShutdownNotification]=dword:0x1 // TODO: See if this works the first time (if the entry is not there when Outlook loads, it will NOT notify the add-in)
string subKey = @"Software\Microsoft\Office\Outlook\Addins\Outlook2013TodoAddIn"; string subKey = @"Software\Microsoft\Office\Outlook\Addins\Outlook2013TodoAddIn";
RegistryKey rk = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(subKey, true); RegistryKey rk = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(subKey, true);
if (rk == null) if (rk == null)
{ {
rk = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(subKey); rk = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(subKey);
} }
if ((int)rk.GetValue("RequireShutdownNotification", 0) == 0) if ((int)rk.GetValue("RequireShutdownNotification", 0) == 0)
{ {
rk.SetValue("RequireShutdownNotification", 1, RegistryValueKind.DWord); // "dword:0x1" rk.SetValue("RequireShutdownNotification", 1, RegistryValueKind.DWord); // "dword:0x1"
} }
} }
#endregion "Methods"
#region VSTO generated code #region VSTO generated code
/// <summary> /// <summary>

View File

@ -67,7 +67,6 @@
this.Name = "TodoRibbonAddIn"; this.Name = "TodoRibbonAddIn";
this.RibbonType = "Microsoft.Outlook.Explorer"; this.RibbonType = "Microsoft.Outlook.Explorer";
this.Tabs.Add(this.tab1); this.Tabs.Add(this.tab1);
this.Load += new Microsoft.Office.Tools.Ribbon.RibbonUIEventHandler(this.TodoRibbonAddIn_Load);
this.tab1.ResumeLayout(false); this.tab1.ResumeLayout(false);
this.tab1.PerformLayout(); this.tab1.PerformLayout();
this.group1.ResumeLayout(false); this.group1.ResumeLayout(false);

View File

@ -2,15 +2,23 @@
namespace Outlook2013TodoAddIn namespace Outlook2013TodoAddIn
{ {
/// <summary>
/// Adds a button to the add-in placeholder in the ribbon
/// </summary>
public partial class TodoRibbonAddIn public partial class TodoRibbonAddIn
{ {
private void TodoRibbonAddIn_Load(object sender, RibbonUIEventArgs e) #region "Methods"
{
}
/// <summary>
/// Change visibility of the pane
/// </summary>
/// <param name="sender">Sender</param>
/// <param name="e">RibbonControlEventArgs</param>
private void toggleButton1_Click(object sender, RibbonControlEventArgs e) private void toggleButton1_Click(object sender, RibbonControlEventArgs e)
{ {
Globals.ThisAddIn.ToDoTaskPane.Visible = this.toggleButton1.Checked; Globals.ThisAddIn.ToDoTaskPane.Visible = this.toggleButton1.Checked;
} }
#endregion
} }
} }