[Freeswitch-trunk] [freeswitch-contrib] FreeSWITCH user-contributed scripts, etc branch master updated. java-esl-client-0.9.2-381-g09778f9

git at svn.freeswitch.org git at svn.freeswitch.org
Wed Feb 2 07:06:01 MSK 2011


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "FreeSWITCH user-contributed scripts, etc".

The branch, master has been updated
       via  09778f943674b470c51a636aa8e3e3b22589708e (commit)
      from  007d9a09df8e52d540e46eb009b44f69121fc275 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 09778f943674b470c51a636aa8e3e3b22589708e
Author: Mitch Capper <mitch.capper at gmail.com>
Date:   Tue Feb 1 20:04:51 2011 -0800

    Made NO_FS a bit more robust
    Moved broker to have an actuall make call function so other things can place calls
    Added Contact Search Box support, it is a bit hacky to say the least.....

diff --git a/mitchcapper/FSClient/Broker.cs b/mitchcapper/FSClient/Broker.cs
index 924d714..e0098b7 100644
--- a/mitchcapper/FSClient/Broker.cs
+++ b/mitchcapper/FSClient/Broker.cs
@@ -6,7 +6,8 @@ using System.Windows;
 using System.Windows.Controls;
 using System.Xml;
 
-using FreeSWITCH.Native;
+using FreeSWITCH.Native;
+using FSClient.Controls;
 using Timer = System.Timers.Timer;
 
 namespace FSClient {
@@ -70,6 +71,8 @@ namespace FSClient {
 			try {//it would be better if this was in the init function but it seems some dll load errors won't be caught if it is.
 #if ! NO_FS
 				fs_core_init();
+#else
+				fs_inited = false;
 #endif
 				if (FreeswitchLoaded != null)
 					FreeswitchLoaded(this, null);
@@ -82,14 +85,16 @@ namespace FSClient {
 				Environment.Exit(-1);
 
 			}
+#if ! NO_FS
 			DelayedFunction.DelayedCall("SofiaProfileCheck", sofia.sofia_profile_check, 100);
+#endif
 		}
 
 		private void initContactManager() {
 			contact_plugin_manager = new ContactPluginManager();
 
 		}
-
+
 		#region Text Input
 
 
@@ -118,8 +123,10 @@ namespace FSClient {
 			if (Call.active_call != null && Call.active_call.state == Call.CALL_STATE.Answered)
 				Call.active_call.send_dtmf(key.ToString());
 			else {
+#if ! NO_FS
 				PortAudio.PlayDTMF(key, null, true);
 				DelayedFunction.DelayedCall("PortAudioLastDigitHitStreamClose", close_streams, 5000);
+#endif
 			}
 		}
 		private void close_streams() {
@@ -219,6 +226,26 @@ namespace FSClient {
 			//OffHook = true;
 			//Utils.bgapi_exec("pa", "play tone_stream://%(10000,0,350,440);loops=20");
 		}
+		public void DialString(String str){
+			if (string.IsNullOrWhiteSpace(str))
+				return;
+			MainWindow.get_instance().RemoveFocus();
+
+			if (str.StartsWith("#") && str.Length > 2) {
+				String acct_num = str.Substring(1, 1);
+				str = str.Substring(2);
+				Account acct = (from a in Account.accounts where a.guid == acct_num select a).SingleOrDefault();
+				if (acct != null) {
+					acct.CreateCall(str);
+					return;
+				}
+			}
+			if (Account.default_account == null) {
+				MessageBox.Show("no default account, make sure you have added one or more accounts (right click in the account area to add) and they are enabled (checked)");
+				return;
+			}
+			Account.default_account.CreateCall(str);
+		}
 		public void TalkPressed() {
 			if (Call.active_call != null) {
 				if (Call.active_call.state == Call.CALL_STATE.Ringing && Call.active_call.is_outgoing == false)
@@ -228,22 +255,8 @@ namespace FSClient {
 			} else {
 				if (String.IsNullOrEmpty(cur_dial_str))
 					DialTone();
-				else {
-					if (cur_dial_str.StartsWith("#") && cur_dial_str.Length > 2) {
-						String acct_num = cur_dial_str.Substring(1, 1);
-						cur_dial_str = cur_dial_str.Substring(2);
-						Account acct = (from a in Account.accounts where a.guid == acct_num select a).SingleOrDefault();
-						if (acct != null) {
-							acct.CreateCall(cur_dial_str);
-							cur_dial_str = "";
-							return;
-						}
-					}
-					if (Account.default_account == null) {
-						MessageBox.Show("no default account, make sure you have added one or more accounts (right click in the account area to add) and they are enabled (checked)");
-						return;
-					}
-					Account.default_account.CreateCall(cur_dial_str);
+				else{
+					DialString(cur_dial_str);
 					cur_dial_str = "";
 				}
 			}
@@ -548,12 +561,16 @@ namespace FSClient {
 			sofia.reload_config(mode);
 		}
 		public static EventHandler<EventArgs> FreeswitchLoaded;
-		public static EventHandler<FSEvent> NewEvent;
+		public static EventHandler<FSEvent> NewEvent;
 		private void event_handler(FreeSWITCH.EventBinding.EventBindingArgs args) {
 
 			if (BroadcastHandler == null)
 				BroadcastHandler = new BroadcastEventDel(BroadcastEvent);
 			Application.Current.Dispatcher.BeginInvoke(BroadcastHandler, new object[] { new FSEvent(args.EventObj) });
+		}
+
+		public OurAutoCompleteBox GetContactSearchBox() {
+			return MainWindow.get_instance().GetContactSearchBox();
 		}
 		private delegate void BroadcastEventDel(FSEvent evt);
 		BroadcastEventDel BroadcastHandler;
@@ -587,7 +604,7 @@ namespace FSClient {
 		private bool is_inited;
 		private bool fs_inited;
 		private static IDisposable event_bind;
-
+		
 		private void fs_core_init() {
 			fs_inited = true;
 			freeswitch.switch_core_set_globals();
diff --git a/mitchcapper/FSClient/Controls/OurAutoCompleteBox.cs b/mitchcapper/FSClient/Controls/OurAutoCompleteBox.cs
new file mode 100644
index 0000000..edc358f
--- /dev/null
+++ b/mitchcapper/FSClient/Controls/OurAutoCompleteBox.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows.Controls;
+
+namespace FSClient.Controls {
+	public class OurAutoCompleteBox : AutoCompleteBox {
+	
+		private TextBox the_textbox;
+		private void find_textbox(){
+			if (the_textbox != null)
+				return;
+			the_textbox = Template.FindName("Text", this) as TextBox;
+		}
+		public TextBox GetActualTextbox() {
+			find_textbox();
+			return the_textbox;
+		}
+		public bool TextBoxHasFocus(){
+			find_textbox();
+			if (the_textbox == null)
+				return false;
+			return the_textbox.IsFocused;
+		}
+		public void TextBoxFocus(){
+			find_textbox();
+			if (the_textbox != null)
+				the_textbox.Focus();
+		}
+	}
+}
diff --git a/mitchcapper/FSClient/FSClient.csproj b/mitchcapper/FSClient/FSClient.csproj
index f4e250c..b12ef37 100644
--- a/mitchcapper/FSClient/FSClient.csproj
+++ b/mitchcapper/FSClient/FSClient.csproj
@@ -68,6 +68,10 @@
     <Reference Include="System.configuration" />
     <Reference Include="System.Data" />
     <Reference Include="System.Drawing" />
+    <Reference Include="System.Windows.Controls.Input.Toolkit, Version=3.5.40128.1, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>C:\Program Files (x86)\WPF Toolkit\v3.5.50211.1\System.Windows.Controls.Input.Toolkit.dll</HintPath>
+    </Reference>
     <Reference Include="System.Windows.Forms" />
     <Reference Include="System.Xaml" />
     <Reference Include="System.Xml">
@@ -91,6 +95,7 @@
     <Compile Include="Account.cs" />
     <Compile Include="Broker.cs" />
     <Compile Include="Call.cs" />
+    <Compile Include="Controls\OurAutoCompleteBox.cs" />
     <Compile Include="Controls\PhonePadButton.xaml.cs">
       <DependentUpon>PhonePadButton.xaml</DependentUpon>
     </Compile>
diff --git a/mitchcapper/FSClient/IContactPlugin.cs b/mitchcapper/FSClient/IContactPlugin.cs
index 4d59e57..b064ff6 100644
--- a/mitchcapper/FSClient/IContactPlugin.cs
+++ b/mitchcapper/FSClient/IContactPlugin.cs
@@ -5,7 +5,9 @@ using System.ComponentModel;
 using System.IO;
 using System.Reflection;
 using System.Windows;
-using System.Windows.Controls;
+using System.Windows.Controls;
+using FSClient.Controls;
+
 namespace FSClient {
 	public class ContactPluginManager : IDisposable {
 		private bool IsTypeOf(Type to_check, Type of) {
@@ -15,6 +17,9 @@ namespace FSClient {
 				return true;
 			return IsTypeOf(to_check.BaseType, of);
 		}
+
+		public static IEnumerable<MenuItem> ContactMenuItems { get; set; }
+
 		private List<IContactPlugin> plugins = new List<IContactPlugin>();
 		public void RegisterPlugin(IContactPlugin plugin) {
 			if (plugins.Count > 0)
@@ -22,13 +27,24 @@ namespace FSClient {
 			try {
 				plugins.Add(plugin);
 				plugin.Initialize();
+				Application.Current.Dispatcher.BeginInvoke((Action)ContactInit);
+				
+
 			} catch (Exception e) {
 				HandleError(plugin, e);
 			}
 		}
+		private void ContactInit(){
+			IContactPlugin plugin = plugins[0];
+			ContactMenuItems = plugin.ContactRightClickMenu();
+			OurAutoCompleteBox box = Broker.get_instance().GetContactSearchBox();
+			if (!plugin.HandleSearchBox(box))
+				box.Visibility = Visibility.Collapsed;
+		}
 		private void HandleError(IContactPlugin plugin, Exception e) {
 			Utils.PluginLog("Contact Plugin Manager", "Plugin \"" + plugin.ProviderName() + "\" had an error Due to: " + e.Message);
-		}
+
+		}
 	
 		public ContactPluginManager() {
 
@@ -62,17 +78,17 @@ namespace FSClient {
 					Utils.PluginLog("Contact Plugin Manager", "Error creating contact plugin from dll \"" + dll + "\" of: " + e.Message);
 				}
 			}
-			Call.calls.CollectionChanged += calls_CollectionChanged;
-			Call.CallRightClickMenuShowing += calls_RightClickMenuShowing;
-		}
-
-		private void calls_RightClickMenuShowing(object sender, Call.CallRightClickEventArgs e){
-			if (plugins.Count == 0)
-				return;
-			plugins[0].CallRightClickMenu(e.call, e.menu);
-		}
-
-
+			Call.calls.CollectionChanged += calls_CollectionChanged;
+			Call.CallRightClickMenuShowing += calls_RightClickMenuShowing;
+		}
+
+		private void calls_RightClickMenuShowing(object sender, Call.CallRightClickEventArgs e){
+			if (plugins.Count == 0)
+				return;
+			plugins[0].CallRightClickMenu(e.call, e.menu);
+		}
+
+
 		private void calls_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { //We want to background resolve things incase a plugin does something that takes awhile
 			if (e.NewItems == null || plugins.Count != 1)
 				return;
@@ -140,11 +156,13 @@ namespace FSClient {
 	public abstract class IContactPlugin {
 		public delegate void NumberResolved(String DisplayName);
 
-		public abstract void ResolveNumber(String number, NumberResolved on_resolved);
+		public abstract void ResolveNumber(String number, NumberResolved on_resolved);
 		public abstract void CallRightClickMenu(Call call, ContextMenu menu);
+		public abstract IEnumerable<MenuItem> ContactRightClickMenu();
 		public abstract void Initialize();
 		public abstract void Terminate();
-		public abstract string ProviderName();
+		public abstract string ProviderName();
+		public abstract bool HandleSearchBox(OurAutoCompleteBox box);
 
 	}
 }
diff --git a/mitchcapper/FSClient/MainWindow.xaml b/mitchcapper/FSClient/MainWindow.xaml
index cf42a50..5e1eb04 100644
--- a/mitchcapper/FSClient/MainWindow.xaml
+++ b/mitchcapper/FSClient/MainWindow.xaml
@@ -1,9 +1,7 @@
 <Window
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-		xmlns:ours="clr-namespace:FSClient.Controls"
-
-        xmlns:toolkit="http://schemas.microsoft.com/wpf/2008/toolkit" xmlns:local="clr-namespace:FSClient" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="FSClient.MainWindow"
+		xmlns:ours="clr-namespace:FSClient.Controls" xmlns:local="clr-namespace:FSClient" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:Controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Input.Toolkit" mc:Ignorable="d" x:Class="FSClient.MainWindow"
         Title="FSClient" Height="319" Width="666"  WindowStyle="SingleBorderWindow" ResizeMode="CanMinimize" Closing="Window_Closing" Icon="phone.ico">
 	<Window.Resources>
 		<local:DurationTimeConverter x:Key="DurationTimeConverter"/>
@@ -174,15 +172,27 @@
 
 				</StackPanel>
 			</Border>
-			<Button Content="Options" HorizontalAlignment="Left" x:Name="btnOptions" Width="75" Click="btnOptions_Click" Style="{DynamicResource GlassButtonStyle}" Height="20" Canvas.Left="349" Canvas.Top="266" d:LayoutOverrides="VerticalAlignment" />
+			<Button Content="Options" HorizontalAlignment="Left" x:Name="btnOptions" Width="50" Click="btnOptions_Click" Style="{DynamicResource GlassButtonStyle}" Height="20" Canvas.Left="374" Canvas.Top="266" d:LayoutOverrides="VerticalAlignment" />
 		</Canvas>
 		<Button Canvas.Left="283" Canvas.Top="21" Content="Send To Voicemail" FontWeight="Bold" Foreground="#FFF5E200" Height="20" Name="btnSendVoicemail" Style="{DynamicResource GlassButtonStyle}" Width="120" Visibility="Hidden" Click="btnSendVoicemail_Click" />
+
+		<ours:OurAutoCompleteBox Canvas.Left="435" Text="Contact Search" Canvas.Top="265" Height="22" Width="164.553" Opacity="0.8" x:Name="txtSearchBox" FilterMode="Contains" GotKeyboardFocus="txtSearchBox_GotKeyboardFocus" LostKeyboardFocus="txtSearchBox_LostKeyboardFocus" DropDownClosing="txtSearchBox_DropDownClosing">
+			<ours:OurAutoCompleteBox.ItemTemplate>
+				<DataTemplate>
+
+					<TextBlock Text="{Binding}">
+						<TextBlock.ContextMenu>
+							<ContextMenu x:Name="contactSearchConextMenu" ItemsSource="{Binding Path=(local:ContactPluginManager.ContactMenuItems)}" IsEnabled="true" Closed="contactSearchConextMenu_Closed" Loaded="contactSearchConextMenu_Loaded" />
+						</TextBlock.ContextMenu>
+					</TextBlock>
+				</DataTemplate>
+				</ours:OurAutoCompleteBox.ItemTemplate>
+		</ours:OurAutoCompleteBox>
 		<Control
             x:Name="busyAnimation" 
             Style="{StaticResource BusyAnimationStyle}"
             Width="{Binding Path=ActualWidth, ElementName=mainControl}" 
-            Height="{Binding Path=ActualHeight, ElementName=mainControl}" 
+            Height="{Binding Path=ActualHeight, ElementName=mainControl}" d:IsHidden="True" 
             />
-
 	</Canvas>
 </Window>
diff --git a/mitchcapper/FSClient/MainWindow.xaml.cs b/mitchcapper/FSClient/MainWindow.xaml.cs
index bd80d6b..2dd780b 100644
--- a/mitchcapper/FSClient/MainWindow.xaml.cs
+++ b/mitchcapper/FSClient/MainWindow.xaml.cs
@@ -1,396 +1,458 @@
-using System;
-using System.ComponentModel;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Input;
-using System.Windows.Media;
-namespace FSClient {
-	public partial class MainWindow : Window {
-		private Broker broker;
-		public MainWindow() {
-			_instance = this;
-
-			InitializeComponent();
-
-			gridCalls.DataContext = Call.calls;
-
-
-			gridCalls.LoadingRow += gridCalls_LoadingRow;
-			gridAccounts.DataContext = Account.accounts;
-
-			this.Loaded += MainWindow_Loaded;
-			
-
-		}
-
-		private void ActiveCallChanged(object sender, Call.ActiveCallChangedArgs e) {
-			Dispatcher.BeginInvoke((Action)(() => {
-				CurrentCallInfo.DataContext = Call.active_call;
-				if (Call.active_call == null)
-					CurrentCallInfo.Visibility = Visibility.Hidden;
-				else
-					CurrentCallInfo.Visibility = Visibility.Visible;
-			}));
-		}
-		private void CallStateChanged(object sender, Call.CallPropertyEventArgs e) {
-			gridCalls.Items.SortDescriptions.Clear();
-			gridCalls.Items.SortDescriptions.Add(new SortDescription("sort_order", ListSortDirection.Descending));
-		}
-		void accounts_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) {
-			if (e.NewItems == null)
-				return;
-			foreach (Account acct in e.NewItems) {
-				acct.PropertyChanged += acct_PropertyChanged;
-			}
-		}
-
-		void acct_PropertyChanged(object sender, PropertyChangedEventArgs e) {
-			if (e.PropertyName == "gateway_id") {
-				gridAccounts.Items.SortDescriptions.Clear();
-				gridAccounts.Items.SortDescriptions.Add(new SortDescription("gateway_id", ListSortDirection.Ascending));
-			}
-		}
-
-
-
-
-		void gridCalls_LoadingRow(object sender, DataGridRowEventArgs e) {
-			e.Row.SetResourceReference(ToolTipProperty, "mainCallTooltip");
-			last_tip = e.Row.ToolTip as ToolTip;
+using System;
+using System.ComponentModel;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Input;
+using System.Windows.Media;
+using FSClient.Controls;
+
+namespace FSClient {
+	public partial class MainWindow : Window {
+		private Broker broker;
+		public MainWindow() {
+			_instance = this;
+
+			InitializeComponent();
+
+			gridCalls.DataContext = Call.calls;
+
+
+			gridCalls.LoadingRow += gridCalls_LoadingRow;
+			gridAccounts.DataContext = Account.accounts;
+
+			this.Loaded += MainWindow_Loaded;
+
+
+		}
+
+		private void ActiveCallChanged(object sender, Call.ActiveCallChangedArgs e) {
+			Dispatcher.BeginInvoke((Action)(() => {
+				CurrentCallInfo.DataContext = Call.active_call;
+				if (Call.active_call == null)
+					CurrentCallInfo.Visibility = Visibility.Hidden;
+				else
+					CurrentCallInfo.Visibility = Visibility.Visible;
+			}));
+		}
+		private void CallStateChanged(object sender, Call.CallPropertyEventArgs e) {
+			gridCalls.Items.SortDescriptions.Clear();
+			gridCalls.Items.SortDescriptions.Add(new SortDescription("sort_order", ListSortDirection.Descending));
+		}
+		void accounts_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) {
+			if (e.NewItems == null)
+				return;
+			foreach (Account acct in e.NewItems) {
+				acct.PropertyChanged += acct_PropertyChanged;
+			}
+		}
+
+		void acct_PropertyChanged(object sender, PropertyChangedEventArgs e) {
+			if (e.PropertyName == "gateway_id") {
+				gridAccounts.Items.SortDescriptions.Clear();
+				gridAccounts.Items.SortDescriptions.Add(new SortDescription("gateway_id", ListSortDirection.Ascending));
+			}
+		}
+
+
+
+
+		void gridCalls_LoadingRow(object sender, DataGridRowEventArgs e) {
+			e.Row.SetResourceReference(ToolTipProperty, "mainCallTooltip");
 			Call c = e.Row.DataContext as Call;
-			last_row = e.Row;
 			if (c == null)
-				return;
-			e.Row.ContextMenu = c.CallRightClickMenu();
-			
-		}
-		private ToolTip last_tip;
-		private DataGridRow last_row;
-		public void SetDialStr(string str) {
-			Dispatcher.BeginInvoke((Action)(() => {
-				txtNumber.Text = str;
-			}));
-		}
-
-		private void CanEndChanged(object sender, bool data) {
-			Dispatcher.BeginInvoke((Action)(() => {
-				btnHangup.IsEnabled = broker.CanEnd;
-			}));
-		}
-		private void SpeakerActiveChanged(object sender, bool data) {
-			Dispatcher.BeginInvoke((Action)(() => {
-				btnSpeaker.Foreground = data ? enabled_brush : disabled_brush;
-			}));
-		}
-		private void MuteChanged(object sender, bool data) {
-			Dispatcher.BeginInvoke((Action)(() => {
-				btnMute.Foreground = data ? enabled_brush : disabled_brush;
-			}));
-		}
-		private void DNDChanged(object sender, bool data) {
-			Dispatcher.BeginInvoke((Action)(() => {
-				btnDND.Foreground = data ? enabled_brush : disabled_brush;
-				Title = "FSClient " + (data ? " - DND" : "");
-			}));
-		}
-		private void CallActiveChanged(object sender, bool data) {
-			Dispatcher.BeginInvoke((Action)(() => {
-				btnHold.IsEnabled = broker.call_active;
-				btnTransfer.IsEnabled = broker.call_active;
-			}));
-
-		}
-
-
-
-		#region TextInput
-
-		private enum TEXT_INPUT_MODE { NUMBERS_ONLY, FULL };
-
-		private TEXT_INPUT_MODE text_mode = TEXT_INPUT_MODE.NUMBERS_ONLY;
-		private void simple_text_mode_char_convert(char c) {
-			if (c == '*' || c == '#' || (c >= '0' && c <= '9')){
-				broker.handle_key_action(c);
-				return;
-			}
-			switch (Char.ToUpper(c)) {
-				case 'A':
-				case 'B':
-				case 'C':
-					broker.handle_key_action('2');
-					break;
-				case 'D':
-				case 'E':
-				case 'F':
-					broker.handle_key_action('3');
-					break;
-				case 'G':
-				case 'H':
-				case 'I':
-					broker.handle_key_action('4');
-					break;
-				case 'J':
-				case 'K':
-				case 'L':
-					broker.handle_key_action('5');
-					break;
-				case 'M':
-				case 'N':
-				case 'O':
-					broker.handle_key_action('6');
-					break;
-				case 'P':
-				case 'Q':
-				case 'R':
-				case 'S':
-					broker.handle_key_action('7');
-					break;
-				case 'T':
-				case 'U':
-				case 'V':
-					broker.handle_key_action('8');
-					break;
-				case 'W':
-				case 'X':
-				case 'Y':
-				case 'Z':
-					broker.handle_key_action('9');
-					break;
-			}
-		}
-		void MainWindow_PreviewTextInput(object sender, TextCompositionEventArgs e) {
-			if (!broker.fully_loaded)
-				return;
-			char[] chars = e.Text.ToCharArray();
-			char[] sys_chars = e.ControlText.ToCharArray();
-			foreach (Char c in sys_chars) {
-				if (c == 22) //paste
-				{
-					String clipboard = Clipboard.GetText();
-					char[] tmp = new char[chars.Length + clipboard.Length];
-					chars.CopyTo(tmp, 0);
-					clipboard.ToCharArray().CopyTo(tmp, chars.Length);
-					chars = tmp;
-				}
-			}
-
-			e.Handled = false;
-			foreach (Char c in chars) {
-				bool handled = true;
-				if (c > 32 && c < 127) {
-					if (text_mode == TEXT_INPUT_MODE.NUMBERS_ONLY || (Call.active_call != null && Call.active_call.state == Call.CALL_STATE.Answered) )
-						simple_text_mode_char_convert(c);
-					else
-						broker.handle_key_action(c);
-						
-				}
-				else if (c == '\b')
-					broker.handle_special_action(Broker.KEYBOARD_ACTION.Backspace);
-				else if (c == '\r')
-					broker.handle_special_action(Broker.KEYBOARD_ACTION.Enter);
-				else if (c == 27)
-					broker.handle_special_action(Broker.KEYBOARD_ACTION.Escape);
-				else
-					handled = false;
-				if (handled)
-					e.Handled = true;
-			}
-		}
-		void MainWindow_PreviewKeyDown(object sender, KeyEventArgs e) {
-			if (!broker.fully_loaded)
-				return;
-
-			if (e.Key == Key.Return){
-				broker.handle_special_action(Broker.KEYBOARD_ACTION.Enter);
-				e.Handled = true;
-			}
-		}
-		#endregion
-		private static MainWindow _instance;
-		public static MainWindow get_instance() {
-			return _instance;
-		}
-
-		private void DialStrChanged(object sender, string data) {
-			SetDialStr(broker.cur_dial_str);
-		}
-		private void CallRingingChanged(object sender, bool data) {
-			Dispatcher.Invoke((Action)(() => {
-				if (data && Call.active_call != null && Call.active_call.CanSendToVoicemail())
-					btnSendVoicemail.Visibility = Visibility.Visible;
-				else
-					btnSendVoicemail.Visibility = Visibility.Hidden;
-			}));
-		}
-		void MainWindow_Loaded(object sender, RoutedEventArgs e) {
-			PreviewTextInput += MainWindow_PreviewTextInput;
-			PreviewKeyDown += MainWindow_PreviewKeyDown; //return must be handled seperately as buttons are triggered on down it seems
-			Call.CallStateChanged += CallStateChanged;
-			Call.ActiveCallChanged += ActiveCallChanged;
-			Account.accounts.CollectionChanged += accounts_CollectionChanged;
-			Broker.FreeswitchLoaded += new EventHandler<EventArgs>(FreeswitchLoaded);
-			broker = Broker.get_instance();
-			
-			broker.cur_dial_strChanged += DialStrChanged;
-			broker.call_activeChanged += CallActiveChanged;
-			broker.active_call_ringingChanged += CallRingingChanged;
-			broker.MutedChanged += MuteChanged;
-			broker.DNDChanged += DNDChanged;
-			broker.CanEndChanged += CanEndChanged;
-			broker.UseNumberOnlyInputChanged += UseNumberOnlyInputChanged;
-			UseNumberOnlyInputChanged(null, false);//trigger an update
-			broker.SpeakerphoneActiveChanged += SpeakerActiveChanged;
-			CurrentCallInfo.Visibility = Visibility.Hidden;
-			Windows.systray_icon_setup();
-		}
-
-		private void FreeswitchLoaded(object sender, EventArgs e){
-			Dispatcher.BeginInvoke((Action)(() => 
-			{
-				busyAnimation.Visibility = Visibility.Hidden;
-			}));
-		}
-		
-
-
-		private void UseNumberOnlyInputChanged(object sender, bool data){
-			text_mode = broker.UseNumberOnlyInput ? TEXT_INPUT_MODE.NUMBERS_ONLY : TEXT_INPUT_MODE.FULL;
-		}
-
-		public void BringToFront() {
-			Show();
-			BringIntoView();
-			WindowState = WindowState.Normal;
-			Topmost = true;
-			Topmost = false;
-		}
-		private void btnCall_Click(object sender, RoutedEventArgs e) {
-			broker.TalkPressed();
-
-		}
-
-		private void btnOptions_Click(object sender, RoutedEventArgs e) {
-			Options opt = new Options();
-			opt.ShowDialog();
-		}
-
-		private void btnHangup_Click(object sender, RoutedEventArgs e) {
-			broker.HangupPressed();
-		}
-
-		private void gridCalls_MouseDoubleClick(object sender, MouseButtonEventArgs e) {
-			FrameworkElement elem = e.OriginalSource as FrameworkElement;
-			if (elem == null)
-				return;
-			Call call = elem.DataContext as Call;
-			if (call == null)
-				return;
-			call.DefaultAction();
-		}
-
-		SolidColorBrush enabled_brush = new SolidColorBrush(Colors.Yellow);
-		SolidColorBrush disabled_brush = new SolidColorBrush(Colors.White);
-		private void btnMute_Click(object sender, RoutedEventArgs e) {
-			broker.Muted = !broker.Muted;
-		}
-
-		private void btnDND_Click(object sender, RoutedEventArgs e) {
-			broker.DND = !broker.DND;
-		}
-		private void gridAccounts_MouseUp(object sender, MouseButtonEventArgs e) {
-			FrameworkElement elem = e.OriginalSource as FrameworkElement;
-			if (elem == null)
-				return;
-			Account account = elem.DataContext as Account;
-			if (account == null)
-				return;
-			DependencyObject dep = elem;
-			while (dep != null && !(dep is DataGridCell)) {
-				dep = VisualTreeHelper.GetParent(dep);
-			}
-			DataGridCell cell = dep as DataGridCell;
-			if (cell == null)
-				return;
-
-			if (cell.Column.SortMemberPath == "enabled") {
-				account.enabled = !account.enabled;
-				account.ReloadAccount();
-			}
-		}
-
-		private void Window_Closing(object sender, CancelEventArgs e) {
-			try{
-				Windows.systray_icon_remove();
-				broker.Dispose();
-			}
-			catch { }
-		}
-
-		private void btnSpeaker_Click(object sender, RoutedEventArgs e) {
-			broker.SpeakerphoneActive = !broker.SpeakerphoneActive;
-		}
-
-
-		private void AccountNew_Click(object sender, RoutedEventArgs e) {
-			Account acct = new Account();
-			Account.AddAccount(acct);
-			acct.edit();
-
-		}
-
-		private void AccountEdit_Click(object sender, RoutedEventArgs e) {
-			Account acct = gridAccounts.SelectedItem as Account;
-			if (acct == null)
-				return;
-			acct.edit();
-		}
-
-		private void AccountSetDefault_Click(object sender, RoutedEventArgs e) {
-			Account acct = gridAccounts.SelectedItem as Account;
-			if (acct == null)
-				return;
-			acct.is_default_account = true;
-		}
-
-		private void AccountDelete_Click(object sender, RoutedEventArgs e) {
-			Account acct = gridAccounts.SelectedItem as Account;
-			if (acct == null)
-				return;
-			Account.accounts.Remove(acct);
-		}
-
-
-		private void gridAccounts_ContextMenuOpening(object sender, ContextMenuEventArgs e) {
-			menuAccountDelete.IsEnabled = menuAccountEdit.IsEnabled = menuAccountSetDefault.IsEnabled = gridAccounts.SelectedItem != null;
-		}
-
-		private void btnDialpad_Click(object sender, RoutedEventArgs e) {
-			Button btn = sender as Button;
-			if (btn != null)
-				broker.handle_key_action(btn.Content.ToString()[0]);
-			Controls.PhonePadButton btn2 = sender as Controls.PhonePadButton;
-			if (btn2 != null)
-				broker.handle_key_action(btn2.Number[0]);
-
-		}
-
-		private void btnHold_Click(object sender, RoutedEventArgs e) {
-			if (Call.active_call != null)
-				Call.active_call.hold();
-		}
-
-		private void btnSendVoicemail_Click(object sender, RoutedEventArgs e) {
-			if (Call.active_call != null)
-				Call.active_call.SendToVoicemail();
-		}
-
-		private void btnTransfer_Click(object sender, RoutedEventArgs e) {
-			if (Call.active_call != null)
-				Call.active_call.TransferPrompt();
-
-
-		}
-
-
-	}
-}
+				return;
+			e.Row.ContextMenu = c.CallRightClickMenu();
+
+		}
+		public void SetDialStr(string str) {
+			Dispatcher.BeginInvoke((Action)(() => {
+				txtNumber.Text = str;
+			}));
+		}
+
+		private void CanEndChanged(object sender, bool data) {
+			Dispatcher.BeginInvoke((Action)(() => {
+				btnHangup.IsEnabled = broker.CanEnd;
+			}));
+		}
+		private void SpeakerActiveChanged(object sender, bool data) {
+			Dispatcher.BeginInvoke((Action)(() => {
+				btnSpeaker.Foreground = data ? enabled_brush : disabled_brush;
+			}));
+		}
+		private void MuteChanged(object sender, bool data) {
+			Dispatcher.BeginInvoke((Action)(() => {
+				btnMute.Foreground = data ? enabled_brush : disabled_brush;
+			}));
+		}
+		private void DNDChanged(object sender, bool data) {
+			Dispatcher.BeginInvoke((Action)(() => {
+				btnDND.Foreground = data ? enabled_brush : disabled_brush;
+				Title = "FSClient " + (data ? " - DND" : "");
+			}));
+		}
+		private void CallActiveChanged(object sender, bool data) {
+			Dispatcher.BeginInvoke((Action)(() => {
+				btnHold.IsEnabled = broker.call_active;
+				btnTransfer.IsEnabled = broker.call_active;
+			}));
+
+		}
+
+
+
+		#region TextInput
+
+		private enum TEXT_INPUT_MODE { NUMBERS_ONLY, FULL };
+
+		private TEXT_INPUT_MODE text_mode = TEXT_INPUT_MODE.NUMBERS_ONLY;
+		private void simple_text_mode_char_convert(char c) {
+			if (c == '*' || c == '#' || (c >= '0' && c <= '9')) {
+				broker.handle_key_action(c);
+				return;
+			}
+			switch (Char.ToUpper(c)) {
+				case 'A':
+				case 'B':
+				case 'C':
+					broker.handle_key_action('2');
+					break;
+				case 'D':
+				case 'E':
+				case 'F':
+					broker.handle_key_action('3');
+					break;
+				case 'G':
+				case 'H':
+				case 'I':
+					broker.handle_key_action('4');
+					break;
+				case 'J':
+				case 'K':
+				case 'L':
+					broker.handle_key_action('5');
+					break;
+				case 'M':
+				case 'N':
+				case 'O':
+					broker.handle_key_action('6');
+					break;
+				case 'P':
+				case 'Q':
+				case 'R':
+				case 'S':
+					broker.handle_key_action('7');
+					break;
+				case 'T':
+				case 'U':
+				case 'V':
+					broker.handle_key_action('8');
+					break;
+				case 'W':
+				case 'X':
+				case 'Y':
+				case 'Z':
+					broker.handle_key_action('9');
+					break;
+			}
+		}
+
+		private bool text_interception_enabled = true;
+		void MainWindow_PreviewTextInput(object sender, TextCompositionEventArgs e) {
+			if (!broker.fully_loaded)
+				return;
+			if (!text_interception_enabled) {
+				e.Handled = false;
+				return;
+			}
+			char[] chars = e.Text.ToCharArray();
+			char[] sys_chars = e.ControlText.ToCharArray();
+			foreach (Char c in sys_chars) {
+				if (c == 22) //paste / control + v
+				{
+					String clipboard = Clipboard.GetText();
+					char[] tmp = new char[chars.Length + clipboard.Length];
+					chars.CopyTo(tmp, 0);
+					clipboard.ToCharArray().CopyTo(tmp, chars.Length);
+					chars = tmp;
+				}
+				else if (c == 6){ // control + f
+					txtSearchBox.TextBoxFocus();
+				}
+			}
+
+			e.Handled = false;
+			foreach (Char c in chars) {
+				bool handled = true;
+				if (c > 32 && c < 127) {
+					if (text_mode == TEXT_INPUT_MODE.NUMBERS_ONLY || (Call.active_call != null && Call.active_call.state == Call.CALL_STATE.Answered))
+						simple_text_mode_char_convert(c);
+					else
+						broker.handle_key_action(c);
+
+				}
+				else if (c == '\b')
+					broker.handle_special_action(Broker.KEYBOARD_ACTION.Backspace);
+				else if (c == '\r')
+					broker.handle_special_action(Broker.KEYBOARD_ACTION.Enter);
+				else if (c == 27)
+					broker.handle_special_action(Broker.KEYBOARD_ACTION.Escape);
+				else
+					handled = false;
+				if (handled)
+					e.Handled = true;
+			}
+		}
+		void MainWindow_PreviewKeyDown(object sender, KeyEventArgs e) {
+			if (!broker.fully_loaded)
+				return;
+			if (!text_interception_enabled) {
+				e.Handled = false;
+				return;
+			}
+
+			if (e.Key == Key.Return) {
+				broker.handle_special_action(Broker.KEYBOARD_ACTION.Enter);
+				e.Handled = true;
+			}
+		}
+		#endregion
+		private static MainWindow _instance;
+		public static MainWindow get_instance() {
+			return _instance;
+		}
+
+		private void DialStrChanged(object sender, string data) {
+			SetDialStr(broker.cur_dial_str);
+		}
+		private void CallRingingChanged(object sender, bool data) {
+			Dispatcher.Invoke((Action)(() => {
+				if (data && Call.active_call != null && Call.active_call.CanSendToVoicemail())
+					btnSendVoicemail.Visibility = Visibility.Visible;
+				else
+					btnSendVoicemail.Visibility = Visibility.Hidden;
+			}));
+		}
+		void MainWindow_Loaded(object sender, RoutedEventArgs e) {
+			PreviewTextInput += MainWindow_PreviewTextInput;
+			PreviewKeyDown += MainWindow_PreviewKeyDown; //return must be handled seperately as buttons are triggered on down it seems
+			MouseUp += MainWindow_MouseUp;
+
+			Call.CallStateChanged += CallStateChanged;
+			Call.ActiveCallChanged += ActiveCallChanged;
+			Account.accounts.CollectionChanged += accounts_CollectionChanged;
+			Broker.FreeswitchLoaded += FreeswitchLoaded;
+			broker = Broker.get_instance();
+
+			broker.cur_dial_strChanged += DialStrChanged;
+			broker.call_activeChanged += CallActiveChanged;
+			broker.active_call_ringingChanged += CallRingingChanged;
+			broker.MutedChanged += MuteChanged;
+			broker.DNDChanged += DNDChanged;
+			broker.CanEndChanged += CanEndChanged;
+			broker.UseNumberOnlyInputChanged += UseNumberOnlyInputChanged;
+			UseNumberOnlyInputChanged(null, false);//trigger an update
+			broker.SpeakerphoneActiveChanged += SpeakerActiveChanged;
+			CurrentCallInfo.Visibility = Visibility.Hidden;
+			Windows.systray_icon_setup();
+		}
+
+		void MainWindow_MouseUp(object sender, MouseButtonEventArgs e) {
+			if (txtSearchBox.TextBoxHasFocus()){
+				DependencyObject parent = e.OriginalSource as UIElement;
+				while (parent != null && !(parent is OurAutoCompleteBox)) 
+					parent = VisualTreeHelper.GetParent(parent);
+				if (parent == null)
+					RemoveFocus();
+			}
+
+		}
+
+		public void RemoveFocus(){
+			btnMute.Focus(); //should really divert focus a better way
+		}
+
+
+
+		private void FreeswitchLoaded(object sender, EventArgs e) {
+			Dispatcher.BeginInvoke((Action)(() => {
+				busyAnimation.Visibility = Visibility.Hidden;
+			}));
+		}
+
+
+
+		private void UseNumberOnlyInputChanged(object sender, bool data) {
+			text_mode = broker.UseNumberOnlyInput ? TEXT_INPUT_MODE.NUMBERS_ONLY : TEXT_INPUT_MODE.FULL;
+		}
+
+		public void BringToFront() {
+			Show();
+			BringIntoView();
+			WindowState = WindowState.Normal;
+			Topmost = true;
+			Topmost = false;
+		}
+		private void btnCall_Click(object sender, RoutedEventArgs e) {
+			broker.TalkPressed();
+
+		}
+
+		private void btnOptions_Click(object sender, RoutedEventArgs e) {
+			Options opt = new Options();
+			opt.ShowDialog();
+		}
+
+		private void btnHangup_Click(object sender, RoutedEventArgs e) {
+			broker.HangupPressed();
+		}
+
+		private void gridCalls_MouseDoubleClick(object sender, MouseButtonEventArgs e) {
+			FrameworkElement elem = e.OriginalSource as FrameworkElement;
+			if (elem == null)
+				return;
+			Call call = elem.DataContext as Call;
+			if (call == null)
+				return;
+			call.DefaultAction();
+		}
+
+		SolidColorBrush enabled_brush = new SolidColorBrush(Colors.Yellow);
+		SolidColorBrush disabled_brush = new SolidColorBrush(Colors.White);
+		private void btnMute_Click(object sender, RoutedEventArgs e) {
+			broker.Muted = !broker.Muted;
+		}
+
+		private void btnDND_Click(object sender, RoutedEventArgs e) {
+			broker.DND = !broker.DND;
+		}
+		private void gridAccounts_MouseUp(object sender, MouseButtonEventArgs e) {
+			FrameworkElement elem = e.OriginalSource as FrameworkElement;
+			if (elem == null)
+				return;
+			Account account = elem.DataContext as Account;
+			if (account == null)
+				return;
+			DependencyObject dep = elem;
+			while (dep != null && !(dep is DataGridCell)) {
+				dep = VisualTreeHelper.GetParent(dep);
+			}
+			DataGridCell cell = dep as DataGridCell;
+			if (cell == null)
+				return;
+
+			if (cell.Column.SortMemberPath == "enabled") {
+				account.enabled = !account.enabled;
+				account.ReloadAccount();
+			}
+		}
+
+		private void Window_Closing(object sender, CancelEventArgs e) {
+			try {
+				Windows.systray_icon_remove();
+				broker.Dispose();
+			}
+			catch{ }
+		}
+
+		private void btnSpeaker_Click(object sender, RoutedEventArgs e) {
+			broker.SpeakerphoneActive = !broker.SpeakerphoneActive;
+		}
+
+
+		private void AccountNew_Click(object sender, RoutedEventArgs e) {
+			Account acct = new Account();
+			Account.AddAccount(acct);
+			acct.edit();
+
+		}
+
+		private void AccountEdit_Click(object sender, RoutedEventArgs e) {
+			Account acct = gridAccounts.SelectedItem as Account;
+			if (acct == null)
+				return;
+			acct.edit();
+		}
+
+		private void AccountSetDefault_Click(object sender, RoutedEventArgs e) {
+			Account acct = gridAccounts.SelectedItem as Account;
+			if (acct == null)
+				return;
+			acct.is_default_account = true;
+		}
+
+		private void AccountDelete_Click(object sender, RoutedEventArgs e) {
+			Account acct = gridAccounts.SelectedItem as Account;
+			if (acct == null)
+				return;
+			Account.accounts.Remove(acct);
+		}
+
+
+		private void gridAccounts_ContextMenuOpening(object sender, ContextMenuEventArgs e) {
+			menuAccountDelete.IsEnabled = menuAccountEdit.IsEnabled = menuAccountSetDefault.IsEnabled = gridAccounts.SelectedItem != null;
+		}
+
+		private void btnDialpad_Click(object sender, RoutedEventArgs e) {
+			Button btn = sender as Button;
+			if (btn != null)
+				broker.handle_key_action(btn.Content.ToString()[0]);
+			PhonePadButton btn2 = sender as PhonePadButton;
+			if (btn2 != null)
+				broker.handle_key_action(btn2.Number[0]);
+
+		}
+
+		private void btnHold_Click(object sender, RoutedEventArgs e) {
+			if (Call.active_call != null)
+				Call.active_call.hold();
+		}
+
+		private void btnSendVoicemail_Click(object sender, RoutedEventArgs e) {
+			if (Call.active_call != null)
+				Call.active_call.SendToVoicemail();
+		}
+
+		private void btnTransfer_Click(object sender, RoutedEventArgs e) {
+			if (Call.active_call != null)
+				Call.active_call.TransferPrompt();
+
+
+		}
+		#region ContactSearchBox
+		public OurAutoCompleteBox GetContactSearchBox() {
+			return txtSearchBox;
+		}
+
+		private void txtSearchBox_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) {
+			text_interception_enabled = false;
+			txtSearchBox.Opacity = 1;
+			if (txtSearchBox.Text == "Contact Search")
+				txtSearchBox.Text = "";
+		}
+
+		private void txtSearchBox_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) {
+			text_interception_enabled = true;
+			txtSearchBox.Opacity = 0.8;
+
+			if (String.IsNullOrWhiteSpace(txtSearchBox.Text))
+				txtSearchBox.Text = "Contact Search";
+		}
+
+		private bool ContactMenuOpen;
+		private void contactSearchConextMenu_Closed(object sender, RoutedEventArgs e) {
+			ContactMenuOpen = false;
+			txtSearchBox.IsDropDownOpen = false;
+		}
+
+		private void contactSearchConextMenu_Loaded(object sender, RoutedEventArgs e) {
+			ContactMenuOpen = true;
+		}
+
+		private void txtSearchBox_DropDownClosing(object sender, RoutedPropertyChangingEventArgs<bool> e) {
+			if (ContactMenuOpen)
+				e.Cancel = true;
+		}
+		#endregion
+	}
+}
diff --git a/mitchcapper/FSClient/SimpleContactPluginBase.cs b/mitchcapper/FSClient/SimpleContactPluginBase.cs
index 6a92a79..bcf73d1 100644
--- a/mitchcapper/FSClient/SimpleContactPluginBase.cs
+++ b/mitchcapper/FSClient/SimpleContactPluginBase.cs
@@ -1,6 +1,10 @@
 using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
+using System.Linq;
+using System.Windows;
 using System.Windows.Controls;
+using System.Windows.Input;
+using FSClient.Controls;
 
 namespace FSClient
 {
@@ -8,9 +12,9 @@ namespace FSClient
 	{
 		protected abstract void _TryResolveNewNumber(string number, NumberResolved on_resolved);
 		protected abstract void LoadDatabase(ref Dictionary<string, string> number_to_alias_db);
-		protected abstract void UpdateDatabase(string number, string alias);
-
-
+		protected abstract void UpdateDatabase(string number, string alias);
+
+
 		protected virtual void ModifyRightClickMenu(Call call, ContextMenu menu)
 		{
 			return;
@@ -30,26 +34,65 @@ namespace FSClient
 			return "";
 		}
 
-		protected Dictionary<string, string> number_to_alias = new Dictionary<string, string>();
-
+		protected Dictionary<string, string> number_to_alias = new Dictionary<string, string>();
+
 		public override void CallRightClickMenu(Call call, ContextMenu menu) {
 			MenuItem item = new MenuItem();
 			item.Click += item_Click;
 			item.Header = "Edit Contact";
-			menu.Items.Add(item);
+			menu.Items.Add(item);
 			ModifyRightClickMenu(call, menu);
 		}
 
-		protected void item_Click(object sender, System.Windows.RoutedEventArgs e)
+		public override IEnumerable<MenuItem> ContactRightClickMenu(){
+			List<MenuItem> items = new List<MenuItem>();
+			MenuItem item = new MenuItem();
+			item.Click += item_Click;
+			item.Header = "Edit Contact";
+			items.Add(item);
+			item = new MenuItem();
+			item.Click +=contact_call_click;
+			item.Header = "Call";
+			items.Add(item);
+			return items;
+		}
+
+		private void contact_call_click(object sender, RoutedEventArgs e){
+			MenuItem item = sender as MenuItem;
+			if (item == null)
+				return;
+
+			SearchAutoCompleteEntry entry = item.DataContext as SearchAutoCompleteEntry ?? search_box.SelectedItem as SearchAutoCompleteEntry;
+			if (entry == null)
+				return;
+			Broker.get_instance().DialString(entry.number);
+		}
+
+		protected void item_Click(object sender, RoutedEventArgs e)
 		{
 			MenuItem item = sender as MenuItem;
 			if (item == null)
 				return;
+			String number;
+			String default_edit_value;
+
 			Call c = item.DataContext as Call;
-			if (c == null)
-				return;
-			String number = NormalizeNumber(c.other_party_number);
-			String alias = InputBox.GetInput("Editing Contact", "Edit alias for number: " + number, DefaultEditValue(c));
+			if (c != null){
+				number = c.other_party_number;
+				default_edit_value = DefaultEditValue(c);
+			}
+			else{
+				SearchAutoCompleteEntry entry = item.DataContext as SearchAutoCompleteEntry ?? search_box.SelectedItem as SearchAutoCompleteEntry;
+
+				if (entry == null)
+					return;
+				number = entry.number;
+				default_edit_value = entry.alias;
+			}
+
+			String orig_number = number;
+			number = NormalizeNumber(number);
+			String alias = InputBox.GetInput("Editing Contact", "Edit alias for number: " + number, default_edit_value);
 			alias = IsValidAlias(alias);
 			if (alias == null)
 				return;
@@ -58,11 +101,12 @@ namespace FSClient
 
 			foreach (Call call in Call.calls)
 			{
-				if (c.other_party_number == call.other_party_number)
-					c.other_party_name = alias;
+				if (orig_number == call.other_party_number || number == call.other_party_number)
+					call.other_party_name = alias;
 			}
 
 			UpdateDatabase(number, alias);
+			refresh_search_box();
 		}
 		public override void ResolveNumber(string number, NumberResolved on_resolved)
 		{
@@ -78,8 +122,69 @@ namespace FSClient
 		public override void Initialize()
 		{
 			LoadDatabase(ref number_to_alias);
+	
+			refresh_search_box();
+		}
+		protected void refresh_search_box(){
+			if (search_box == null)
+				return;
+			search_box.ItemsSource = from c in number_to_alias select new SearchAutoCompleteEntry(c.Key,c.Value);
+		}
+		protected class SearchAutoCompleteEntry{
+			public string number;
+			public string alias;
+			public string display_name;
+			public SearchAutoCompleteEntry(String number, String alias){
+				this.number = number;
+				this.alias = alias;
+				if (String.IsNullOrWhiteSpace(alias) || number == alias)
+					display_name = number;
+				else
+					display_name = alias + " - " + number;
+			}
+			public override string ToString(){
+				return display_name;
+			}
+		}
+		protected void search_box_PreviewKeyUp(object sender, KeyEventArgs e){
+			if (e.Key == Key.Enter){
+				call_current_contact();
+			}
+		}
 
+		protected OurAutoCompleteBox search_box;
+		private TextBox real_search_box;
+		public override bool HandleSearchBox(OurAutoCompleteBox box) {
+			search_box = box;
+
+			real_search_box = search_box.GetActualTextbox();
+			real_search_box.ContextMenu = new ContextMenu();
+			real_search_box.ContextMenuOpening += search_box_ContextMenuOpening;
+			
+			foreach (MenuItem item in ContactRightClickMenu()){
+				real_search_box.ContextMenu.Items.Add(item);
+			}
+			
+			search_box.PreviewKeyUp += search_box_PreviewKeyUp;
+			search_box.MouseDoubleClick += search_box_MouseDoubleClick;
+			if (number_to_alias.Count > 0)
+				refresh_search_box();
+			return true;
+		}
+		protected void call_current_contact(){
+			SearchAutoCompleteEntry entry = search_box.SelectedItem as SearchAutoCompleteEntry;
+			if (entry != null)
+				Broker.get_instance().DialString(entry.number);
+		}
+		void search_box_MouseDoubleClick(object sender, MouseButtonEventArgs e){
+			call_current_contact();
 		}
 
+		void search_box_ContextMenuOpening(object sender, ContextMenuEventArgs e){
+			if (search_box.SelectedItem == null)
+				real_search_box.ContextMenu.Visibility = Visibility.Hidden;
+			else
+				real_search_box.ContextMenu.Visibility = Visibility.Visible;
+		}
 	}
 }

-----------------------------------------------------------------------

Summary of changes:
 mitchcapper/FSClient/Broker.cs                     |   57 +-
 .../FSClient/Controls/OurAutoCompleteBox.cs        |   32 +
 mitchcapper/FSClient/FSClient.csproj               |    5 +
 mitchcapper/FSClient/IContactPlugin.cs             |   48 +-
 mitchcapper/FSClient/MainWindow.xaml               |   22 +-
 mitchcapper/FSClient/MainWindow.xaml.cs            |  850 +++++++++++---------
 mitchcapper/FSClient/SimpleContactPluginBase.cs    |  133 +++-
 7 files changed, 698 insertions(+), 449 deletions(-)
 create mode 100644 mitchcapper/FSClient/Controls/OurAutoCompleteBox.cs


hooks/post-receive
-- 
FreeSWITCH user-contributed scripts, etc



More information about the Freeswitch-trunk mailing list