提交 c10fc85f authored 作者: Mitch Capper's avatar Mitch Capper

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.....
上级 f2269751
......@@ -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();
......
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();
}
}
}
......@@ -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>
......
......@@ -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);
}
}
<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>
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;
}
}
}
Markdown 格式
0% 或
您添加了 0 人 到此讨论。请谨慎行事。
请先完成此评论的编辑!
请 注册 或者 后发表评论