From d7c7c94a7e0cabd39ec35c840a851655e40cec67 Mon Sep 17 00:00:00 2001 From: Patrick Simpson Date: Thu, 29 Jun 2017 18:27:48 +0200 Subject: [PATCH] Implemented GABLookupControl using new combo box --- .../Controls/KAbstractComboBox.cs | 21 +- .../AcaciaZPushPlugin/Controls/KComboBox.cs | 64 +++- .../Controls/KComboBoxCustomDraw.cs | 2 +- .../SharedFoldersDialog.Designer.cs | 49 +-- .../SharedFolders/SharedFoldersDialog.resx | 241 +++++++------- .../AcaciaZPushPlugin/UI/GABLookupControl.cs | 300 ++++++++---------- .../AcaciaZPushPlugin/ZPush/GABUser.cs | 15 +- 7 files changed, 362 insertions(+), 330 deletions(-) diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KAbstractComboBox.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KAbstractComboBox.cs index 96a95d0..7d7fd52 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KAbstractComboBox.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KAbstractComboBox.cs @@ -59,15 +59,24 @@ namespace Acacia.Controls } } + protected int _settingText = 0; override public string Text { get { return _edit.Text; } set { - _edit.Text = value; - // Set the cursor after the text - _edit.Select(_edit.Text.Length, 0); + ++_settingText; + try + { + _edit.Text = value; + // Set the cursor after the text + _edit.Select(_edit.Text.Length, 0); + } + finally + { + --_settingText; + } } } @@ -327,12 +336,6 @@ namespace Acacia.Controls DropControl.MaximumSize = DropControl.MinimumSize = new Size(width, height); _dropDown.Control.Bounds = _dropDown.ControlHost.Bounds; - System.Diagnostics.Trace.WriteLine(string.Format( - "Layout: {0}, host: {1}, control: {2}", - height, - _dropDown.ControlHost.Bounds, - _dropDown.Control.Bounds - )); } protected abstract int GetDropDownHeightMax(); diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KComboBox.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KComboBox.cs index 309b49c..00aa0eb 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KComboBox.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KComboBox.cs @@ -27,6 +27,7 @@ namespace Acacia.Controls { private readonly KComboBox _owner; private int _committedIndex = -1; + public int ItemWidth { get; set; } public DropList(KComboBox owner, bool ownerDraw) { @@ -91,7 +92,8 @@ namespace Acacia.Controls { // Preferred size is simply the size of the (maximum) number of items Size prefSize = base.GetPreferredSize(proposedSize); - return new Size(prefSize.Width, ItemHeight * Math.Min(Items.Count, _owner.MaxDropDownItems)); + int w = Math.Max(prefSize.Width, ItemWidth); + return new Size(w, ItemHeight * Math.Min(Items.Count, _owner.MaxDropDownItems)); } public void CommitSelection() @@ -162,18 +164,41 @@ namespace Acacia.Controls Text = ""; _selectedItem = null; } + OnSelectedItemChanged(); } - public void BeginUpdate() + public DisplayItem SelectedItem { - _list.BeginUpdate(); + get { return _selectedItem; } } - public void EndUpdate() + public void Select(object data) { - _list.EndUpdate(); + _list.SelectedIndex = -1; + Text = null; + _selectedItem = null; + if (data != null) + { + foreach (DisplayItem item in DisplayItems) + { + if (item.Item.Equals(data)) + { + _list.SelectedItem = item; + _selectedItem = item; + break; + } + } + } } + public event EventHandler SelectedItemChanged; + + protected virtual void OnSelectedItemChanged() + { + SelectedItemChanged?.Invoke(this, new EventArgs()); + } + + /// /// Wrapper for list items to use custom string formatting /// @@ -213,11 +238,14 @@ namespace Acacia.Controls if (_dataSource != value) { _dataSource = value; + _displayItemCache.Clear(); UpdateItems(); } } } + private readonly Dictionary _displayItemCache = new Dictionary(); + private void UpdateItems() { int oldCount = _list.Items.Count; @@ -228,12 +256,17 @@ namespace Acacia.Controls int selected = -1; foreach (object item in _dataSource.FilteredItems) { - DisplayItem displayItem = new DisplayItem(this, item); - if (displayItem.Equals(_selectedItem)) + DisplayItem displayItem; + if (!_displayItemCache.TryGetValue(item, out displayItem)) + { + displayItem = new DisplayItem(this, item); + _displayItemCache.Add(item, displayItem); + } + + if (displayItem == _selectedItem) selected = _list.Items.Count; _list.Items.Add(displayItem); } - System.Diagnostics.Trace.WriteLine(string.Format("FILTER: {0}", _list.Items.Count, selected)); // Select the current item only if new number of items is smaller. This means we don't keep selection // when the user is removing text, only when they are typing more. @@ -277,7 +310,7 @@ namespace Acacia.Controls protected void SetItemSize(Size size) { ItemHeight = size.Height; - _list.Width = size.Width; + _list.ItemWidth = size.Width; } protected override void OnTextChanged(EventArgs e) @@ -290,7 +323,10 @@ namespace Acacia.Controls DataSource.Filter = new KDataFilter(Text); UpdateItems(); - DroppedDown = true; + if (_settingText == 0) + { + DroppedDown = true; + } } } @@ -322,8 +358,12 @@ namespace Acacia.Controls // Enter commits the selected index and closes the drop down case Keys.Enter: case Keys.Tab: - _list.CommitSelection(); - DroppedDown = false; + if (DroppedDown) + { + if (_list.SelectedIndex >= 0) + _list.CommitSelection(); + DroppedDown = false; + } e.IsInputKey = e.KeyCode == Keys.Enter; break; default: diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KComboBoxCustomDraw.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KComboBoxCustomDraw.cs index cb15187..5f5f86a 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KComboBoxCustomDraw.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KComboBoxCustomDraw.cs @@ -49,7 +49,7 @@ namespace Acacia.Controls OnDrawItem(new DrawItemEventArgs(e, GetDisplayItem(e.Index))); } - abstract protected void OnDrawItem(DrawItemEventArgs e); + protected abstract void OnDrawItem(DrawItemEventArgs e); protected abstract void OnMeasureItem(MeasureItemEventArgs e); diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.Designer.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.Designer.cs index 479ae06..ae3b9b3 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.Designer.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.Designer.cs @@ -35,19 +35,19 @@ this._layoutMain = new System.Windows.Forms.TableLayoutPanel(); this._layoutSelectUser = new System.Windows.Forms.TableLayoutPanel(); this.labelSelectUser = new System.Windows.Forms.Label(); - this.buttonOpenUser = new System.Windows.Forms.Button(); this._layoutCenterGABLookup = new System.Windows.Forms.TableLayoutPanel(); this.gabLookup = new Acacia.UI.GABLookupControl(); + this.buttonOpenUser = new System.Windows.Forms.Button(); this.kTreeFolders = new Acacia.Controls.KTree(); this._layoutOptions = new System.Windows.Forms.TableLayoutPanel(); this._labelName = new System.Windows.Forms.Label(); this.textName = new System.Windows.Forms.TextBox(); this._labelSendAs = new System.Windows.Forms.Label(); this.checkSendAs = new System.Windows.Forms.CheckBox(); - this._labelPermissions = new System.Windows.Forms.Label(); - this.labelPermissionsValue = new System.Windows.Forms.Label(); this._labelReminders = new System.Windows.Forms.Label(); this.checkReminders = new System.Windows.Forms.CheckBox(); + this._labelPermissions = new System.Windows.Forms.Label(); + this.labelPermissionsValue = new System.Windows.Forms.Label(); this.dialogButtons = new Acacia.Controls.KDialogButtons(); this._layout.SuspendLayout(); this._mainBusyHider.SuspendLayout(); @@ -85,8 +85,8 @@ // resources.ApplyResources(this._layoutSelectUser, "_layoutSelectUser"); this._layoutSelectUser.Controls.Add(this.labelSelectUser, 0, 0); - this._layoutSelectUser.Controls.Add(this.buttonOpenUser, 2, 0); this._layoutSelectUser.Controls.Add(this._layoutCenterGABLookup, 1, 0); + this._layoutSelectUser.Controls.Add(this.buttonOpenUser, 2, 0); this._layoutSelectUser.Name = "_layoutSelectUser"; // // labelSelectUser @@ -94,13 +94,6 @@ resources.ApplyResources(this.labelSelectUser, "labelSelectUser"); this.labelSelectUser.Name = "labelSelectUser"; // - // buttonOpenUser - // - resources.ApplyResources(this.buttonOpenUser, "buttonOpenUser"); - this.buttonOpenUser.Name = "buttonOpenUser"; - this.buttonOpenUser.UseVisualStyleBackColor = true; - this.buttonOpenUser.Click += new System.EventHandler(this.buttonOpenUser_Click); - // // _layoutCenterGABLookup // resources.ApplyResources(this._layoutCenterGABLookup, "_layoutCenterGABLookup"); @@ -114,9 +107,18 @@ this.gabLookup.DroppedDown = false; this.gabLookup.GAB = null; this.gabLookup.Name = "gabLookup"; + this.gabLookup.PlaceholderColor = System.Drawing.Color.Gray; + this.gabLookup.PlaceholderFont = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.gabLookup.SelectedUser = null; this.gabLookup.SelectedUserChanged += new Acacia.UI.GABLookupControl.SelectedUserEventHandler(this.gabLookup_SelectedUserChanged); // + // buttonOpenUser + // + resources.ApplyResources(this.buttonOpenUser, "buttonOpenUser"); + this.buttonOpenUser.Name = "buttonOpenUser"; + this.buttonOpenUser.UseVisualStyleBackColor = true; + this.buttonOpenUser.Click += new System.EventHandler(this.buttonOpenUser_Click); + // // kTreeFolders // this.kTreeFolders.BackColor = System.Drawing.SystemColors.Window; @@ -140,10 +142,10 @@ this._layoutOptions.Controls.Add(this.textName, 1, 0); this._layoutOptions.Controls.Add(this._labelSendAs, 0, 1); this._layoutOptions.Controls.Add(this.checkSendAs, 1, 1); - this._layoutOptions.Controls.Add(this._labelPermissions, 0, 3); - this._layoutOptions.Controls.Add(this.labelPermissionsValue, 1, 3); this._layoutOptions.Controls.Add(this._labelReminders, 0, 2); this._layoutOptions.Controls.Add(this.checkReminders, 1, 2); + this._layoutOptions.Controls.Add(this._labelPermissions, 0, 3); + this._layoutOptions.Controls.Add(this.labelPermissionsValue, 1, 3); this._layoutOptions.Name = "_layoutOptions"; // // _labelName @@ -170,16 +172,6 @@ this.checkSendAs.UseVisualStyleBackColor = true; this.checkSendAs.CheckedChanged += new System.EventHandler(this.checkSendAs_CheckedChanged); // - // _labelPermissions - // - resources.ApplyResources(this._labelPermissions, "_labelPermissions"); - this._labelPermissions.Name = "_labelPermissions"; - // - // labelPermissionsValue - // - resources.ApplyResources(this.labelPermissionsValue, "labelPermissionsValue"); - this.labelPermissionsValue.Name = "labelPermissionsValue"; - // // _labelReminders // resources.ApplyResources(this._labelReminders, "_labelReminders"); @@ -192,6 +184,16 @@ this.checkReminders.UseVisualStyleBackColor = true; this.checkReminders.CheckedChanged += new System.EventHandler(this.checkReminders_CheckedChanged); // + // _labelPermissions + // + resources.ApplyResources(this._labelPermissions, "_labelPermissions"); + this._labelPermissions.Name = "_labelPermissions"; + // + // labelPermissionsValue + // + resources.ApplyResources(this.labelPermissionsValue, "labelPermissionsValue"); + this.labelPermissionsValue.Name = "labelPermissionsValue"; + // // dialogButtons // resources.ApplyResources(this.dialogButtons, "dialogButtons"); @@ -220,6 +222,7 @@ this._layoutSelectUser.ResumeLayout(false); this._layoutSelectUser.PerformLayout(); this._layoutCenterGABLookup.ResumeLayout(false); + this._layoutCenterGABLookup.PerformLayout(); this._layoutOptions.ResumeLayout(false); this._layoutOptions.PerformLayout(); this.ResumeLayout(false); diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.resx b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.resx index 9d25f1f..2d9e44e 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.resx +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.resx @@ -148,7 +148,7 @@ 3, 0 - 105, 31 + 105, 33 0 @@ -171,48 +171,6 @@ 0 - - True - - - GrowAndShrink - - - Fill - - - False - - - NoControl - - - 380, 3 - - - 8, 0, 8, 0 - - - 59, 25 - - - 1 - - - Open - - - buttonOpenUser - - - System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - _layoutSelectUser - - - 1 - True @@ -228,8 +186,11 @@ 200, 0 + + + - 256, 21 + 256, 23 0 @@ -259,10 +220,10 @@ 3 - 262, 27 + 262, 29 - 2 + 1 _layoutCenterGABLookup @@ -274,11 +235,53 @@ _layoutSelectUser - 2 + 1 <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="gabLookup" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /></Controls><Columns Styles="Percent,100" /><Rows Styles="Percent,50,AutoSize,0,Percent,50" /></TableLayoutSettings> + + True + + + GrowAndShrink + + + Fill + + + False + + + NoControl + + + 380, 3 + + + 8, 0, 8, 0 + + + 59, 27 + + + 2 + + + Open + + + buttonOpenUser + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + _layoutSelectUser + + + 2 + Fill @@ -289,7 +292,7 @@ 1 - 442, 31 + 442, 33 0 @@ -307,16 +310,16 @@ 0 - <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="labelSelectUser" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="buttonOpenUser" Row="0" RowSpan="1" Column="2" ColumnSpan="1" /><Control Name="_layoutCenterGABLookup" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /></Controls><Columns Styles="AutoSize,0,Percent,100,AutoSize,0" /><Rows Styles="Percent,100,Absolute,31" /></TableLayoutSettings> + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="labelSelectUser" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="_layoutCenterGABLookup" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="buttonOpenUser" Row="0" RowSpan="1" Column="2" ColumnSpan="1" /></Controls><Columns Styles="AutoSize,0,Percent,100,AutoSize,0" /><Rows Styles="Percent,100,Absolute,33" /></TableLayoutSettings> Fill - 3, 40 + 3, 42 - 442, 275 + 442, 273 0 @@ -468,6 +471,72 @@ 3 + + True + + + Fill + + + 3, 53 + + + 82, 27 + + + 6 + + + Show reminders + + + MiddleLeft + + + _labelReminders + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + _layoutOptions + + + 4 + + + True + + + Left + + + 94, 57 + + + 6, 4, 3, 3 + + + 0, 3, 0, 3 + + + 15, 20 + + + 7 + + + checkReminders + + + System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + _layoutOptions + + + 5 + True @@ -502,7 +571,7 @@ _layoutOptions - 4 + 6 True @@ -541,72 +610,6 @@ _layoutOptions - 5 - - - True - - - Fill - - - 3, 53 - - - 82, 27 - - - 6 - - - Show reminders - - - MiddleLeft - - - _labelReminders - - - System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - _layoutOptions - - - 6 - - - True - - - Left - - - 94, 57 - - - 6, 4, 3, 3 - - - 0, 3, 0, 3 - - - 15, 20 - - - 7 - - - checkReminders - - - System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - _layoutOptions - - 7 @@ -640,7 +643,7 @@ 2 - <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="_labelName" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="textName" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="_labelSendAs" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="checkSendAs" Row="1" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="_labelPermissions" Row="3" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="labelPermissionsValue" Row="3" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="_labelReminders" Row="2" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="checkReminders" Row="2" RowSpan="1" Column="1" ColumnSpan="1" /></Controls><Columns Styles="AutoSize,0,Percent,100" /><Rows Styles="AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0" /></TableLayoutSettings> + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="_labelName" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="textName" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="_labelSendAs" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="checkSendAs" Row="1" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="_labelReminders" Row="2" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="checkReminders" Row="2" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="_labelPermissions" Row="3" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="labelPermissionsValue" Row="3" RowSpan="1" Column="1" ColumnSpan="1" /></Controls><Columns Styles="AutoSize,0,Percent,100" /><Rows Styles="AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0" /></TableLayoutSettings> Fill diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/GABLookupControl.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/GABLookupControl.cs index 6e2fbca..7781420 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/GABLookupControl.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/UI/GABLookupControl.cs @@ -1,4 +1,4 @@ -/// Copyright 2016 Kopano b.v. +/// Copyright 2017 Kopano b.v. /// /// This program is free software: you can redistribute it and/or modify /// it under the terms of the GNU Affero General Public License, version 3, @@ -31,8 +31,59 @@ using Acacia.Controls; namespace Acacia.UI { - public partial class GABLookupControl : KComboBox + public partial class GABLookupControl : KComboBoxCustomDraw { + private class GABDataSource : KDataSource + { + private readonly GABHandler _gab; + private readonly List _users; + + public GABDataSource(GABHandler gab) + { + this._gab = gab; + + _users = new List(); + foreach (IItem item in _gab.Contacts.Items.Sort("FullName", false)) + { + if (item is IContactItem) + _users.Add(new GABUser((IContactItem)item)); + } + } + + public override IEnumerable Items + { + get + { + return _users; + } + } + + protected override string GetItemText(GABUser item) + { + // If there is a filter, try to complete that + if (!string.IsNullOrEmpty(Filter?.FilterText)) + { + string s = Filter?.FilterText.ToLower(); + if (item.UserName?.ToLower().StartsWith(s) == true) + return item.UserName; + else if (item.FullName?.ToLower().StartsWith(s) == true) + return item.FullName; + else if (item.EmailAddress?.ToLower().StartsWith(s) == true) + return item.EmailAddress; + } + return item.UserName; + } + + protected override bool MatchesFilter(GABUser item) + { + string s = Filter.FilterText.ToLower(); + return + item.FullName?.ToLower().StartsWith(s) == true || + item.UserName?.ToLower().StartsWith(s) == true || + item.EmailAddress?.ToLower().StartsWith(s) == true; + } + } + public GABLookupControl() : this(null) { } @@ -40,7 +91,7 @@ namespace Acacia.UI public GABLookupControl(GABHandler gab) { InitializeComponent(); - this.GAB = gab; + GAB = gab; } #region Properties and events @@ -64,40 +115,31 @@ namespace Acacia.UI [Category("Behavior")] public event SelectedUserEventHandler SelectedUserChanged; + private GABUser _selectedUser; public GABUser SelectedUser { get { - /*if (SelectedValue == null) - return new GABUser(Text, Text); - else - return (GABUser)SelectedValue;*/ - return null; + return _selectedUser; } set { - /*if (value == null) - { - SelectedIndex = -1; - Text = ""; - } - else - { - - }*/ + _selectedUser = null; + Select(value); } } - private void SetSelectedUser(GABUser user, bool isChosen) + protected override void OnTextChanged(EventArgs e) { - if (SelectedUser != user || isChosen) - { - System.Diagnostics.Trace.WriteLine(string.Format("SELECT: {0} -> {1} : {2}", SelectedUser, user, isChosen)); - if (isChosen) - SelectedUser = user; - if (SelectedUserChanged != null) - SelectedUserChanged(this, new SelectedUserEventArgs(user, isChosen)); - } + base.OnTextChanged(e); + _selectedUser = string.IsNullOrEmpty(Text) ? null : new GABUser(Text); + SelectedUserChanged?.Invoke(this, new SelectedUserEventArgs(_selectedUser, false)); + } + + protected override void OnSelectedItemChanged() + { + _selectedUser = (GABUser)SelectedItem?.Item; + SelectedUserChanged?.Invoke(this, new SelectedUserEventArgs(_selectedUser, true)); } #endregion @@ -117,7 +159,7 @@ namespace Acacia.UI if (_gab != value) { _gab = value; - LookupUsers(false); + DataSource = _gab == null ? null : new GABDataSource(_gab); } } } @@ -126,147 +168,20 @@ namespace Acacia.UI #endregion - protected override void OnTextChanged(EventArgs e) - { - LookupUsers(true); - SelectCurrentUser(false); - } - - private void SelectCurrentUser(bool isChosen) - { - /*GABUser user = null; - // Select whatever is currently in the text box as a user - if (DataSource != null) - { - // Find if there's a user matching - user = ((List)DataSource).FirstOrDefault((u) => u.DisplayName == Text); - } - if (user == null && Text.Length > 0) - { - // Make a new one - user = new GABUser(Text, Text); - } - SetSelectedUser(user, isChosen);*/ - } - - /*private bool _needUpdate; - - protected override void OnTextUpdate(EventArgs e) - { - _needUpdate = true; - } - - protected override void OnSelectedIndexChanged(EventArgs e) - { - base.OnSelectedIndexChanged(e); - SetSelectedUser((GABUser)SelectedItem, true); - } - - protected override void OnKeyDown(KeyEventArgs e) - { - base.OnKeyDown(e); - if (e.KeyCode == Keys.Enter) - { - SelectCurrentUser(true); - } - else - { - SetSelectedUser(null, false); - } - } - - protected override void OnDataSourceChanged(EventArgs e) - { - // Suppress to prevent automatic selection - }*/ - - private string _lastText; - private List _allUsers; - - private void LookupUsers(bool dropDown) - { - // Cannot lookup if there is no GAB - if (_gab == null) - return; - - string text = this.Text; - // Only search if the text actually changed - if (_lastText != text) - { - // Limit search results if there is a filter, otherwise show everything - List users; - if (text.Length == 0) - { - // Cache the list of all users - if (_allUsers == null) - { - _allUsers = Lookup("", int.MaxValue); - } - users = _allUsers; - } - else - { - users = Lookup(text, 8); - } - - // Sort the users if we have them - users.Sort(); - - _lastText = text; - - // Setting the datasource will trigger a select if there is a match - BeginUpdate(); - //DataSource = users; - //SetItemsCore(users); - if (dropDown && text.Length != 0) - DroppedDown = true; - //Cursor.Current = Cursors.Default; - //Text = _lastText; - //SelectionLength = 0; - //SelectionStart = _lastText.Length; - EndUpdate(); - } - } - - #region Lookup helpers - // TODO: these probably belong in GAB - - public List Lookup(string text, int max) - { - // Begin GAB lookup, search on full name or username - using (ISearch search = _gab.Contacts.Search()) - { - ISearchOperator oper = search.AddOperator(SearchOperator.Or); - oper.AddField("urn:schemas:contacts:cn").SetOperation(SearchOperation.Like, text + "%"); - oper.AddField("urn:schemas:contacts:customerid").SetOperation(SearchOperation.Like, text + "%"); - - // Fetch the results up to the limit. - // TODO: make limit a property? - List users = new List(); - foreach (IContactItem result in search.Search(max)) - { - users.Add(new GABUser(result.FullName, result.CustomerID)); - } - - return users; - } - } - public GABUser LookupExact(string username) { - if (_gab?.Contacts != null) + string s = username.ToLower(); + if (DataSource != null) { - // Begin GAB lookup, search on full name or username - using (ISearch search = _gab.Contacts.Search()) + foreach(GABUser user in DataSource.Items) { - search.AddField("urn:schemas:contacts:customerid").SetOperation(SearchOperation.Equal, username); - - // Fetch the result, if any. - List users = new List(); - using (IContactItem result = search.SearchOne()) + if ( + user.FullName?.ToLower().Equals(s) == true || + user.UserName?.ToLower().Equals(s) == true || + user.EmailAddress?.ToLower().Equals(s) == true + ) { - if (result != null) - return new GABUser(result.FullName, result.CustomerID); + return user; } } } @@ -274,6 +189,65 @@ namespace Acacia.UI return new GABUser(username); } + #region Rendering + + private static readonly Size NameSpacing = new Size(12, 4); + private static readonly Padding ItemPadding = new Padding(5); + private static readonly Padding BorderPadding = new Padding(2); + private const int BorderThickness = 1; + + protected override void OnMeasureItem(MeasureItemEventArgs e) + { + GABUser item = (GABUser)e.Item; + + Size nameSize = TextRenderer.MeasureText(e.Graphics, item.FullName, Font); + Size loginSize = TextRenderer.MeasureText(e.Graphics, item.UserName, Font); + Size emailSize = TextRenderer.MeasureText(e.Graphics, item.EmailAddress, Font); + + e.ItemWidth = Math.Max(emailSize.Width, nameSize.Width + loginSize.Width + NameSpacing.Width) + + ItemPadding.Horizontal; + e.ItemHeight = emailSize.Height + Math.Max(nameSize.Height, loginSize.Height) + + ItemPadding.Vertical + + NameSpacing.Height + + BorderThickness + BorderPadding.Vertical; + } + + protected override void OnDrawItem(DrawItemEventArgs e) + { + GABUser item = (GABUser)e.Item; + + // Draw the background + e.DrawBackground(); + + // Get the sizes + Size nameSize = TextRenderer.MeasureText(e.Graphics, item.FullName, Font); + Size loginSize = TextRenderer.MeasureText(e.Graphics, item.UserName, Font); + Size emailSize = TextRenderer.MeasureText(e.Graphics, item.EmailAddress, Font); + + // Draw the full name top-left + Point pt = e.Bounds.TopLeft(); + pt.Y += ItemPadding.Top; + pt.X += ItemPadding.Left; + TextRenderer.DrawText(e.Graphics, item.FullName, Font, pt, e.ForeColor); + + // Draw the username top-right + pt.X = e.Bounds.Right - loginSize.Width - ItemPadding.Right; + TextRenderer.DrawText(e.Graphics, item.UserName, Font, pt, e.ForeColor); + + // Draw the email below + pt.Y += Math.Max(nameSize.Height, loginSize.Height) + NameSpacing.Height; + pt.X = e.Bounds.X + ItemPadding.Left; + TextRenderer.DrawText(e.Graphics, item.EmailAddress, Font, pt, e.ForeColor); + + // Draw a separator line + if (e.Index < DisplayItemCount - 1) + { + int lineY = e.Bounds.Bottom - 1 - BorderThickness - BorderPadding.Bottom; + e.Graphics.DrawLine(Pens.LightGray, BorderPadding.Left, lineY, e.Bounds.Width - BorderPadding.Right, lineY); + } + + } + #endregion } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/GABUser.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/GABUser.cs index f269e45..fd3ff98 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/GABUser.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/GABUser.cs @@ -1,4 +1,6 @@ -/// Copyright 2016 Kopano b.v. + +using Acacia.Stubs; +/// Copyright 2016 Kopano b.v. /// /// This program is free software: you can redistribute it and/or modify /// it under the terms of the GNU Affero General Public License, version 3, @@ -13,7 +15,6 @@ /// along with this program.If not, see. /// /// Consult LICENSE file for details - using System; using System.Collections.Generic; using System.Linq; @@ -36,8 +37,9 @@ namespace Acacia.ZPush public readonly string FullName; public readonly string UserName; + public readonly string EmailAddress; - public GABUser(string displayName, string userName) + private GABUser(string displayName, string userName) { this.FullName = displayName; this.UserName = userName; @@ -49,6 +51,13 @@ namespace Acacia.ZPush this.UserName = userName; } + public GABUser(IContactItem item) + { + this.FullName = item.FullName; + this.EmailAddress = item.Email1Address; + this.UserName = item.CustomerID; + } + public int CompareTo(GABUser other) { return FullName.CompareTo(other.FullName);