diff --git a/src/OutlookGoogleCalendarSync/Forms/MainForm.Designer.cs b/src/OutlookGoogleCalendarSync/Forms/MainForm.Designer.cs index 18c44f37..38349836 100644 --- a/src/OutlookGoogleCalendarSync/Forms/MainForm.Designer.cs +++ b/src/OutlookGoogleCalendarSync/Forms/MainForm.Designer.cs @@ -115,6 +115,15 @@ private void InitializeComponent() { this.lClientID = new System.Windows.Forms.Label(); this.lSecret = new System.Windows.Forms.Label(); this.gbGoogle_GConfig = new System.Windows.Forms.GroupBox(); + this.cbDeleteWhenColourExcl = new System.Windows.Forms.CheckBox(); + this.label35 = new System.Windows.Forms.Label(); + this.cbColourFilter = new System.Windows.Forms.ComboBox(); + this.clbColours = new System.Windows.Forms.CheckedListBox(); + this.msColours = new System.Windows.Forms.ContextMenuStrip(this.components); + this.miColourSelectAll = new System.Windows.Forms.ToolStripMenuItem(); + this.miColourSelectNone = new System.Windows.Forms.ToolStripMenuItem(); + this.miColourSelectInvert = new System.Windows.Forms.ToolStripMenuItem(); + this.miColourRefresh = new System.Windows.Forms.ToolStripMenuItem(); this.cbExcludeDeclinedInvites = new System.Windows.Forms.CheckBox(); this.cbExcludeGoals = new System.Windows.Forms.CheckBox(); this.gbGoogle_Account = new System.Windows.Forms.GroupBox(); @@ -317,6 +326,7 @@ private void InitializeComponent() { ((System.ComponentModel.ISupportInitialize)(this.pbExpandGoogleAccount)).BeginInit(); this.gbGoogle_OAuth.SuspendLayout(); this.gbGoogle_GConfig.SuspendLayout(); + this.msColours.SuspendLayout(); this.gbGoogle_Account.SuspendLayout(); this.tabSyncOptions.SuspendLayout(); this.WhatPostit.SuspendLayout(); @@ -770,7 +780,7 @@ private void InitializeComponent() { this.msCategories.Name = "msCategories"; this.msCategories.ShowImageMargin = false; this.msCategories.ShowItemToolTips = false; - this.msCategories.Size = new System.Drawing.Size(148, 70); + this.msCategories.Size = new System.Drawing.Size(148, 92); // // miCatSelectAll // @@ -1087,7 +1097,7 @@ private void InitializeComponent() { // this.pbExpandGoogleOauth.Cursor = System.Windows.Forms.Cursors.Hand; this.pbExpandGoogleOauth.Image = global::OutlookGoogleCalendarSync.Properties.Resources.expand; - this.pbExpandGoogleOauth.Location = new System.Drawing.Point(1, 336); + this.pbExpandGoogleOauth.Location = new System.Drawing.Point(1, 394); this.pbExpandGoogleOauth.Name = "pbExpandGoogleOauth"; this.pbExpandGoogleOauth.Size = new System.Drawing.Size(20, 20); this.pbExpandGoogleOauth.TabIndex = 50; @@ -1098,7 +1108,7 @@ private void InitializeComponent() { // cbShowDeveloperOptions // this.cbShowDeveloperOptions.AutoSize = true; - this.cbShowDeveloperOptions.Location = new System.Drawing.Point(23, 316); + this.cbShowDeveloperOptions.Location = new System.Drawing.Point(23, 374); this.cbShowDeveloperOptions.Name = "cbShowDeveloperOptions"; this.cbShowDeveloperOptions.Size = new System.Drawing.Size(193, 17); this.cbShowDeveloperOptions.TabIndex = 48; @@ -1141,7 +1151,7 @@ private void InitializeComponent() { this.gbGoogle_OAuth.Controls.Add(this.lSecret); this.gbGoogle_OAuth.Font = new System.Drawing.Font("Arial Black", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.gbGoogle_OAuth.ForeColor = System.Drawing.SystemColors.MenuHighlight; - this.gbGoogle_OAuth.Location = new System.Drawing.Point(10, 339); + this.gbGoogle_OAuth.Location = new System.Drawing.Point(10, 397); this.gbGoogle_OAuth.MinimumSize = new System.Drawing.Size(368, 0); this.gbGoogle_OAuth.Name = "gbGoogle_OAuth"; this.gbGoogle_OAuth.Size = new System.Drawing.Size(368, 174); @@ -1247,6 +1257,10 @@ private void InitializeComponent() { // this.gbGoogle_GConfig.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); + this.gbGoogle_GConfig.Controls.Add(this.cbDeleteWhenColourExcl); + this.gbGoogle_GConfig.Controls.Add(this.label35); + this.gbGoogle_GConfig.Controls.Add(this.cbColourFilter); + this.gbGoogle_GConfig.Controls.Add(this.clbColours); this.gbGoogle_GConfig.Controls.Add(this.cbExcludeDeclinedInvites); this.gbGoogle_GConfig.Controls.Add(this.cbExcludeGoals); this.gbGoogle_GConfig.Font = new System.Drawing.Font("Arial Black", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); @@ -1254,17 +1268,117 @@ private void InitializeComponent() { this.gbGoogle_GConfig.Location = new System.Drawing.Point(10, 246); this.gbGoogle_GConfig.MinimumSize = new System.Drawing.Size(368, 0); this.gbGoogle_GConfig.Name = "gbGoogle_GConfig"; - this.gbGoogle_GConfig.Size = new System.Drawing.Size(368, 64); + this.gbGoogle_GConfig.Size = new System.Drawing.Size(368, 122); this.gbGoogle_GConfig.TabIndex = 45; this.gbGoogle_GConfig.TabStop = false; this.gbGoogle_GConfig.Text = " Sync Configuration"; // + // cbDeleteWhenColourExcl + // + this.cbDeleteWhenColourExcl.AutoSize = true; + this.cbDeleteWhenColourExcl.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.cbDeleteWhenColourExcl.ForeColor = System.Drawing.SystemColors.ControlText; + this.cbDeleteWhenColourExcl.Location = new System.Drawing.Point(13, 48); + this.cbDeleteWhenColourExcl.Name = "cbDeleteWhenColourExcl"; + this.cbDeleteWhenColourExcl.Size = new System.Drawing.Size(175, 17); + this.cbDeleteWhenColourExcl.TabIndex = 53; + this.cbDeleteWhenColourExcl.Text = "Delete synced items if excluded"; + this.cbDeleteWhenColourExcl.UseVisualStyleBackColor = true; + this.cbDeleteWhenColourExcl.CheckedChanged += new System.EventHandler(this.cbDeleteWhenColourExcl_CheckedChanged); + // + // label35 + // + this.label35.AutoSize = true; + this.label35.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label35.ForeColor = System.Drawing.SystemColors.ControlText; + this.label35.Location = new System.Drawing.Point(10, 26); + this.label35.Name = "label35"; + this.label35.Size = new System.Drawing.Size(66, 13); + this.label35.TabIndex = 52; + this.label35.Text = "Filter colours"; + // + // cbColourFilter + // + this.cbColourFilter.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbColourFilter.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.cbColourFilter.ForeColor = System.Drawing.SystemColors.ControlText; + this.cbColourFilter.FormattingEnabled = true; + this.cbColourFilter.Items.AddRange(new object[] { + "Exclude", + "Include"}); + this.cbColourFilter.Location = new System.Drawing.Point(82, 23); + this.cbColourFilter.Name = "cbColourFilter"; + this.cbColourFilter.Size = new System.Drawing.Size(114, 21); + this.cbColourFilter.TabIndex = 51; + this.cbColourFilter.SelectedIndexChanged += new System.EventHandler(this.cbColourFilter_SelectedIndexChanged); + // + // clbColours + // + this.clbColours.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.clbColours.CheckOnClick = true; + this.clbColours.ContextMenuStrip = this.msColours; + this.clbColours.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.clbColours.ForeColor = System.Drawing.SystemColors.ControlText; + this.clbColours.FormattingEnabled = true; + this.clbColours.Items.AddRange(new object[] { + "Blue", + "Green", + "Red"}); + this.clbColours.Location = new System.Drawing.Point(202, 23); + this.clbColours.Name = "clbColours"; + this.clbColours.Size = new System.Drawing.Size(157, 94); + this.clbColours.Sorted = true; + this.clbColours.TabIndex = 50; + this.clbColours.SelectedIndexChanged += new System.EventHandler(this.clbColours_SelectedIndexChanged); + // + // msColours + // + this.msColours.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.miColourSelectAll, + this.miColourSelectNone, + this.miColourSelectInvert, + this.miColourRefresh}); + this.msColours.Name = "msColours"; + this.msColours.ShowImageMargin = false; + this.msColours.ShowItemToolTips = false; + this.msColours.Size = new System.Drawing.Size(133, 92); + // + // miColourSelectAll + // + this.miColourSelectAll.Name = "miColourSelectAll"; + this.miColourSelectAll.Size = new System.Drawing.Size(132, 22); + this.miColourSelectAll.Text = "Select All"; + this.miColourSelectAll.Click += new System.EventHandler(this.miColourSelectAll_Click); + // + // miColourSelectNone + // + this.miColourSelectNone.Name = "miColourSelectNone"; + this.miColourSelectNone.Size = new System.Drawing.Size(132, 22); + this.miColourSelectNone.Text = "Select None"; + this.miColourSelectNone.Click += new System.EventHandler(this.miColourSelectNone_Click); + // + // miColourSelectInvert + // + this.miColourSelectInvert.Name = "miColourSelectInvert"; + this.miColourSelectInvert.Size = new System.Drawing.Size(132, 22); + this.miColourSelectInvert.Text = "Invert Selection"; + this.miColourSelectInvert.Click += new System.EventHandler(this.miColourSelectInvert_Click); + // + // miColourRefresh + // + this.miColourRefresh.Name = "miColourRefresh"; + this.miColourRefresh.Size = new System.Drawing.Size(132, 22); + this.miColourRefresh.Text = "Refresh Colours"; + this.miColourRefresh.Click += new System.EventHandler(this.miColourRefresh_Click); + // // cbExcludeDeclinedInvites // this.cbExcludeDeclinedInvites.AutoSize = true; this.cbExcludeDeclinedInvites.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.cbExcludeDeclinedInvites.ForeColor = System.Drawing.SystemColors.ControlText; - this.cbExcludeDeclinedInvites.Location = new System.Drawing.Point(13, 22); + this.cbExcludeDeclinedInvites.Location = new System.Drawing.Point(13, 71); this.cbExcludeDeclinedInvites.Name = "cbExcludeDeclinedInvites"; this.cbExcludeDeclinedInvites.Size = new System.Drawing.Size(190, 17); this.cbExcludeDeclinedInvites.TabIndex = 49; @@ -1277,7 +1391,7 @@ private void InitializeComponent() { this.cbExcludeGoals.AutoSize = true; this.cbExcludeGoals.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.cbExcludeGoals.ForeColor = System.Drawing.SystemColors.ControlText; - this.cbExcludeGoals.Location = new System.Drawing.Point(13, 41); + this.cbExcludeGoals.Location = new System.Drawing.Point(13, 90); this.cbExcludeGoals.Name = "cbExcludeGoals"; this.cbExcludeGoals.Size = new System.Drawing.Size(182, 17); this.cbExcludeGoals.TabIndex = 48; @@ -3734,6 +3848,7 @@ private void InitializeComponent() { this.gbGoogle_OAuth.PerformLayout(); this.gbGoogle_GConfig.ResumeLayout(false); this.gbGoogle_GConfig.PerformLayout(); + this.msColours.ResumeLayout(false); this.gbGoogle_Account.ResumeLayout(false); this.gbGoogle_Account.PerformLayout(); this.tabSyncOptions.ResumeLayout(false); @@ -3899,6 +4014,11 @@ private void InitializeComponent() { private System.Windows.Forms.ToolStripMenuItem miCatSelectNone; private System.Windows.Forms.ToolStripMenuItem miCatSelectInvert; private System.Windows.Forms.ToolStripMenuItem miCatRefresh; + private System.Windows.Forms.ContextMenuStrip msColours; + private System.Windows.Forms.ToolStripMenuItem miColourSelectAll; + private System.Windows.Forms.ToolStripMenuItem miColourSelectNone; + private System.Windows.Forms.ToolStripMenuItem miColourSelectInvert; + private System.Windows.Forms.ToolStripMenuItem miColourRefresh; private System.Windows.Forms.ContextMenuStrip msProfileActions; private System.Windows.Forms.ToolStripMenuItem miAddProfile; private System.Windows.Forms.ToolStripMenuItem miDeleteProfile; @@ -4037,5 +4157,9 @@ private void InitializeComponent() { private System.Windows.Forms.Label lClientID; private System.Windows.Forms.Label lSecret; private System.Windows.Forms.CheckBox cbShowDeveloperOptions; + private System.Windows.Forms.Label label35; + public System.Windows.Forms.ComboBox cbColourFilter; + public System.Windows.Forms.CheckedListBox clbColours; + private System.Windows.Forms.CheckBox cbDeleteWhenColourExcl; } } diff --git a/src/OutlookGoogleCalendarSync/Forms/MainForm.cs b/src/OutlookGoogleCalendarSync/Forms/MainForm.cs index 7f741af6..214343e0 100644 --- a/src/OutlookGoogleCalendarSync/Forms/MainForm.cs +++ b/src/OutlookGoogleCalendarSync/Forms/MainForm.cs @@ -93,6 +93,8 @@ private void updateGUIsettings() { "Disconnect the Google account being used to synchonize with."); ToolTips.SetToolTip(cbListHiddenGcals, "Include hidden calendars in the above drop down."); + ToolTips.SetToolTip(cbDeleteWhenColourExcl, + "If items are already synced in Outlook and subsequently excluded by a colour filter."); //Settings ToolTips.SetToolTip(tbInterval, @@ -167,11 +169,6 @@ private void updateGUIsettings() { cbMuteClicks.Checked = Settings.Instance.MuteClickSounds; #endregion UpdateGUIsettings_Profile(); - #region Google - groupboxSizing(gbGoogle_Account, pbExpandGoogleAccount, true); - groupboxSizing(gbGoogle_GConfig, pbExpandGoogleConfig, true); - groupboxSizing(gbGoogle_OAuth, pbExpandGoogleOauth, false); - #endregion #region Application behaviour groupboxSizing(gbAppBehaviour_Logging, pbExpandLogging, true); groupboxSizing(gbAppBehaviour_Proxy, pbExpandProxy, false); @@ -270,7 +267,7 @@ public void UpdateGUIsettings_Profile() { LastSyncVal = profile.LastSyncDateText; NextSyncVal = profile.OgcsTimer?.NextSyncDateText; #endregion - #region Outlook box + #region Outlook page #region Mailbox if (OutlookOgcs.Factory.OutlookVersionName == OutlookOgcs.Factory.OutlookVersionNames.Outlook2003) { rbOutlookDefaultMB.Checked = true; @@ -414,7 +411,11 @@ public void UpdateGUIsettings_Profile() { } #endregion #endregion - #region Google box + #region Google page + groupboxSizing(gbGoogle_Account, pbExpandGoogleAccount, true); + groupboxSizing(gbGoogle_GConfig, pbExpandGoogleConfig, true); + groupboxSizing(gbGoogle_OAuth, pbExpandGoogleOauth, false); + tbConnectedAcc.Text = string.IsNullOrEmpty(Settings.Instance.GaccountEmail) ? "Not connected" : Settings.Instance.GaccountEmail; if (profile.UseGoogleCalendar?.Id != null) { foreach (GoogleCalendarListEntry cle in this.cbGoogleCalendars.Items) { @@ -434,6 +435,9 @@ public void UpdateGUIsettings_Profile() { tbClientSecret.ReadOnly = false; } + cbColourFilter.SelectedItem = profile.ColoursRestrictBy == SettingsStore.Calendar.RestrictBy.Include ? "Include" : "Exclude"; + GoogleOgcs.Calendar.BuildOfflineColourPicker(clbColours); + cbDeleteWhenColourExcl.Checked = profile.DeleteWhenColourExcluded; cbExcludeDeclinedInvites.Checked = profile.ExcludeDeclinedInvites; cbExcludeGoals.Checked = profile.ExcludeGoals; cbExcludeGoals.Enabled = GoogleOgcs.Calendar.IsDefaultCalendar() ?? true; @@ -444,7 +448,7 @@ public void UpdateGUIsettings_Profile() { tbClientSecret.Text = Settings.Instance.PersonalClientSecret; } #endregion - #region Sync Options box + #region Sync Options page groupboxSizing(gbSyncOptions_How, pbExpandHow, true); groupboxSizing(gbSyncOptions_When, pbExpandWhen, false); groupboxSizing(gbSyncOptions_What, pbExpandWhat, false); @@ -1247,7 +1251,7 @@ private void groupboxSizing(GroupBox section, PictureBox sectionImage, Boolean? switch (section.Name.ToString().Split('_').LastOrDefault()) { //Google case "Account": section.Height = 242; break; - case "GConfig": section.Height = 64; break; + case "GConfig": section.Height = 122; break; case "OAuth": section.Height = 174; break; //Settings case "How": section.Height = btCloseRegexRules.Visible ? 251 : 198; break; @@ -1486,6 +1490,7 @@ private void pbExpandGoogleOauth_Click(object sender, EventArgs e) { groupboxSizing(gbGoogle_OAuth, pbExpandGoogleOauth); } + #region Google Account private void llMultipleOGCS_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { Helper.OpenBrowser("https://github.com/phw198/OutlookGoogleCalendarSync/wiki/Running-Multiple-Instances-of-OGCS"); } @@ -1592,6 +1597,65 @@ private void btResetGCal_Click(object sender, EventArgs e) { private void cbListHiddenGcals_CheckedChanged(object sender, EventArgs e) { cbGoogleCalendars_BuildList(); } + #endregion + + #region GoogleConfig + #region Colours + private void cbColourFilter_SelectedIndexChanged(object sender, EventArgs e) { + if (this.LoadingProfileConfig) return; + + ActiveCalendarProfile.ColoursRestrictBy = (cbColourFilter.SelectedItem.ToString() == "Include") ? + SettingsStore.Calendar.RestrictBy.Include : SettingsStore.Calendar.RestrictBy.Exclude; + //Invert selection + miColourSelectInvert_Click(null, null); + } + + private void cbDeleteWhenColourExcl_CheckedChanged(object sender, EventArgs e) { + ActiveCalendarProfile.DeleteWhenColourExcluded = cbDeleteWhenColourExcl.Checked; + } + + private void clbColours_SelectedIndexChanged(object sender, EventArgs e) { + if (this.LoadingProfileConfig) return; + + ActiveCalendarProfile.Colours.Clear(); + foreach (object item in clbColours.CheckedItems) { + ActiveCalendarProfile.Colours.Add(item.ToString()); + } + } + + private void refreshColours() { + GoogleOgcs.Calendar.Instance.ColourPalette.Get(); + GoogleOgcs.Calendar.Instance.ColourPalette.BuildPicker(clbColours); + } + private void miColourRefresh_Click(object sender, EventArgs e) { + refreshColours(); + } + /// Shim function to work around x-thread call of BuildPicker() + public void miColourBuildPicker_Click(object sender, EventArgs e) { + CheckedListBox clb = GetControlThreadSafe(clbColours) as CheckedListBox; + GoogleOgcs.Calendar.Instance.ColourPalette.BuildPicker(clb); + SetControlPropertyThreadSafe(clbColours, "Items", clb.Items); + } + private void miColourSelectNone_Click(object sender, EventArgs e) { + for (int i = 0; i < clbColours.Items.Count; i++) { + clbColours.SetItemCheckState(i, CheckState.Unchecked); + } + clbColours_SelectedIndexChanged(null, null); + this.clbColours.SelectedIndexChanged += new System.EventHandler(this.clbColours_SelectedIndexChanged); + } + private void miColourSelectAll_Click(object sender, EventArgs e) { + for (int i = 0; i < clbColours.Items.Count; i++) { + clbColours.SetItemCheckState(i, CheckState.Checked); + } + clbColours_SelectedIndexChanged(null, null); + } + private void miColourSelectInvert_Click(object sender, EventArgs e) { + for (int i = 0; i < clbColours.Items.Count; i++) { + clbColours.SetItemChecked(i, !clbColours.CheckedIndices.Contains(i)); + } + clbColours_SelectedIndexChanged(null, null); + } + #endregion private void cbExcludeDeclinedInvites_CheckedChanged(object sender, EventArgs e) { ActiveCalendarProfile.ExcludeDeclinedInvites = cbExcludeDeclinedInvites.Checked; @@ -1599,6 +1663,7 @@ private void cbExcludeDeclinedInvites_CheckedChanged(object sender, EventArgs e) private void cbExcludeGoals_CheckedChanged(object sender, EventArgs e) { ActiveCalendarProfile.ExcludeGoals = cbExcludeGoals.Checked; } + #endregion #region Developer Options private void cbShowDeveloperOptions_CheckedChanged(object sender, EventArgs e) { @@ -1654,7 +1719,6 @@ private void syncDirection_SelectedIndexChanged(object sender, EventArgs e) { ActiveCalendarProfile.SyncDirection = (Sync.Direction)syncDirection.SelectedItem; if (ActiveCalendarProfile.SyncDirection.Id == Sync.Direction.Bidirectional.Id) { ActiveCalendarProfile.RegisterForPushSync(); - cbDeleteWhenCatExcl.Visible = true; cbObfuscateDirection.Enabled = true; cbObfuscateDirection.SelectedIndex = Sync.Direction.OutlookToGoogle.Id - 1; @@ -1674,7 +1738,6 @@ private void syncDirection_SelectedIndexChanged(object sender, EventArgs e) { lWhatExcludeInfo.Left = 207; cbExcludeTentative.Visible = true; } else { - cbDeleteWhenCatExcl.Visible = false; cbObfuscateDirection.Enabled = false; cbObfuscateDirection.SelectedIndex = ActiveCalendarProfile.SyncDirection.Id - 1; @@ -1966,20 +2029,20 @@ private void tbMinuteOffsets_ValueChanged(object sender, EventArgs e) { if (!Settings.Instance.UsingPersonalAPIkeys()) { //Fair usage - most frequent sync interval is 2 hours when Push enabled tbInterval.ValueChanged -= new System.EventHandler(this.tbMinuteOffsets_ValueChanged); - if (cbIntervalUnit.SelectedItem.ToString() == "Minutes") { + if (cbIntervalUnit.SelectedItem.ToString() == "Minutes") { if ((int)tbInterval.Value < MinSyncMinutes) - tbInterval.Value = (tbInterval.Value < Convert.ToInt16(tbInterval.Text)) ? 0 : MinSyncMinutes; + tbInterval.Value = (tbInterval.Value < Convert.ToInt16(tbInterval.Text)) ? 0 : MinSyncMinutes; else if ((int)tbInterval.Value > MinSyncMinutes) { tbInterval.Value = (MinSyncMinutes / 60) + 1; - cbIntervalUnit.Text = "Hours"; - } + cbIntervalUnit.Text = "Hours"; + } - } else if (cbIntervalUnit.SelectedItem.ToString() == "Hours") { + } else if (cbIntervalUnit.SelectedItem.ToString() == "Hours") { if (((int)tbInterval.Value * 60) < MinSyncMinutes) - tbInterval.Value = (tbInterval.Value < Convert.ToInt16(tbInterval.Text)) ? 0 : (MinSyncMinutes / 60); + tbInterval.Value = (tbInterval.Value < Convert.ToInt16(tbInterval.Text)) ? 0 : (MinSyncMinutes / 60); + } + tbInterval.ValueChanged += new System.EventHandler(this.tbMinuteOffsets_ValueChanged); } - tbInterval.ValueChanged += new System.EventHandler(this.tbMinuteOffsets_ValueChanged); - } ActiveCalendarProfile.SyncInterval = (int)tbInterval.Value; ActiveCalendarProfile.OgcsTimer.SetNextSync(); @@ -1987,7 +2050,7 @@ private void tbMinuteOffsets_ValueChanged(object sender, EventArgs e) { } private void cbIntervalUnit_SelectedIndexChanged(object sender, EventArgs e) { - if (cbIntervalUnit.Text == "Minutes" && (int)tbInterval.Value > 0 && (int)tbInterval.Value < MinSyncMinutes) { + if (cbIntervalUnit.Text == "Minutes" && (int)tbInterval.Value > 0 && (int)tbInterval.Value < MinSyncMinutes) { tbInterval.Value = MinSyncMinutes; } ActiveCalendarProfile.SyncIntervalUnit = cbIntervalUnit.Text; @@ -2379,20 +2442,20 @@ private void cbAlphaReleases_CheckedChanged(object sender, EventArgs e) { #endregion #region Thread safe access to form components - //private delegate Control getControlThreadSafeDelegate(Control control); + private delegate Control getControlThreadSafeDelegate(Control control); - private delegate void setControlPropertyThreadSafeDelegate(Control control, string propertyName, object propertyValue); private delegate object getControlPropertyThreadSafeDelegate(Control control, string propertyName); + private delegate void setControlPropertyThreadSafeDelegate(Control control, string propertyName, object propertyValue); private delegate void callControlMethodThreadSafeDelegate(Control control, string methodName, object methodArgValue); - //private static Control getControlThreadSafe(Control control) { - // if (control.InvokeRequired) { - // return (Control)control.Invoke(new getControlThreadSafeDelegate(getControlThreadSafe), new object[] { control }); - // } else { - // return control; - // } - //} + public static Control GetControlThreadSafe(Control control) { + if (control.InvokeRequired) { + return (Control)control.Invoke(new getControlThreadSafeDelegate(GetControlThreadSafe), new object[] { control }); + } else { + return control.GetType().InvokeMember("discarded", System.Reflection.BindingFlags.CreateInstance, null, control, null) as Control; + } + } public object GetControlPropertyThreadSafe(Control control, string propertyName) { if (control.InvokeRequired) { @@ -2405,8 +2468,12 @@ public void SetControlPropertyThreadSafe(Control control, string propertyName, o if (control.InvokeRequired) { control.Invoke(new setControlPropertyThreadSafeDelegate(SetControlPropertyThreadSafe), new object[] { control, propertyName, propertyValue }); } else { + if (control is CheckedListBox && propertyValue is CheckedListBox.ObjectCollection) { + (control as CheckedListBox).Items.AddRange(propertyValue as CheckedListBox.ObjectCollection); + return; + } var theObject = control.GetType().InvokeMember(propertyName, System.Reflection.BindingFlags.SetProperty, null, control, new object[] { propertyValue }); - if (control.GetType().Name == "TextBox") { + if (control is TextBox) { TextBox tb = control as TextBox; tb.SelectionStart = tb.Text.Length; tb.ScrollToCaret(); diff --git a/src/OutlookGoogleCalendarSync/Forms/MainForm.resx b/src/OutlookGoogleCalendarSync/Forms/MainForm.resx index 5b4ff2be..25eade93 100644 --- a/src/OutlookGoogleCalendarSync/Forms/MainForm.resx +++ b/src/OutlookGoogleCalendarSync/Forms/MainForm.resx @@ -118,10 +118,10 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - 142, 17 + 403, 17 - 17, 17 + 126, 17 To change the Client ID and secret, first disconnect your account @@ -131,9 +131,12 @@ Obtain new values from the Google Developer Console. You'll need to enable the Calendar API in your project: - + 17, 17 + + 251, 17 + On the "Google" tab, select the calendar you wish to synchronise. @@ -160,7 +163,7 @@ or support further improvements, any donations would be greatly appreciated! - 285, 17 + 546, 17 diff --git a/src/OutlookGoogleCalendarSync/GoogleOgcs/EventColour.cs b/src/OutlookGoogleCalendarSync/GoogleOgcs/EventColour.cs index aa3472ba..2de827f7 100644 --- a/src/OutlookGoogleCalendarSync/GoogleOgcs/EventColour.cs +++ b/src/OutlookGoogleCalendarSync/GoogleOgcs/EventColour.cs @@ -232,6 +232,26 @@ public void Get() { foreach (KeyValuePair colour in colours.Calendar) { calendarPalette.Add(new Palette(Palette.Type.Calendar, colour.Key, colour.Value.Background, OutlookOgcs.Categories.Map.RgbColour(colour.Value.Background))); } + Forms.Main.Instance.miColourBuildPicker_Click(null, null); + } + + /// + /// Build colour list from those downloaded from Google. + /// + /// The checklistbox to populate with the colours. + public void BuildPicker(System.Windows.Forms.CheckedListBox clb) { + clb.BeginUpdate(); + clb.Items.Clear(); + clb.Items.Add(""); + foreach (Palette colour in GoogleOgcs.Calendar.Instance.ColourPalette.eventPalette) { + clb.Items.Add(colour.Name); + } + foreach (String colour in Forms.Main.Instance.ActiveCalendarProfile.Colours) { + try { + clb.SetItemChecked(clb.Items.IndexOf(colour), true); + } catch { /* Colour "colour" no longer exists */ } + } + clb.EndUpdate(); } /// diff --git a/src/OutlookGoogleCalendarSync/GoogleOgcs/GoogleCalendar.cs b/src/OutlookGoogleCalendarSync/GoogleOgcs/GoogleCalendar.cs index e89a8f4e..e055c408 100644 --- a/src/OutlookGoogleCalendarSync/GoogleOgcs/GoogleCalendar.cs +++ b/src/OutlookGoogleCalendarSync/GoogleOgcs/GoogleCalendar.cs @@ -25,9 +25,10 @@ public static Calendar Instance { Authenticator = new GoogleOgcs.Authenticator() }; instance.Authenticator.GetAuthenticated(); - if (instance.Authenticator.Authenticated) + if (instance.Authenticator.Authenticated) { instance.Authenticator.OgcsUserStatus(); - else { + _ = instance.ColourPalette; + } else { instance = null; if (Forms.Main.Instance.Console.DocumentText.Contains("Authorisation to allow OGCS to manage your Google calendar was cancelled.")) throw new OperationCanceledException(); @@ -42,6 +43,9 @@ public Calendar() { } private Boolean openedIssue1593 = false; public GoogleOgcs.Authenticator Authenticator; + /// Google Events excluded through user config + public Dictionary ExcludedByColour { get; private set; } + private GoogleOgcs.EventColour colourPalette; public static Boolean IsColourPaletteNull { get { return instance?.colourPalette == null; } } @@ -271,6 +275,7 @@ public List GetCalendarEntriesInRange() { public List GetCalendarEntriesInRange(DateTime from, DateTime to) { List result = new List(); + ExcludedByColour = new Dictionary(); Events request = null; String pageToken = null; Int16 pageNum = 1; @@ -339,6 +344,25 @@ public List GetCalendarEntriesInRange(DateTime from, DateTime to) { result = result.Except(endsOnSyncStart).ToList(); } + //Colours + List colour = new List(); + if (profile.ColoursRestrictBy == SettingsStore.Calendar.RestrictBy.Include) { + colour = result.Where(ev => (profile.Colours.Count() == 0 || (String.IsNullOrEmpty(ev.ColorId) && !profile.Colours.Contains("")) || + !String.IsNullOrEmpty(ev.ColorId) && !profile.Colours.Contains(EventColour.Palette.GetColourName(ev.ColorId)))).ToList(); + + } else if (profile.ColoursRestrictBy == SettingsStore.Calendar.RestrictBy.Exclude) { + colour = result.Where(ev => (profile.Colours.Count() > 0 && (String.IsNullOrEmpty(ev.ColorId) && profile.Colours.Contains("")) || + !String.IsNullOrEmpty(ev.ColorId) && profile.Colours.Contains(EventColour.Palette.GetColourName(ev.ColorId)))).ToList(); + } + if (colour.Count > 0) { + log.Debug(colour.Count + " Google items contain a colour that is filtered out."); + } + foreach (Event ev in colour) { + ExcludedByColour.Add(ev.Id, CustomProperty.Get(ev, CustomProperty.MetadataId.oEntryId)); + } + result = result.Except(colour).ToList(); + + //Availability, Privacy if (profile.SyncDirection.Id != Sync.Direction.OutlookToGoogle.Id) { //Sync direction means G->O will delete previously synced all-days if (profile.ExcludeFree) { List availability = result.Where(ev => profile.ExcludeFree && ev.Transparency == "transparent").ToList(); @@ -363,6 +387,7 @@ public List GetCalendarEntriesInRange(DateTime from, DateTime to) { } } + //Invitation if (profile.ExcludeDeclinedInvites) { List declined = result.Where(ev => string.IsNullOrEmpty(ev.RecurringEventId) && ev.Attendees != null && ev.Attendees.Count(a => a.Self == true && a.ResponseStatus == "declined") == 1).ToList(); if (declined.Count > 0) { @@ -371,6 +396,7 @@ public List GetCalendarEntriesInRange(DateTime from, DateTime to) { } } + //Goals if ((IsDefaultCalendar() ?? true) && profile.ExcludeGoals) { List goals = result.Where(ev => !string.IsNullOrEmpty(ev.Description) && ev.Description.Contains("This event was added from Goals in Google Calendar.") && @@ -1366,15 +1392,24 @@ public void IdentifyEventDifferences( if (responseFiltered > 0) log.Info(responseFiltered + " Outlook items will not be created due to only syncing invites that have been responded to."); } - if (google.Count > 0 && OutlookOgcs.Calendar.Instance.ExcludedByCategory.Count > 0 && profile.SyncDirection.Id == Sync.Direction.Bidirectional.Id && !profile.DeleteWhenCategoryExcluded) { + if (google.Count > 0 && OutlookOgcs.Calendar.Instance.ExcludedByCategory.Count > 0 && !profile.DeleteWhenCategoryExcluded) { //Check if Google items to be deleted were filtered out from Outlook for (int g = google.Count - 1; g >= 0; g--) { - if (CustomProperty.Exists(google[g], CustomProperty.MetadataId.oEntryId) && - OutlookOgcs.Calendar.Instance.ExcludedByCategory.Contains(CustomProperty.Get(google[g], CustomProperty.MetadataId.oEntryId))) { + if (OutlookOgcs.Calendar.Instance.ExcludedByCategory.ContainsValue(google[g].Id) || + OutlookOgcs.Calendar.Instance.ExcludedByCategory.ContainsKey(CustomProperty.Get(google[g], CustomProperty.MetadataId.oEntryId) ?? "")) { google.Remove(google[g]); } } } + if (outlook.Count > 0 && GoogleOgcs.Calendar.Instance.ExcludedByColour.Count > 0) { + //Check if Outlook items to be created were filtered out from Google + for (int o = outlook.Count - 1; o >= 0; o--) { + if (ExcludedByColour.ContainsValue(outlook[o].EntryID) || + ExcludedByColour.ContainsKey(OutlookOgcs.CustomProperty.Get(outlook[o], OutlookOgcs.CustomProperty.MetadataId.gEventID) ?? "")) { + outlook.Remove(outlook[o]); + } + } + } if (profile.DisableDelete) { if (google.Count > 0) { @@ -2156,6 +2191,23 @@ public static ApiException HandleAPIlimits(ref Google.GoogleApiException ex, Eve return null; } } + + /// + /// Build colour list from any saved in Settings, instead of downloading from Google. + /// + /// The checklistbox to populate with the colours. + public static void BuildOfflineColourPicker(System.Windows.Forms.CheckedListBox clb) { + if (IsInstanceNull || !Instance.Authenticator.Authenticated) { + clb.BeginUpdate(); + clb.Items.Clear(); + foreach (String colour in Forms.Main.Instance.ActiveCalendarProfile.Colours) { + clb.Items.Add(colour, true); + } + clb.EndUpdate(); + } else { + Instance.ColourPalette.BuildPicker(clb); + } + } #endregion /// diff --git a/src/OutlookGoogleCalendarSync/OutlookOgcs/OutlookCalendar.cs b/src/OutlookGoogleCalendarSync/OutlookOgcs/OutlookCalendar.cs index 90a5831b..081dbc48 100644 --- a/src/OutlookGoogleCalendarSync/OutlookOgcs/OutlookCalendar.cs +++ b/src/OutlookGoogleCalendarSync/OutlookOgcs/OutlookCalendar.cs @@ -60,8 +60,8 @@ public enum Service { } public EphemeralProperties EphemeralProperties = new EphemeralProperties(); - /// Outlook Event IDs excluded through user config - public List ExcludedByCategory; + /// Outlook Appointment excluded through user config + public Dictionary ExcludedByCategory { get; private set; } public Calendar() { InstanceConnect = true; @@ -232,7 +232,7 @@ public List FilterCalendarEntries(SettingsStore.Calendar profil (profile.CategoriesRestrictBy == SettingsStore.Calendar.RestrictBy.Exclude && profile.Categories.Contains(""))); } else throw; } - if (filtered) { ExcludedByCategory.Add(ai.EntryID); continue; } + if (filtered) { ExcludedByCategory.Add(ai.EntryID, CustomProperty.Get(ai, CustomProperty.MetadataId.gEventID)); continue; } //Availability, Privacy if (profile.SyncDirection.Id != Sync.Direction.GoogleToOutlook.Id) { //Sync direction means O->G will delete previously synced excluded items @@ -270,7 +270,7 @@ public List FilterCalendarEntries(SettingsStore.Calendar profil if (ExcludedByCategory.Count > 0) log.Info(ExcludedByCategory.Count + " Outlook items contain a category that is filtered out."); if (responseFiltered > 0) log.Info(responseFiltered + " Outlook items are invites not yet responded to."); - if ((allDayFiltered + ExcludedByCategory.Count + responseFiltered) > 0) { + if ((availabilityFiltered + allDayFiltered + ExcludedByCategory.Count + responseFiltered) > 0) { if (result.Count == 0) Forms.Main.Instance.Console.Update("Due to your OGCS Outlook settings, all Outlook items have been filtered out!", Console.Markup.config, notifyBubble: true); else if (profile.SyncDirection.Id == Sync.Direction.GoogleToOutlook.Id) @@ -1449,6 +1449,25 @@ public static void IdentifyEventDifferences( } if (responseFiltered > 0) log.Info(responseFiltered + " Outlook items will not be deleted due to only syncing invites that have been responded to."); } + + if (outlook.Count > 0 && GoogleOgcs.Calendar.Instance.ExcludedByColour.Count > 0 && !profile.DeleteWhenColourExcluded) { + //Check if Outlook items to be deleted were filtered out from Google + for (int o = outlook.Count - 1; o >= 0; o--) { + if (GoogleOgcs.Calendar.Instance.ExcludedByColour.ContainsValue(outlook[o].EntryID) || + GoogleOgcs.Calendar.Instance.ExcludedByColour.ContainsKey(CustomProperty.Get(outlook[o], CustomProperty.MetadataId.gEventID) ?? "")) { + outlook.Remove(outlook[o]); + } + } + } + if (google.Count > 0 && Instance.ExcludedByCategory.Count > 0) { + //Check if Google items to be created were filtered out from Outlook + for (int g = google.Count - 1; g >= 0; g--) { + if (Instance.ExcludedByCategory.ContainsValue(google[g].Id) || + Instance.ExcludedByCategory.ContainsKey(GoogleOgcs.CustomProperty.Get(google[g], GoogleOgcs.CustomProperty.MetadataId.oEntryId) ?? "")) { + google.Remove(google[g]); + } + } + } if (profile.DisableDelete) { if (outlook.Count > 0) { diff --git a/src/OutlookGoogleCalendarSync/SettingsStore/Calendar.cs b/src/OutlookGoogleCalendarSync/SettingsStore/Calendar.cs index e0c5ba64..a753c0c3 100644 --- a/src/OutlookGoogleCalendarSync/SettingsStore/Calendar.cs +++ b/src/OutlookGoogleCalendarSync/SettingsStore/Calendar.cs @@ -47,6 +47,9 @@ private void setDefaults() { //Google UseGoogleCalendar = new GoogleCalendarListEntry(); CloakEmail = true; + ColoursRestrictBy = RestrictBy.Exclude; + DeleteWhenColourExcluded = true; + Colours = new List(); ExcludeDeclinedInvites = true; ExcludeGoals = true; @@ -127,6 +130,9 @@ [DataMember] public Boolean OutlookGalBlocked { #region Google [DataMember] public GoogleCalendarListEntry UseGoogleCalendar { get; set; } [DataMember] public Boolean CloakEmail { get; set; } + [DataMember] public RestrictBy ColoursRestrictBy { get; set; } + [DataMember] public Boolean DeleteWhenColourExcluded { get; set; } + [DataMember] public List Colours { get; set; } [DataMember] public Boolean ExcludeDeclinedInvites { get; set; } [DataMember] public Boolean ExcludeGoals { get; set; } #endregion @@ -272,6 +278,9 @@ public void LogSettings() { log.Info("GOOGLE SETTINGS:-"); log.Info(" Calendar: " + (UseGoogleCalendar == null ? "" : UseGoogleCalendar.ToString(true))); + log.Info(" Colour Filter: " + ColoursRestrictBy.ToString()); + log.Info(" Delete When Excluded:" + DeleteWhenColourExcluded); + log.Info(" Colours: " + String.Join(",", Colours.ToArray())); log.Info(" Exclude Declined Invites: " + ExcludeDeclinedInvites); log.Info(" Exclude Goals: " + ExcludeGoals); log.Info(" Cloak Email: " + CloakEmail);