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.numRangeDays = new System.Windows.Forms.NumericUpDown();
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.mnuItemReplyAllEmail = new System.Windows.Forms.ToolStripMenuItem();
this.hdrDate = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
@ -86,6 +86,7 @@
this.apptCalendar.MaxSelectionCount = 1;
this.apptCalendar.Name = "apptCalendar";
this.apptCalendar.TabIndex = 4;
this.apptCalendar.DoubleClickEx += new System.EventHandler(this.apptCalendar_DoubleClickEx);
this.apptCalendar.DateChanged += new System.Windows.Forms.DateRangeEventHandler(this.monthCalendar1_DateChanged);
//
// ctxMenuAppointments
@ -186,7 +187,7 @@
private System.Windows.Forms.NumericUpDown numRangeDays;
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.ToolStripMenuItem mnuItemReplyAllEmail;
private System.Windows.Forms.ColumnHeader hdrDate;

View File

@ -7,22 +7,38 @@ using Outlook = Microsoft.Office.Interop.Outlook;
namespace Outlook2013TodoAddIn
{
/// User control to hold the calendar, etc...
/// </summary>
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";
#endregion "Variables"
#region "Properties"
/// <summary>
/// Number of days (including today) to retrieve appointments from in the future
/// </summary>
public decimal NumDays
{
get
{
return this.numRangeDays.Value;
}
set
{
this.numRangeDays.Value = value;
}
get { return this.numRangeDays.Value; }
set { this.numRangeDays.Value = value; }
}
#endregion "Properties"
#region "Methods"
/// <summary>
/// Default constructor
/// </summary>
public AppointmentsControl()
{
InitializeComponent();
@ -43,22 +59,40 @@ namespace Outlook2013TodoAddIn
// 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)
{
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)
{
Properties.Settings.Default.NumDays = this.numRangeDays.Value;
this.RetrieveAppointments();
}
/// <summary>
/// Manual refresh
/// </summary>
/// <param name="sender">Sender</param>
/// <param name="e">EventArgs</param>
private void btnRefresh_Click(object sender, EventArgs e)
{
this.RetrieveAppointments();
}
/// <summary>
/// Retrieve all appointments for the current configurations
/// </summary>
public void RetrieveAppointments()
{
// Get the Outlook folder for the calendar to retrieve the appointments
@ -123,20 +157,15 @@ namespace Outlook2013TodoAddIn
case Outlook.OlBusyStatus.olBusy:
current.ForeColor = Color.Purple;
break;
case Outlook.OlBusyStatus.olFree:
break;
case Outlook.OlBusyStatus.olOutOfOffice:
current.ForeColor = Color.Brown;
break;
case Outlook.OlBusyStatus.olTentative:
break;
case Outlook.OlBusyStatus.olWorkingElsewhere:
break;
default:
break;
}
@ -159,11 +188,11 @@ namespace Outlook2013TodoAddIn
}
/// <summary>
/// Get recurring appointments in date range.
/// Get recurring appointments in a date range.
/// </summary>
/// <param name="folder"></param>
/// <param name="startTime"></param>
/// <param name="endTime"></param>
/// <param name="folder">Outlook folder</param>
/// <param name="startTime">Start time</param>
/// <param name="endTime">End time</param>
/// <returns>Outlook.Items</returns>
private Outlook.Items GetAppointmentsInRange(Outlook.Folder folder, DateTime startTime, DateTime endTime)
{
@ -190,6 +219,11 @@ namespace Outlook2013TodoAddIn
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)
{
if (this.listView1.SelectedIndices.Count != 0)
@ -222,13 +256,17 @@ namespace Outlook2013TodoAddIn
// Open up the appointment in a new window
appt.Display(true); // Modal yes/no
}
// At the end, synchronously "refresh" items in case they have changed
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)
{
if (this.listView1.SelectedIndices.Count != 0)
@ -237,7 +275,6 @@ namespace Outlook2013TodoAddIn
if (appt != null)
{
Outlook.MailItem mail = Globals.ThisAddIn.Application.CreateItem(Outlook.OlItemType.olMailItem) as Outlook.MailItem;
string curUserAddress = GetEmailAddress(Globals.ThisAddIn.Application.Session.CurrentUser);
foreach (Outlook.Recipient rcpt in appt.Recipients)
{
@ -245,8 +282,6 @@ namespace Outlook2013TodoAddIn
if (curUserAddress != smtpAddress)
{
mail.Recipients.Add(smtpAddress);
//mail.Recipients.Add(rcpt.AddressEntry.Name);
}
}
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)
{
Outlook.PropertyAccessor pa = rcpt.PropertyAccessor;
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
{
/// <summary>
/// Mimic Outlook's popup to open one instance or the whole series
/// </summary>
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
{
get
{
return this.rbtnAll.Checked;
}
get { return this.rbtnAll.Checked; }
}
#endregion "Properties"
#region "Methods"
/// <summary>
/// Open the form
/// </summary>
public FormRecurringOpen()
{
InitializeComponent();
}
#endregion "Methods"
}
}

View File

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

View File

@ -5,69 +5,69 @@ using Office = Microsoft.Office.Core;
namespace Outlook2013TodoAddIn
{
/// <summary>
/// Class for the add-in
/// </summary>
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; }
//private Dictionary<Outlook.Inspector, InspectorWrapper> inspectorWrappersValue = new Dictionary<Outlook.Inspector, InspectorWrapper>();
//private Outlook.Inspectors inspectors;
#endregion "Properties"
//void Inspectors_NewInspector(Outlook.Inspector Inspector)
//{
// if (Inspector.CurrentItem is Outlook.MailItem)
// {
// inspectorWrappersValue.Add(Inspector, new InspectorWrapper(Inspector));
// }
//}
//public Dictionary<Outlook.Inspector, InspectorWrapper> InspectorWrappers
//{
// get
// {
// return inspectorWrappersValue;
// }
//}
#region "Methods"
/// <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)
{
//inspectors = this.Application.Inspectors;
//inspectors.NewInspector +=
// new Outlook.InspectorsEvents_NewInspectorEventHandler(
// Inspectors_NewInspector);
this.AddRegistryNotification();
//foreach (Outlook.Inspector inspector in inspectors)
//{
// Inspectors_NewInspector(inspector);
//}
this.AppControl = new AppointmentsControl();
this.AppControl.NumDays = Properties.Settings.Default.NumDays; // Setting the value will load the appointments
this.AppControl.RetrieveAppointments();
appControl = new AppointmentsControl();
appControl.NumDays = Properties.Settings.Default.NumDays; // Setting the value will load the appointments
//Properties.Settings.Default.Properties[]
// 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 = this.CustomTaskPanes.Add(this.AppControl, "Appointments");
// TODO: Fix this
// ToDoTaskPane.Visible = Properties.Settings.Default.Visible;
ToDoTaskPane.Visible = true;
ToDoTaskPane.Width = Properties.Settings.Default.Width;
ToDoTaskPane.DockPosition = Office.MsoCTPDockPosition.msoCTPDockPositionRight;
ToDoTaskPane.DockPositionRestrict = Office.MsoCTPDockPositionRestrict.msoCTPDockPositionRestrictNoHorizontal;
ToDoTaskPane.VisibleChanged += ToDoTaskPane_VisibleChanged;
appControl.SizeChanged += appControl_SizeChanged;
this.AddRegistryNotification();
this.AppControl.SizeChanged += appControl_SizeChanged;
}
/// <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)
{
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)
{
// TODO: Save visibility ONLY when not closing the form
// Properties.Settings.Default.Visible = ToDoTaskPane.Visible;
TodoRibbonAddIn rbn = Globals.Ribbons.FirstOrDefault(r => r is TodoRibbonAddIn) as TodoRibbonAddIn;
if (rbn != null)
@ -77,45 +77,42 @@ namespace Outlook2013TodoAddIn
}
/// <summary>
/// This is NEVER executed anymore
/// This is not executed by default
/// 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>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <param name="sender">Sender</param>
/// <param name="e">EventArgs</param>
private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
{
//inspectors.NewInspector -=
// new Outlook.InspectorsEvents_NewInspectorEventHandler(
// 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;
// Can't call property setters such as: Properties.Settings.Default.NumDays = XXX because the pane is already disposed.
// Settings will be set while the app is running and saved here.
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()
{
// http://msdn.microsoft.com/en-us/library/office/ee720183.aspx#OL2010AdditionalShutdownChanges_AddinShutdownChangesinOL2010Beta
// HKEY_CURRENT_USER\Software\Microsoft\Office\Outlook\Addins\<ProgID>\[RequireShutdownNotification]=dword:0x1
// TODO: Make sure there are no memory leaks (dispose COM obejcts)
// 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";
RegistryKey rk = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(subKey, true);
if (rk == null)
{
rk = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(subKey);
}
if ((int)rk.GetValue("RequireShutdownNotification", 0) == 0)
{
rk.SetValue("RequireShutdownNotification", 1, RegistryValueKind.DWord); // "dword:0x1"
}
}
#endregion "Methods"
#region VSTO generated code
/// <summary>

View File

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

View File

@ -2,15 +2,23 @@
namespace Outlook2013TodoAddIn
{
/// <summary>
/// Adds a button to the add-in placeholder in the ribbon
/// </summary>
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)
{
Globals.ThisAddIn.ToDoTaskPane.Visible = this.toggleButton1.Checked;
}
#endregion
}
}