From cafc939a4ff700aa974b3efd36381c148a600c99 Mon Sep 17 00:00:00 2001 From: Gergo F Date: Sat, 30 Jul 2016 11:58:08 +0100 Subject: [PATCH 01/60] Fix: Some older ZNC might cause nullexception on self introduction --- Floe.Net/Irc/IrcSession.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/Floe.Net/Irc/IrcSession.cs b/Floe.Net/Irc/IrcSession.cs index 388b702..88a4b39 100644 --- a/Floe.Net/Irc/IrcSession.cs +++ b/Floe.Net/Irc/IrcSession.cs @@ -953,11 +953,15 @@ private void OnJoin(IrcMessage message) { var handler = this.Joined; var e = new IrcJoinEventArgs(message); - if (this.IsSelf(e.Who.Nickname)) - { - handler = this.SelfJoined; - } - this.RaiseEvent(handler, e); + if (e.Who == null) + { + handler = this.SelfJoined; + } + else if (this.IsSelf(e.Who.Nickname)) + { + handler = this.SelfJoined; + } + this.RaiseEvent(handler, e); } private void OnPart(IrcMessage message) From edd80d5bce1cbdeeedffa7fd70c7b0a8e0cb8331 Mon Sep 17 00:00:00 2001 From: Gergo F Date: Sat, 30 Jul 2016 12:01:30 +0100 Subject: [PATCH 02/60] Unfortunately I met server who doesn't accept : colon before the server password --- Floe.Net/Irc/IrcMessage.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Floe.Net/Irc/IrcMessage.cs b/Floe.Net/Irc/IrcMessage.cs index dc5b032..d7c26c1 100644 --- a/Floe.Net/Irc/IrcMessage.cs +++ b/Floe.Net/Irc/IrcMessage.cs @@ -78,7 +78,7 @@ public override string ToString() } sb.Append(' '); - if (i == this.Parameters.Count - 1) + if ((i == this.Parameters.Count - 1) && (this.Command != "PASS")) sb.Append(':'); sb.Append(this.Parameters[i]); } From 86aa977cd93bfab28479d0134c7e2091c9ad6d1b Mon Sep 17 00:00:00 2001 From: Gergo F Date: Sat, 30 Jul 2016 12:04:21 +0100 Subject: [PATCH 03/60] Showing user's full address on quit is good --- Floe.UI/ChatControl/ChatControl_Events.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Floe.UI/ChatControl/ChatControl_Events.cs b/Floe.UI/ChatControl/ChatControl_Events.cs index 4dc5303..a03deeb 100644 --- a/Floe.UI/ChatControl/ChatControl_Events.cs +++ b/Floe.UI/ChatControl/ChatControl_Events.cs @@ -457,7 +457,8 @@ private void Session_UserQuit(object sender, IrcQuitEventArgs e) { if (!isIgnored) { - this.Write("Quit", e.Message.Time, string.Format("{0} has quit ({1})", e.Who.Nickname, e.Text)); + this.Write("Quit", e.Message.Time, string.Format("{0} ({1}@{2}) has quit ({3})", + e.Who.Nickname, e.Who.Username, e.Who.Hostname, e.Text)); } _nickList.Remove(e.Who.Nickname); } From 32e9cc7290aad850304f699782d975a406c39090 Mon Sep 17 00:00:00 2001 From: Seven-7 Date: Mon, 6 Feb 2017 15:04:55 +0000 Subject: [PATCH 04/60] Minor adjustments and fixes --- Floe.Net/Irc/IrcTarget.cs | 5 ++++- Floe.UI/ChatControl/ChatControl.xaml.cs | 2 +- Floe.UI/ChatControl/ChatControl_Commands.cs | 2 ++ Floe.UI/ChatControl/ChatControl_Events.cs | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Floe.Net/Irc/IrcTarget.cs b/Floe.Net/Irc/IrcTarget.cs index 486cf3d..67e3433 100644 --- a/Floe.Net/Irc/IrcTarget.cs +++ b/Floe.Net/Irc/IrcTarget.cs @@ -65,7 +65,10 @@ public override string ToString() /// Returns true if the name refers to a channel, false if it refers to a user. public static bool IsChannelName(string name) { - return name.Length > 1 && name[0] == '#' || name[0] == '+' || name[0] == '&' || name[0] == '!'; + if (name.Length < 1) + return false; + else + return name[0] == '#' || name[0] == '+' || name[0] == '&' || name[0] == '!'; } /// diff --git a/Floe.UI/ChatControl/ChatControl.xaml.cs b/Floe.UI/ChatControl/ChatControl.xaml.cs index cefb80a..4a7836b 100644 --- a/Floe.UI/ChatControl/ChatControl.xaml.cs +++ b/Floe.UI/ChatControl/ChatControl.xaml.cs @@ -24,7 +24,7 @@ public CommandException(string message) #endregion - private const double MinNickListWidth = 50.0; + private const double MinNickListWidth = 100.0; private LinkedList _history; private LinkedListNode _historyNode; diff --git a/Floe.UI/ChatControl/ChatControl_Commands.cs b/Floe.UI/ChatControl/ChatControl_Commands.cs index 792c2b9..5ea20e2 100644 --- a/Floe.UI/ChatControl/ChatControl_Commands.cs +++ b/Floe.UI/ChatControl/ChatControl_Commands.cs @@ -371,6 +371,7 @@ private void Execute(string command, string arguments) this.Session.Nick(args[0]); break; case "NOTICE": + case "N": args = Split(command, arguments, 2, 2); this.Session.Notice(new IrcTarget(args[0]), args[1]); break; @@ -387,6 +388,7 @@ private void Execute(string command, string arguments) } break; case "PART": + case "P": case "LEAVE": args = Split(command, arguments, 1, 1, true); this.Session.Part(args[0]); diff --git a/Floe.UI/ChatControl/ChatControl_Events.cs b/Floe.UI/ChatControl/ChatControl_Events.cs index a03deeb..4b0fa3c 100644 --- a/Floe.UI/ChatControl/ChatControl_Events.cs +++ b/Floe.UI/ChatControl/ChatControl_Events.cs @@ -470,7 +470,7 @@ private void Session_ChannelModeChanged(object sender, IrcChannelModeEventArgs e { if (e.Who != null) { - this.Write("Mode", e.Message.Time, string.Format("{0} set mode: {1}", e.Who.Nickname, + this.Write("Mode", e.Message.Time, string.Format("{0} sets mode: {1}", e.Who.Nickname, string.Join(" ", IrcChannelMode.RenderModes(e.Modes)))); _channelModes = (from m in e.Modes.Where((newMode) => newMode.Parameter == null && newMode.Set). From d6904d808a3eba7b0609bbf8a912b956450dbfb2 Mon Sep 17 00:00:00 2001 From: Seven-7 Date: Tue, 7 Feb 2017 16:54:40 +0000 Subject: [PATCH 05/60] A more acceptable notice, part and /hop with message --- Floe.Net/Irc/IrcSession.cs | 10 ++++ Floe.UI/ChatControl/ChatControl_Commands.cs | 21 +++++++- Floe.UI/ChatControl/ChatControl_Events.cs | 60 ++++++++++++--------- 3 files changed, 63 insertions(+), 28 deletions(-) diff --git a/Floe.Net/Irc/IrcSession.cs b/Floe.Net/Irc/IrcSession.cs index 88a4b39..472784e 100644 --- a/Floe.Net/Irc/IrcSession.cs +++ b/Floe.Net/Irc/IrcSession.cs @@ -469,6 +469,16 @@ public void Part(string channel) this.Send("PART", channel); } + /// + /// Part (leave) a channel with message. + /// + /// The channel to leave. + /// The optional part message. + public void Part(string channel, string text) + { + this.Send("PART", channel, text); + } + /// /// Change the topic on a channel. The session must have the appropriate permissions on the channel. /// diff --git a/Floe.UI/ChatControl/ChatControl_Commands.cs b/Floe.UI/ChatControl/ChatControl_Commands.cs index 5ea20e2..a4a26ec 100644 --- a/Floe.UI/ChatControl/ChatControl_Commands.cs +++ b/Floe.UI/ChatControl/ChatControl_Commands.cs @@ -390,8 +390,15 @@ private void Execute(string command, string arguments) case "PART": case "P": case "LEAVE": - args = Split(command, arguments, 1, 1, true); - this.Session.Part(args[0]); + args = Split(command, arguments, 1, 2, true); + if (args.Length == 2) + { + this.Session.Part(args[0], args[1]); + } + else + { + this.Session.Part(args[0]); + } break; case "TOPIC": args = Split(command, arguments, 1, 2, true); @@ -404,6 +411,16 @@ private void Execute(string command, string arguments) this.Session.Topic(args[0]); } break; + case "HOP": + case "CYCLE": + case "CY": + args = Split(command, arguments, 1, 2, true); + if (args.Length == 2) + this.Session.Part(args[0], args[1]); + else + this.Session.Part(args[0]); + this.Session.Join(args[0]); + break; case "INVITE": args = Split(command, arguments, 2, 2); this.Session.Invite(args[1], args[0]); diff --git a/Floe.UI/ChatControl/ChatControl_Events.cs b/Floe.UI/ChatControl/ChatControl_Events.cs index 4b0fa3c..178139a 100644 --- a/Floe.UI/ChatControl/ChatControl_Events.cs +++ b/Floe.UI/ChatControl/ChatControl_Events.cs @@ -57,28 +57,28 @@ private void Session_ConnectionError(object sender, ErrorEventArgs e) } } - private void Session_Noticed(object sender, IrcMessageEventArgs e) - { - if (App.IsIgnoreMatch(e.From, IgnoreActions.Notice)) - { - return; - } - - if (this.IsServer) - { - if (e.From is IrcPeer) - { - this.Write("Notice", e.Message.Time, (IrcPeer)e.From, e.Text, false); - } - else if (this.IsServer) - { - this.Write("Notice", e.Message.Time, e.Text); - } - App.DoEvent("notice"); - } - } - - private void Session_PrivateMessaged(object sender, IrcMessageEventArgs e) + private void Session_Noticed(object sender, IrcMessageEventArgs e) + { + if (App.IsIgnoreMatch(e.From, IgnoreActions.Notice)) + { + return; + } + if ((this.IsServer) || (this.Target.IsChannel && this.Target.Equals(e.To)) + || (IsDefault && this.IsChannel && e.From != null && _nickList.Contains(e.From.Nickname))) + { + if (e.From is IrcPeer) + { + this.Write("Notice", e.Message.Time, (IrcPeer)e.From, e.Text, false); + } + else if (this.IsServer) + { + this.Write("Notice", e.Message.Time, e.Text); + } + } + App.DoEvent("notice"); + } + + private void Session_PrivateMessaged(object sender, IrcMessageEventArgs e) { if (App.IsIgnoreMatch(e.From, e.To.IsChannel ? IgnoreActions.Channel : IgnoreActions.Private)) { @@ -126,7 +126,7 @@ private void Session_PrivateMessaged(object sender, IrcMessageEventArgs e) window.setOverlayIcon(OverlayIconState.ChatActivity); } - if (e.From.Prefix.Equals("*buffextras!buffextras@znc.in")) + if (e.From != null && e.From.Prefix.Equals("*buffextras!buffextras@znc.in")) { int space = e.Text.IndexOf(' '); String subject = e.Text.Substring(0, space); @@ -395,9 +395,17 @@ private void Session_Parted(object sender, IrcPartEventArgs e) { if (!isIgnored) { - this.Write("Part", e.Message.Time, string.Format("{0} ({1}@{2}) has left channel {3}", - e.Who.Nickname, e.Who.Username, e.Who.Hostname, this.Target.ToString())); - } + if (string.IsNullOrEmpty(e.Text)) + { + this.Write("Part", e.Message.Time, string.Format("{0} ({1}@{2}) has left channel {3}", + e.Who.Nickname, e.Who.Username, e.Who.Hostname, this.Target.ToString())); + } + else + { + this.Write("Part", e.Message.Time, string.Format("{0} ({1}@{2}) has left channel {3} ({4})", + e.Who.Nickname, e.Who.Username, e.Who.Hostname, this.Target.ToString(), e.Text)); + } + } _nickList.Remove(e.Who.Nickname); } } From 20a892f70ddc703ed2a7a88f5441462da470d7db Mon Sep 17 00:00:00 2001 From: Seven-7 Date: Wed, 8 Feb 2017 20:41:45 +0000 Subject: [PATCH 06/60] Added ability to display correctly NOTICE and PRIVMSG originated from Server --- Floe.Net/Irc/IrcTarget.cs | 27 +++++++++++++++++++++++ Floe.UI/ChatControl/ChatControl.xaml.cs | 20 ++++++++++++++++- Floe.UI/ChatControl/ChatControl_Events.cs | 12 ++++++---- Floe.UI/ChatWindow/ChatWindow_Events.cs | 4 ++-- 4 files changed, 56 insertions(+), 7 deletions(-) diff --git a/Floe.Net/Irc/IrcTarget.cs b/Floe.Net/Irc/IrcTarget.cs index 67e3433..c954427 100644 --- a/Floe.Net/Irc/IrcTarget.cs +++ b/Floe.Net/Irc/IrcTarget.cs @@ -49,6 +49,33 @@ public IrcTarget(IrcPeer peer) this.Name = peer.Nickname; } + /// + /// Construct an IrcTarget from an IrcServer. This is useful when replying to a received message. + /// + /// + public IrcTarget(IrcServer peer) + { + this.IsChannel = false; + this.Name = peer.ServerName; + } + + /// + /// Construct an IrcTarget from an IrcPrefix. This is useful when replying to a received message. + /// + /// + public IrcTarget(IrcPrefix peer) + { + this.IsChannel = false; + if (peer is IrcPeer) + { + this.Name = new IrcPeer(peer.Prefix.ToString()).Nickname; + } + if (peer is IrcServer) + { + this.Name = new IrcServer(peer.Prefix.ToString()).ServerName; + } + } + /// /// Gets the name of the target. /// diff --git a/Floe.UI/ChatControl/ChatControl.xaml.cs b/Floe.UI/ChatControl/ChatControl.xaml.cs index 4a7836b..e9daa8b 100644 --- a/Floe.UI/ChatControl/ChatControl.xaml.cs +++ b/Floe.UI/ChatControl/ChatControl.xaml.cs @@ -231,7 +231,25 @@ private void Write(string styleKey, DateTime date, IrcPeer peer, string text, bo } } - private void Write(string styleKey, IrcPeer peer, string text, bool attn) + private void Write(string styleKey, DateTime date, IrcServer peer, string text, bool attn) + { + this.Write(styleKey, date, string.Format("{0}", peer.ServerName).GetHashCode(), + this.GetNickWithLevel(peer.ServerName), text, attn); + if (!boxOutput.IsAutoScrolling) + { + App.DoEvent("beep"); + } + } + + private void Write(string styleKey, DateTime date, IrcPrefix peer, string text, bool attn) + { + if (peer is IrcPeer) + this.Write(styleKey, date, (IrcPeer)peer, text, attn); + if (peer is IrcServer) + this.Write(styleKey, date, (IrcServer)peer, text, attn); + } + + private void Write(string styleKey, IrcPeer peer, string text, bool attn) { this.Write(styleKey, DateTime.Now, peer, text, attn); } diff --git a/Floe.UI/ChatControl/ChatControl_Events.cs b/Floe.UI/ChatControl/ChatControl_Events.cs index 178139a..b1109d7 100644 --- a/Floe.UI/ChatControl/ChatControl_Events.cs +++ b/Floe.UI/ChatControl/ChatControl_Events.cs @@ -70,6 +70,10 @@ private void Session_Noticed(object sender, IrcMessageEventArgs e) { this.Write("Notice", e.Message.Time, (IrcPeer)e.From, e.Text, false); } + else if (e.Message.From is IrcServer) + { + this.Write("Notice", e.Message.Time, (IrcServer)e.Message.From, e.Text, false); + } else if (this.IsServer) { this.Write("Notice", e.Message.Time, e.Text); @@ -88,7 +92,7 @@ private void Session_PrivateMessaged(object sender, IrcMessageEventArgs e) if (!this.IsServer) { if ((this.Target.IsChannel && this.Target.Equals(e.To)) || - (!this.Target.IsChannel && this.Target.Equals(new IrcTarget(e.From)) && !e.To.IsChannel)) + (!this.Target.IsChannel && this.Target.Equals(new IrcTarget(e.Message.From)) && !e.To.IsChannel)) { bool attn = false; if (App.IsAttentionMatch(this.Session.Nickname, e.Text)) @@ -168,13 +172,13 @@ private void Session_PrivateMessaged(object sender, IrcMessageEventArgs e) } else { - this.Write("Default", e.Message.Time, e.From, e.Text, attn); + this.Write("Default", e.Message.Time, e.Message.From, e.Text, attn); if (!this.Target.IsChannel) { - if (e.From.Prefix != _prefix) + if (e.Message.From.Prefix != _prefix) { - _prefix = e.From.Prefix; + _prefix = e.Message.From.Prefix; this.SetTitle(); } Interop.WindowHelper.FlashWindow(_window); diff --git a/Floe.UI/ChatWindow/ChatWindow_Events.cs b/Floe.UI/ChatWindow/ChatWindow_Events.cs index 476099b..22db4c8 100644 --- a/Floe.UI/ChatWindow/ChatWindow_Events.cs +++ b/Floe.UI/ChatWindow/ChatWindow_Events.cs @@ -114,9 +114,9 @@ private void session_RawMessageReceived(object sender, IrcEventArgs e) { return; } - if (!target.IsChannel && e.Message.From is IrcPeer) + if (!target.IsChannel/* && e.Message.From is IrcPeer*/) { - if (App.Create(sender as IrcSession, new IrcTarget((IrcPeer)e.Message.From), false) + if (App.Create(sender as IrcSession, new IrcTarget(e.Message.From), false) && _notifyIcon != null && _notifyIcon.IsVisible) { _notifyIcon.Show("IRC Message", string.Format("You received a message from {0}.", ((IrcPeer)e.Message.From).Nickname)); From 97bf6a12b0ac642d933dd456bf617149866cf883 Mon Sep 17 00:00:00 2001 From: Seven-7 Date: Sat, 11 Feb 2017 10:48:57 +0000 Subject: [PATCH 07/60] Added channelname completition --- Floe.UI/ChatControl/ChanNameComplete.cs | 88 +++++++++++++++++++ .../ChatControl/ChatControl_ChannelList.cs | 31 +++++++ Floe.UI/ChatControl/ChatControl_Events.cs | 6 +- Floe.UI/ChatControl/ChatControl_NickList.cs | 18 ++-- Floe.UI/ChatControl/NicknameComplete.cs | 15 ++-- Floe.UI/Floe.UI.csproj | 2 + 6 files changed, 147 insertions(+), 13 deletions(-) create mode 100644 Floe.UI/ChatControl/ChanNameComplete.cs create mode 100644 Floe.UI/ChatControl/ChatControl_ChannelList.cs diff --git a/Floe.UI/ChatControl/ChanNameComplete.cs b/Floe.UI/ChatControl/ChanNameComplete.cs new file mode 100644 index 0000000..a38338b --- /dev/null +++ b/Floe.UI/ChatControl/ChanNameComplete.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows.Controls; +using Floe.Net; + +namespace Floe.UI +{ + class ChanNameComplete + { + private string[] _chanCandidates; + private uint _tabCount; + private string _incompleteChan; + private int _incompleteChanStart; + private TextBox _txtInput; + private bool _chanAtBeginning; + + public ChanNameComplete(TextBox txtInput, string[] chanCandidates) + { + _tabCount = 0; + _txtInput = txtInput; + _incompleteChan = initialInputParse(); + if (IrcTarget.IsChannelName(_incompleteChan)) + { + _chanCandidates = (from n in chanCandidates + where n.StartsWith(_incompleteChan, StringComparison.InvariantCultureIgnoreCase) + orderby n.ToLowerInvariant() + select n).ToArray(); + } + } + public void getNextChan() + { + _tabCount++; + if (_chanCandidates == null || _chanCandidates.Length <= 0) + { + return; + } + + if (_tabCount > _chanCandidates.Length) + { + _tabCount = 1; + } + + string completeChan = _chanCandidates[_tabCount - 1]; + + if (_chanAtBeginning) + { + completeChan += ": "; + } + else + { + completeChan += " "; + } + + _txtInput.Text = _txtInput.Text.Substring(0, _incompleteChanStart) + completeChan; + _txtInput.CaretIndex = _txtInput.Text.Length; + return; + } + + private string initialInputParse() + { + int i = _txtInput.CaretIndex - 1; + char c = _txtInput.Text[i]; + while (c != ' ' && i > 0) + { + c = _txtInput.Text[--i]; + } + if (i == 0) + { + _chanAtBeginning = true; + _incompleteChanStart = 0; + } + else if (_txtInput.Text[i - 1] == ':') + { + _incompleteChanStart = i + 1; + _chanAtBeginning = true; + } + else + { + _incompleteChanStart = i + 1; + _chanAtBeginning = false; + } + return _txtInput.Text.Substring(_incompleteChanStart, _txtInput.CaretIndex - _incompleteChanStart); + } + + } +} diff --git a/Floe.UI/ChatControl/ChatControl_ChannelList.cs b/Floe.UI/ChatControl/ChatControl_ChannelList.cs new file mode 100644 index 0000000..246f5ad --- /dev/null +++ b/Floe.UI/ChatControl/ChatControl_ChannelList.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using Floe.Net; + +namespace Floe.UI +{ + public partial class ChatControl : ChatPage + { + private string[] _chanList; + private ChanNameComplete _channameComplete; + + private void DoChannelCompletion() + { + if (txtInput.CaretIndex == 0) + { + return; + } + if (_channameComplete == null) + { + _chanList = ((ChatWindow)_window).Items.Where((item) => item.IsVisible && item.Page.Session == this.Session && item.Page.Target != null && item.Page.Target.IsChannel).Select(p => p.Page.Target.Name).ToArray(); + _channameComplete = new ChanNameComplete(txtInput, _chanList); + } + + _channameComplete.getNextChan(); + } + } +} diff --git a/Floe.UI/ChatControl/ChatControl_Events.cs b/Floe.UI/ChatControl/ChatControl_Events.cs index b1109d7..b21ddd9 100644 --- a/Floe.UI/ChatControl/ChatControl_Events.cs +++ b/Floe.UI/ChatControl/ChatControl_Events.cs @@ -891,7 +891,8 @@ protected override void OnPreviewKeyDown(KeyEventArgs e) { tabHit = true; DoNickCompletion(); - } + DoChannelCompletion(); + } break; default: Keyboard.Focus(txtInput); @@ -902,7 +903,8 @@ protected override void OnPreviewKeyDown(KeyEventArgs e) if (tabHit != true) { _nicknameComplete = null; - } + _channameComplete = null; + } } else if (e.Key >= Key.A && e.Key <= Key.Z) { diff --git a/Floe.UI/ChatControl/ChatControl_NickList.cs b/Floe.UI/ChatControl/ChatControl_NickList.cs index 7238bb6..e61dceb 100644 --- a/Floe.UI/ChatControl/ChatControl_NickList.cs +++ b/Floe.UI/ChatControl/ChatControl_NickList.cs @@ -29,15 +29,23 @@ private string GetNickWithoutLevel(string nick) private void DoNickCompletion() { - if(txtInput.CaretIndex == 0) + if (txtInput.CaretIndex == 0) { return; } - if (_nicknameComplete == null) - { - _nicknameComplete = new NicknameComplete(txtInput, _nickList); - } + if (_nicknameComplete == null) + { + if (this.IsNickname) + { + NicknameList pnickList = new NicknameList(); + pnickList.Add(this.Session.Nickname); + pnickList.Add(this.Target.Name); + _nicknameComplete = new NicknameComplete(txtInput, pnickList); + } + else + _nicknameComplete = new NicknameComplete(txtInput, _nickList); + } _nicknameComplete.getNextNick(); } diff --git a/Floe.UI/ChatControl/NicknameComplete.cs b/Floe.UI/ChatControl/NicknameComplete.cs index 2082521..b67ae7c 100644 --- a/Floe.UI/ChatControl/NicknameComplete.cs +++ b/Floe.UI/ChatControl/NicknameComplete.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Text; using System.Windows.Controls; +using Floe.Net; namespace Floe.UI { @@ -20,17 +21,19 @@ public NicknameComplete(TextBox txtInput, NicknameList nickList) _tabCount = 0; _txtInput = txtInput; _incompleteNick = initialInputParse(); - _nickCandidates = (from n in nickList - where n.Nickname.StartsWith(_incompleteNick, StringComparison.InvariantCultureIgnoreCase) - orderby n.Nickname.ToLowerInvariant() - select n.Nickname).ToArray(); - + if (!IrcTarget.IsChannelName(_incompleteNick)) + { + _nickCandidates = (from n in nickList + where n.Nickname.StartsWith(_incompleteNick, StringComparison.InvariantCultureIgnoreCase) + orderby n.Nickname.ToLowerInvariant() + select n.Nickname).ToArray(); + } } public void getNextNick() { _tabCount++; - if (_nickCandidates.Length <= 0) + if (_nickCandidates == null || _nickCandidates.Length <= 0) { return; } diff --git a/Floe.UI/Floe.UI.csproj b/Floe.UI/Floe.UI.csproj index 2ee7bf7..31c5c49 100644 --- a/Floe.UI/Floe.UI.csproj +++ b/Floe.UI/Floe.UI.csproj @@ -125,9 +125,11 @@ + ChatControl.xaml + From efd0cc52d01661946b57efbfa054778e48a6aa21 Mon Sep 17 00:00:00 2001 From: Gergo F Date: Thu, 23 Feb 2017 21:44:17 +0000 Subject: [PATCH 08/60] Show in Title bar nicklist count and show correctly channel modes --- Floe.Net/Irc/IrcEventArgs.cs | 4 +- Floe.UI/ChatControl/ChatControl.xaml.cs | 12 +- Floe.UI/ChatControl/ChatControl_Events.cs | 130 +++++++++++++++++++--- Floe.UI/ChatControl/NicknameList.cs | 18 ++- 4 files changed, 141 insertions(+), 23 deletions(-) diff --git a/Floe.Net/Irc/IrcEventArgs.cs b/Floe.Net/Irc/IrcEventArgs.cs index 9b8c778..d9d0ce3 100644 --- a/Floe.Net/Irc/IrcEventArgs.cs +++ b/Floe.Net/Irc/IrcEventArgs.cs @@ -264,7 +264,7 @@ public sealed class IrcChannelModeEventArgs : IrcEventArgs /// /// Gets the user who performed the mode change. /// - public IrcPeer Who { get; private set; } + public IrcPrefix Who { get; private set; } /// /// Gets the channel on which the modes were changed. @@ -279,7 +279,7 @@ public sealed class IrcChannelModeEventArgs : IrcEventArgs internal IrcChannelModeEventArgs(IrcMessage message) : base(message) { - this.Who = message.From as IrcPeer; + this.Who = message.From; this.Channel = message.Parameters.Count > 0 ? new IrcTarget(message.Parameters[0]) : null; this.Modes = message.Parameters.Count > 1 ? IrcChannelMode.ParseModes(message.Parameters.Skip(1)) : null; } diff --git a/Floe.UI/ChatControl/ChatControl.xaml.cs b/Floe.UI/ChatControl/ChatControl.xaml.cs index e9daa8b..b71ab70 100644 --- a/Floe.UI/ChatControl/ChatControl.xaml.cs +++ b/Floe.UI/ChatControl/ChatControl.xaml.cs @@ -7,6 +7,7 @@ using System.Windows.Input; using Floe.Net; using System.Threading; +using System.Text; namespace Floe.UI { @@ -75,8 +76,11 @@ public ChatControl(ChatPageType type, IrcSession session, IrcTarget target) if (e.Message.Parameters.Count > 2 && this.Target.Equals(new IrcTarget(e.Message.Parameters[1]))) { - _channelModes = e.Message.Parameters[2].ToCharArray().Where((c) => c != '+').ToArray(); - this.SetTitle(); + string _chModes = e.Message.Parameters[2]; + for (int i = 3; i < e.Message.Parameters.Count; i++) + _chModes += " " + e.Message.Parameters[i]; + _channelModes = _chModes.ToCharArray().Where((c) => c != '+').ToArray(); + this.SetTitle(); } e.Handled = true; return true; @@ -298,8 +302,8 @@ private void SetTitle() default: if (this.Target.IsChannel) { - this.Title = string.Format("{0} - {1} ({2}) on {3} - {4} ({5}) - {6}", App.Product, this.Session.Nickname, - userModes, this.Session.NetworkName, this.Target.ToString(), channelModes, _topic); + this.Title = string.Format("{0} - {1} ({2}) on {3} - {4} ({5}) ({6}) - {7}", App.Product, this.Session.Nickname, + userModes, this.Session.NetworkName, this.Target.ToString(), _nickList.Count, channelModes, _topic); } else { diff --git a/Floe.UI/ChatControl/ChatControl_Events.cs b/Floe.UI/ChatControl/ChatControl_Events.cs index b21ddd9..66b7c20 100644 --- a/Floe.UI/ChatControl/ChatControl_Events.cs +++ b/Floe.UI/ChatControl/ChatControl_Events.cs @@ -5,6 +5,8 @@ using System.Windows.Input; using Floe.Net; using System.Windows.Documents; +using System.Text; +using System.Collections.Generic; namespace Floe.UI { @@ -482,19 +484,17 @@ private void Session_ChannelModeChanged(object sender, IrcChannelModeEventArgs e { if (e.Who != null) { - this.Write("Mode", e.Message.Time, string.Format("{0} sets mode: {1}", e.Who.Nickname, - string.Join(" ", IrcChannelMode.RenderModes(e.Modes)))); - - _channelModes = (from m in e.Modes.Where((newMode) => newMode.Parameter == null && newMode.Set). - Select((newMode) => newMode.Mode).Union(_channelModes).Distinct() - where !e.Modes.Any((newMode) => !newMode.Set && newMode.Mode == m) - select m).ToArray(); - } - else - { - _channelModes = (from m in e.Modes - where m.Set && m.Parameter == null - select m.Mode).ToArray(); + if (e.Who is IrcPeer) + { + this.Write("Mode", e.Message.Time, string.Format("{0} sets mode: {1}", new IrcPeer(e.Who.Prefix).Nickname, + string.Join(" ", IrcChannelMode.RenderModes(e.Modes)))); + } + if (e.Who is IrcServer) + { + this.Write("Mode", e.Message.Time, string.Format("{0} sets mode: {1}", new IrcServer(e.Who.Prefix).ServerName, + string.Join(" ", IrcChannelMode.RenderModes(e.Modes)))); + } + _channelModes = AssembleChannelModes(e).ToCharArray(); } this.SetTitle(); foreach (var mode in e.Modes) @@ -951,6 +951,8 @@ private void SubscribeEvents() DataObject.AddPastingHandler(txtInput, new DataObjectPastingEventHandler(txtInput_Pasting)); this.IsConnected = !(this.Session.State == IrcSessionState.Disconnected); + if (_nickList != null) + _nickList.NickListChanged += OnNickListChanged; } private void UnsubscribeEvents() @@ -978,6 +980,9 @@ private void UnsubscribeEvents() { _window.Deactivated -= new EventHandler(_window_Deactivated); } + + if (_nickList != null) + _nickList.NickListChanged -= OnNickListChanged; } private void PrepareContextMenus() @@ -1029,5 +1034,104 @@ private string FormatTimeSpan(string text) } return new TimeSpan(0, 0, seconds).ToString(); } + + public void OnNickListChanged(object source, EventArgs e) + { + this.SetTitle(); + } + + public string OrderChannelModes(string chanModes) + { + string resultModes = String.Empty; + if (chanModes.Contains('s')) + resultModes += 's'; + if (chanModes.Contains('p')) + resultModes += 'p'; + if (chanModes.Contains('m')) + resultModes += 'm'; + if (chanModes.Contains('t')) + resultModes += 't'; + if (chanModes.Contains('i')) + resultModes += 'i'; + if (chanModes.Contains('n')) + resultModes += 'n'; + if (chanModes.Contains('r')) + resultModes += 'r'; + if (chanModes.Contains('D')) + resultModes += 'D'; + if (chanModes.Contains('d')) + resultModes += 'd'; + if (chanModes.Contains('R')) + resultModes += 'R'; + if (chanModes.Contains('l')) + resultModes += 'l'; + if (chanModes.Contains('k')) + resultModes += 'k'; + if (string.IsNullOrWhiteSpace(resultModes) || string.IsNullOrEmpty(resultModes)) + resultModes = chanModes; + return resultModes; + } + + public string AssembleChannelModes(IrcChannelModeEventArgs chModes) + { + List StrChanModes = new List(new string(_channelModes).Split(' ').ToList()); + string _chanModes = StrChanModes[0]; + List modeParam = new List(); + if (StrChanModes.Count > 1) + modeParam = StrChanModes.Skip(1).ToList(); + StringBuilder sb = new StringBuilder(); + sb.Append(_chanModes); + foreach (IrcChannelMode mode in chModes.Modes) + { + switch (mode.Mode) + { + case 'O': + case 'o': + case 'v': + case 'h': + //case 'k': + //case 'l': + case 'b': + case 'e': + case 'I': + case 'f': + case 'j': + case 'q': + continue; + } + if (!_chanModes.Contains(mode.Mode) && mode.Set) + { + sb.Append(mode.Mode); + if (!string.IsNullOrWhiteSpace(mode.Parameter)) + { + if (mode.Mode == 'l') + modeParam.Insert(0, mode.Parameter); + else + modeParam.Add(mode.Parameter); + } + } + else if (_chanModes.Contains(mode.Mode) && !mode.Set) + { + sb.Remove(sb.ToString().IndexOf(mode.Mode), 1); + if (modeParam.Count > 0) + { + if (mode.Mode == 'l') + modeParam.RemoveAt(0); + if (mode.Mode == 'k') + { + if (modeParam.Count > 1) + modeParam.RemoveAt(1); + else + modeParam.RemoveAt(0); + } + } + } + } + sb = new StringBuilder(OrderChannelModes(sb.ToString())); + if (modeParam.Count > 0) + sb.Append(" ").Append(string.Join(" ", modeParam)); + _chanModes = sb.ToString(); + return _chanModes; + } } } diff --git a/Floe.UI/ChatControl/NicknameList.cs b/Floe.UI/ChatControl/NicknameList.cs index 083d426..945e5b0 100644 --- a/Floe.UI/ChatControl/NicknameList.cs +++ b/Floe.UI/ChatControl/NicknameList.cs @@ -12,6 +12,7 @@ namespace Floe.UI { public class NicknameList : KeyedCollection, INotifyCollectionChanged { + public EventHandler NickListChanged; public NicknameList() : base(StringComparer.OrdinalIgnoreCase) { @@ -26,14 +27,16 @@ public void AddRange(IEnumerable nicks) { this.Add(item); } - } + OnNickListChanged(this, null); + } - public void Add(string nick) + public void Add(string nick) { this.Add(new NicknameItem(nick)); - } + OnNickListChanged(this, null); + } - public void ChangeNick(string oldNick, string newNick) + public void ChangeNick(string oldNick, string newNick) { var item = this[oldNick]; if (item != null) @@ -117,7 +120,14 @@ private void OnCollectionChanged(NotifyCollectionChangedEventArgs args) if (handler != null) { handler(this, args); + OnNickListChanged(this, null); } } + + protected virtual void OnNickListChanged(object source, EventArgs e) + { + if (NickListChanged != null) + NickListChanged(this, null); + } } } From ce598099119de9020a54621f335239fb77049c43 Mon Sep 17 00:00:00 2001 From: Gergo F Date: Sun, 26 Feb 2017 00:56:54 +0000 Subject: [PATCH 09/60] Started to implement TreeView functionality --- Floe.UI/ChatWindow/ChatWindow.xaml | 99 ++++++++++++++--------- Floe.UI/ChatWindow/ChatWindow.xaml.cs | 24 +++++- Floe.UI/ChatWindow/ChatWindow_TreeView.cs | 36 +++++++++ Floe.UI/Floe.UI.csproj | 1 + 4 files changed, 121 insertions(+), 39 deletions(-) create mode 100644 Floe.UI/ChatWindow/ChatWindow_TreeView.cs diff --git a/Floe.UI/ChatWindow/ChatWindow.xaml b/Floe.UI/ChatWindow/ChatWindow.xaml index 3d05413..97b82b7 100644 --- a/Floe.UI/ChatWindow/ChatWindow.xaml +++ b/Floe.UI/ChatWindow/ChatWindow.xaml @@ -1,7 +1,7 @@  - - - + + + @@ -24,30 +24,30 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + @@ -61,8 +61,8 @@ M0,8 L8,8 M0,0 L8,0 L8,8 L0,8 L0,0 M0,1 L8,1 M3,4 L6,8 L10,0 - M25,120 L55,0 M60,120 L90,0 M20,40 H110 M15,75 H100 - M0,0 A3,3 180 0 1 5,5 A3,3 180 0 1 0,0 M5,5 L8,8 + M25,120 L55,0 M60,120 L90,0 M20,40 H110 M15,75 H100 + M0,0 A3,3 180 0 1 5,5 A3,3 180 0 1 0,0 M5,5 L8,8 M0,4 L8,8 8,0Z M0,0 L8,4 L0,8Z M0,0 L8,0 M0,2 L4,8 L8,2 @@ -150,14 +150,37 @@ + - + + + + + + + + + + + + + + +                     + + + + + + - + - + @@ -385,8 +408,8 @@ - - + + diff --git a/Floe.UI/ChatWindow/ChatWindow.xaml.cs b/Floe.UI/ChatWindow/ChatWindow.xaml.cs index 9117c71..dff7a8f 100644 --- a/Floe.UI/ChatWindow/ChatWindow.xaml.cs +++ b/Floe.UI/ChatWindow/ChatWindow.xaml.cs @@ -3,7 +3,6 @@ using System.Linq; using System.Windows; using System.Windows.Controls; - using Floe.Net; namespace Floe.UI @@ -11,15 +10,18 @@ namespace Floe.UI public partial class ChatWindow : Window { public ObservableCollection Items { get; private set; } + public ObservableCollection NetworkTreeViewList; public ChatControl ActiveControl { get { return tabsChat.SelectedContent as ChatControl; } } public ChatWindow() { this.Items = new ObservableCollection(); + this.NetworkTreeViewList = new ObservableCollection(); this.DataContext = this; InitializeComponent(); this.Loaded += new RoutedEventHandler(ChatWindow_Loaded); + chatTreeView.ItemsSource = NetworkTreeViewList; } public void AddPage(ChatPage page, bool switchToPage) @@ -30,6 +32,7 @@ public void AddPage(ChatPage page, bool switchToPage) { this.Items.Add(item); this.SubscribeEvents(page.Session); + this.NetworkTreeViewList.Add(new NetworkTreeViewItem(item.Page)); } else { @@ -41,6 +44,14 @@ public void AddPage(ChatPage page, bool switchToPage) break; } } + for (int i = this.NetworkTreeViewList.Count - 1; i >= 0; --i) + { + if (this.NetworkTreeViewList[i].Page.Session == page.Session) + { + this.NetworkTreeViewList[i].ChannelItems.Add(new ChannelTreeViewItem(item.Page)); + break; + } + } } if (switchToPage) { @@ -61,6 +72,17 @@ public void RemovePage(ChatPage page) } page.Dispose(); this.Items.Remove(this.Items.Where((i) => i.Page == page).FirstOrDefault()); + if (page.Type == ChatPageType.Server) + { + this.NetworkTreeViewList.Remove(NetworkTreeViewList.Where(tr => tr.Page == page).FirstOrDefault()); + } + else + { + foreach (var nitem in this.NetworkTreeViewList) + { + nitem.ChannelItems.Remove(nitem.ChannelItems.Where(c => c.Page == page).FirstOrDefault()); + } + } } public void SwitchToPage(ChatPage page) diff --git a/Floe.UI/ChatWindow/ChatWindow_TreeView.cs b/Floe.UI/ChatWindow/ChatWindow_TreeView.cs new file mode 100644 index 0000000..88abc34 --- /dev/null +++ b/Floe.UI/ChatWindow/ChatWindow_TreeView.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Collections.ObjectModel; +using Floe.Net; + +namespace Floe.UI +{ + public class NetworkTreeViewItem + { + public ChatPage Page { get; private set; } + public string NetworkName { get { return Page.Header == null ? "Not loaded" : Page.Header; } } + + public NetworkTreeViewItem(ChatPage page) + { + this.Page = page; + ChannelItems = new ObservableCollection(); + } + + public ObservableCollection ChannelItems { get; set; } + } + + public class ChannelTreeViewItem + { + public ChatPage Page { get; private set; } + public string ChannelName { get { return Page.Target.Name; } } + + public ChannelTreeViewItem(ChatPage page) + { + this.Page = page; + } + } +} diff --git a/Floe.UI/Floe.UI.csproj b/Floe.UI/Floe.UI.csproj index 31c5c49..729c47a 100644 --- a/Floe.UI/Floe.UI.csproj +++ b/Floe.UI/Floe.UI.csproj @@ -147,6 +147,7 @@ ChatWindow.xaml + From a95e23a8ab202396278ede89379b68b6e5976306 Mon Sep 17 00:00:00 2001 From: Gergo F Date: Sun, 26 Feb 2017 10:52:35 +0000 Subject: [PATCH 10/60] Change selected Tab on TreeeView SelectedItemChanged --- Floe.UI/ChatWindow/ChatWindow.xaml.cs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/Floe.UI/ChatWindow/ChatWindow.xaml.cs b/Floe.UI/ChatWindow/ChatWindow.xaml.cs index dff7a8f..67a8e9f 100644 --- a/Floe.UI/ChatWindow/ChatWindow.xaml.cs +++ b/Floe.UI/ChatWindow/ChatWindow.xaml.cs @@ -22,6 +22,19 @@ public ChatWindow() this.Loaded += new RoutedEventHandler(ChatWindow_Loaded); chatTreeView.ItemsSource = NetworkTreeViewList; + chatTreeView.SelectedItemChanged += ChatTreeView_SelectedItemChanged; + } + + private void ChatTreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs e) + { + if (e.NewValue is NetworkTreeViewItem) + { + SwitchToPage(((NetworkTreeViewItem)e.NewValue).Page); + } + if (e.NewValue is ChannelTreeViewItem) + { + SwitchToPage(((ChannelTreeViewItem)e.NewValue).Page); + } } public void AddPage(ChatPage page, bool switchToPage) @@ -87,7 +100,15 @@ public void RemovePage(ChatPage page) public void SwitchToPage(ChatPage page) { - var index = this.Items.Where((tab) => tab.Page == page).Select((t,i) => i).FirstOrDefault(); + var index = this.Items.Where((tab) => tab.Page == page).Select((t, i) => i).FirstOrDefault(); + if (index == 0) + { + foreach (var tbItem in this.Items) + { + if (tbItem.Page.Session == page.Session && tbItem.Page.Target == page.Target) + index = this.Items.IndexOf(tbItem); + } + } tabsChat.SelectedIndex = index; } From 4d9dd829e2fe9d2a31010121f008739f27e02ab4 Mon Sep 17 00:00:00 2001 From: Gergo F Date: Sun, 26 Feb 2017 11:44:26 +0000 Subject: [PATCH 11/60] First channelname on channel-completion is the actual active channelname --- Floe.UI/ChatControl/ChanNameComplete.cs | 1 - Floe.UI/ChatControl/ChatControl_ChannelList.cs | 9 +++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Floe.UI/ChatControl/ChanNameComplete.cs b/Floe.UI/ChatControl/ChanNameComplete.cs index a38338b..17ee9ef 100644 --- a/Floe.UI/ChatControl/ChanNameComplete.cs +++ b/Floe.UI/ChatControl/ChanNameComplete.cs @@ -25,7 +25,6 @@ public ChanNameComplete(TextBox txtInput, string[] chanCandidates) { _chanCandidates = (from n in chanCandidates where n.StartsWith(_incompleteChan, StringComparison.InvariantCultureIgnoreCase) - orderby n.ToLowerInvariant() select n).ToArray(); } } diff --git a/Floe.UI/ChatControl/ChatControl_ChannelList.cs b/Floe.UI/ChatControl/ChatControl_ChannelList.cs index 246f5ad..e262c4b 100644 --- a/Floe.UI/ChatControl/ChatControl_ChannelList.cs +++ b/Floe.UI/ChatControl/ChatControl_ChannelList.cs @@ -13,6 +13,14 @@ public partial class ChatControl : ChatPage private string[] _chanList; private ChanNameComplete _channameComplete; + private void SwapFirst() + { + string _firstChan = ((ChatWindow)_window).Items.Where((item) => item.IsSelected).Select(p => p.Page.Target.Name).FirstOrDefault(); + int index = Array.IndexOf(_chanList, _firstChan); + _chanList[index] = _chanList[0]; + _chanList[0] = _firstChan; + } + private void DoChannelCompletion() { if (txtInput.CaretIndex == 0) @@ -22,6 +30,7 @@ private void DoChannelCompletion() if (_channameComplete == null) { _chanList = ((ChatWindow)_window).Items.Where((item) => item.IsVisible && item.Page.Session == this.Session && item.Page.Target != null && item.Page.Target.IsChannel).Select(p => p.Page.Target.Name).ToArray(); + SwapFirst(); _channameComplete = new ChanNameComplete(txtInput, _chanList); } From f86c3f60fb9a831e87c04ee4aad86a4bfcc47453 Mon Sep 17 00:00:00 2001 From: Gergo F Date: Sun, 26 Feb 2017 19:00:33 +0000 Subject: [PATCH 12/60] Properly update New Server Tab's Networkname on connection --- Floe.UI/ChatWindow/ChatWindow.xaml | 2 +- Floe.UI/ChatWindow/ChatWindow_TreeView.cs | 77 ++++++++++++++++------- 2 files changed, 54 insertions(+), 25 deletions(-) diff --git a/Floe.UI/ChatWindow/ChatWindow.xaml b/Floe.UI/ChatWindow/ChatWindow.xaml index 97b82b7..e1d3689 100644 --- a/Floe.UI/ChatWindow/ChatWindow.xaml +++ b/Floe.UI/ChatWindow/ChatWindow.xaml @@ -165,7 +165,7 @@ - + diff --git a/Floe.UI/ChatWindow/ChatWindow_TreeView.cs b/Floe.UI/ChatWindow/ChatWindow_TreeView.cs index 88abc34..2ffb228 100644 --- a/Floe.UI/ChatWindow/ChatWindow_TreeView.cs +++ b/Floe.UI/ChatWindow/ChatWindow_TreeView.cs @@ -5,32 +5,61 @@ using System.Windows; using System.Windows.Controls; using System.Collections.ObjectModel; +using System.ComponentModel; using Floe.Net; namespace Floe.UI { - public class NetworkTreeViewItem - { - public ChatPage Page { get; private set; } - public string NetworkName { get { return Page.Header == null ? "Not loaded" : Page.Header; } } - - public NetworkTreeViewItem(ChatPage page) - { - this.Page = page; - ChannelItems = new ObservableCollection(); - } - - public ObservableCollection ChannelItems { get; set; } - } - - public class ChannelTreeViewItem - { - public ChatPage Page { get; private set; } - public string ChannelName { get { return Page.Target.Name; } } - - public ChannelTreeViewItem(ChatPage page) - { - this.Page = page; - } - } + public class NetworkTreeViewItem : INotifyPropertyChanged + { + public ChatPage Page { get; private set; } + public string NetworkName + { + get + { + return Page.Header == null ? "Not loaded" : Page.Header; + } + private set + { + OnPropertyChanged("NetworkName"); + } + } + + public NetworkTreeViewItem(ChatPage page) + { + this.Page = page; + this.Page.Session.StateChanged += Session_StateChanged; + ChannelItems = new ObservableCollection(); + } + + private void Session_StateChanged(object sender, EventArgs e) + { + this.NetworkName = Page.Header; + } + + public ObservableCollection ChannelItems { get; set; } + + public event PropertyChangedEventHandler PropertyChanged; + + public void OnPropertyChanged(string name) + { + var handler = this.PropertyChanged; + if (handler != null) + { + handler(this, new PropertyChangedEventArgs(name)); + } + } + + } + + public class ChannelTreeViewItem + { + public ChatPage Page { get; private set; } + public string ChannelName { get { return Page.Target.Name; } } + + public ChannelTreeViewItem(ChatPage page) + { + this.Page = page; + } + } } From 3fee3f63835ae8166dfc42423b6fe49956b2abe2 Mon Sep 17 00:00:00 2001 From: Gergo F Date: Tue, 28 Feb 2017 23:13:20 +0000 Subject: [PATCH 13/60] Adjusted default config values --- Floe.Configuration/ColorsElement.cs | 40 +++++++++++------------ Floe.Configuration/FormattingElement.cs | 32 +++++++++--------- Floe.Configuration/WindowsElement.cs | 4 +-- Floe.UI/ChatWindow/ChatWindow_TreeView.cs | 1 - 4 files changed, 38 insertions(+), 39 deletions(-) diff --git a/Floe.Configuration/ColorsElement.cs b/Floe.Configuration/ColorsElement.cs index 4cabc10..d81787e 100644 --- a/Floe.Configuration/ColorsElement.cs +++ b/Floe.Configuration/ColorsElement.cs @@ -8,42 +8,42 @@ namespace Floe.Configuration { public class ColorsElement : ConfigurationElement, INotifyPropertyChanged { - [ConfigurationProperty("background", DefaultValue = "Black")] + [ConfigurationProperty("background", DefaultValue = "#FFC0C0C0")] public string Background { get { return (string)this["background"]; } set { this["background"] = value; OnPropertyChanged("Background"); } } - [ConfigurationProperty("editBackground", DefaultValue = "Black")] + [ConfigurationProperty("editBackground", DefaultValue = "#FFC0C0C0")] public string EditBackground { get { return (string)this["editBackground"]; } set { this["editBackground"] = value; OnPropertyChanged("EditBackground"); } } - [ConfigurationProperty("edit", DefaultValue = "White")] + [ConfigurationProperty("edit", DefaultValue = "#FFC0C0C0")] public string Edit { get { return (string)this["edit"]; } set { this["edit"] = value; OnPropertyChanged("Edit"); } } - [ConfigurationProperty("default", DefaultValue = "White")] + [ConfigurationProperty("default", DefaultValue = "#FF000000")] public string Default { get { return (string)this["default"]; } set { this["default"] = value; OnPropertyChanged("Default"); } } - [ConfigurationProperty("action", DefaultValue = "White")] + [ConfigurationProperty("action", DefaultValue = "#FFFF00FF")] public string Action { get { return (string)this["action"]; } set { this["action"] = value; OnPropertyChanged("Action"); } } - [ConfigurationProperty("ctcp", DefaultValue = "Yellow")] + [ConfigurationProperty("ctcp", DefaultValue = "#FF00FF00")] public string Ctcp { get { return (string)this["ctcp"]; } @@ -57,70 +57,70 @@ public string Info set { this["info"] = value; OnPropertyChanged("Info"); } } - [ConfigurationProperty("invite", DefaultValue = "Yellow")] + [ConfigurationProperty("invite", DefaultValue = "#FF00FF00")] public string Invite { get { return (string)this["invite"]; } set { this["invite"] = value; OnPropertyChanged("Invite"); } } - [ConfigurationProperty("join", DefaultValue = "Lavender")] + [ConfigurationProperty("join", DefaultValue = "#FF008000")] public string Join { get { return (string)this["join"]; } set { this["join"] = value; OnPropertyChanged("Join"); } } - [ConfigurationProperty("kick", DefaultValue = "Lavender")] + [ConfigurationProperty("kick", DefaultValue = "#FF008000")] public string Kick { get { return (string)this["kick"]; } set { this["kick"] = value; OnPropertyChanged("Kick"); } } - [ConfigurationProperty("mode", DefaultValue = "Yellow")] + [ConfigurationProperty("mode", DefaultValue = "#FF008000")] public string Mode { get { return (string)this["mode"]; } set { this["mode"] = value; OnPropertyChanged("Mode"); } } - [ConfigurationProperty("nick", DefaultValue = "Yellow")] + [ConfigurationProperty("nick", DefaultValue = "#FF008000")] public string Nick { get { return (string)this["nick"]; } set { this["nick"] = value; OnPropertyChanged("Nick"); } } - [ConfigurationProperty("notice", DefaultValue = "Yellow")] + [ConfigurationProperty("notice", DefaultValue = "#FF800000")] public string Notice { get { return (string)this["notice"]; } set { this["notice"] = value; OnPropertyChanged("Notice"); } } - [ConfigurationProperty("own", DefaultValue = "Gray")] + [ConfigurationProperty("own", DefaultValue = "#FF000000")] public string Own { get { return (string)this["own"]; } set { this["own"] = value; OnPropertyChanged("Own"); } } - [ConfigurationProperty("part", DefaultValue = "Lavender")] + [ConfigurationProperty("part", DefaultValue = "#FF008000")] public string Part { get { return (string)this["part"]; } set { this["part"] = value; OnPropertyChanged("Part"); } } - [ConfigurationProperty("quit", DefaultValue = "Lavender")] + [ConfigurationProperty("quit", DefaultValue = "#FF0000A0")] public string Quit { get { return (string)this["quit"]; } set { this["quit"] = value; OnPropertyChanged("Quit"); } } - [ConfigurationProperty("topic", DefaultValue = "Yellow")] + [ConfigurationProperty("topic", DefaultValue = "#FF008000")] public string Topic { get { return (string)this["topic"]; } @@ -148,7 +148,7 @@ public string OldMarker set { this["oldMarker"] = value; OnPropertyChanged("OldMarker"); } } - [ConfigurationProperty("attention", DefaultValue = "#404000")] + [ConfigurationProperty("attention", DefaultValue = "#FF00FF00")] public string Attention { get { return (string)this["attention"]; } @@ -176,21 +176,21 @@ public string Alert set { this["alertActivity"] = value; OnPropertyChanged("Alert"); } } - [ConfigurationProperty("windowBackground", DefaultValue = "#293955")] + [ConfigurationProperty("windowBackground", DefaultValue = "#FF293955")] public string WindowBackground { get { return (string)this["windowBackground"]; } set { this["windowBackground"] = value; OnPropertyChanged("WindowBackground"); } } - [ConfigurationProperty("windowForeground", DefaultValue = "White")] + [ConfigurationProperty("windowForeground", DefaultValue = "#FFFFFFFF")] public string WindowForeground { get { return (string)this["windowForeground"]; } set { this["windowForeground"] = value; OnPropertyChanged("WindowForeground"); } } - [ConfigurationProperty("highlight", DefaultValue = "#3399FF")] + [ConfigurationProperty("highlight", DefaultValue = "#FF00FFFF")] public string Highlight { get { return (string)this["highlight"]; } diff --git a/Floe.Configuration/FormattingElement.cs b/Floe.Configuration/FormattingElement.cs index 5d68a98..7f2b48e 100644 --- a/Floe.Configuration/FormattingElement.cs +++ b/Floe.Configuration/FormattingElement.cs @@ -65,14 +65,14 @@ public string TimestampFormat } } - [ConfigurationProperty("useTabularView", DefaultValue=true)] + [ConfigurationProperty("useTabularView", DefaultValue=false)] public bool UseTabularView { get { return (bool)this["useTabularView"]; } set { this["useTabularView"] = value; this.OnPropertyChanged("UseTabularView"); } } - [ConfigurationProperty("colorizeNicknames", DefaultValue = true)] + [ConfigurationProperty("colorizeNicknames", DefaultValue = false)] public bool ColorizeNicknames { get { return (bool)this["colorizeNicknames"]; } @@ -86,26 +86,26 @@ public int NicknameColorSeed set { this["nicknameColorSeed"] = value; this.OnPropertyChanged("NicknameColorSeed"); } } - [ConfigurationProperty("attentionOnOwnNickname", DefaultValue = false)] + [ConfigurationProperty("attentionOnOwnNickname", DefaultValue = true)] public bool AttentionOnOwnNickname { get { return (bool)this["attentionOnOwnNickname"]; } set { this["attentionOnOwnNickname"] = value; this.OnPropertyChanged("AttentionOnOwnNickname"); } } - [ConfigurationProperty("overlayIconOnChatActivity", DefaultValue = false)] - public bool OverlayIconOnChatActivity - { - get { return (bool)this["overlayIconOnChatActivity"]; } - set { this["overlayIconOnChatActivity"] = value; this.OnPropertyChanged("OverlayIconOnChatActivity"); } - } - - [ConfigurationProperty("overlayIconChangeColor", DefaultValue = false)] - public bool OverlayIconChangeColor - { - get { return (bool)this["overlayIconChangeColor"]; } - set { this["overlayIconChangeColor"] = value; this.OnPropertyChanged("OverlayIconChangeColor"); } - } + [ConfigurationProperty("overlayIconOnChatActivity", DefaultValue = false)] + public bool OverlayIconOnChatActivity + { + get { return (bool)this["overlayIconOnChatActivity"]; } + set { this["overlayIconOnChatActivity"] = value; this.OnPropertyChanged("OverlayIconOnChatActivity"); } + } + + [ConfigurationProperty("overlayIconChangeColor", DefaultValue = false)] + public bool OverlayIconChangeColor + { + get { return (bool)this["overlayIconChangeColor"]; } + set { this["overlayIconChangeColor"] = value; this.OnPropertyChanged("OverlayIconChangeColor"); } + } [ConfigurationProperty("attentionPatterns", DefaultValue = "")] public string AttentionPatterns diff --git a/Floe.Configuration/WindowsElement.cs b/Floe.Configuration/WindowsElement.cs index eed9d67..e12cbb7 100644 --- a/Floe.Configuration/WindowsElement.cs +++ b/Floe.Configuration/WindowsElement.cs @@ -41,7 +41,7 @@ public double ChromeOpacity set { this["chromeOpacity"] = value; this.OnPropertyChanged("ChromeOpacity"); } } - [ConfigurationProperty("backgroundOpacity", DefaultValue = 0.92)] + [ConfigurationProperty("backgroundOpacity", DefaultValue = 1.0)] public double BackgroundOpacity { get { return (double)this["backgroundOpacity"]; } @@ -55,7 +55,7 @@ public bool MinimizeToSysTray set { this["minimizeToSysTray"] = value; this.OnPropertyChanged("MinimizeToSysTray"); } } - [ConfigurationProperty("tabStripPosition", DefaultValue=TabStripPosition.Bottom)] + [ConfigurationProperty("tabStripPosition", DefaultValue=TabStripPosition.Top)] public TabStripPosition TabStripPosition { get { return (TabStripPosition)this["tabStripPosition"]; } diff --git a/Floe.UI/ChatWindow/ChatWindow_TreeView.cs b/Floe.UI/ChatWindow/ChatWindow_TreeView.cs index 2ffb228..a674b08 100644 --- a/Floe.UI/ChatWindow/ChatWindow_TreeView.cs +++ b/Floe.UI/ChatWindow/ChatWindow_TreeView.cs @@ -49,7 +49,6 @@ public void OnPropertyChanged(string name) handler(this, new PropertyChangedEventArgs(name)); } } - } public class ChannelTreeViewItem From 72294d109b12867f4de4346674c635bf68fba390 Mon Sep 17 00:00:00 2001 From: Gergo F Date: Thu, 2 Mar 2017 00:18:34 +0000 Subject: [PATCH 14/60] Quick fix: Window is DragMovable on Titlebar MouseDown --- Floe.UI/ChatWindow/ChatWindow.xaml | 2 +- Floe.UI/ChatWindow/ChatWindow.xaml.cs | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Floe.UI/ChatWindow/ChatWindow.xaml b/Floe.UI/ChatWindow/ChatWindow.xaml index e1d3689..1009a1c 100644 --- a/Floe.UI/ChatWindow/ChatWindow.xaml +++ b/Floe.UI/ChatWindow/ChatWindow.xaml @@ -177,7 +177,7 @@ - + diff --git a/Floe.UI/ChatWindow/ChatWindow.xaml.cs b/Floe.UI/ChatWindow/ChatWindow.xaml.cs index 67a8e9f..bd64008 100644 --- a/Floe.UI/ChatWindow/ChatWindow.xaml.cs +++ b/Floe.UI/ChatWindow/ChatWindow.xaml.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Windows; using System.Windows.Controls; +using System.Windows.Input; using Floe.Net; namespace Floe.UI @@ -152,5 +153,11 @@ private void QuitAllSessions() } } } + + private void Border_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e) + { + if (e.ChangedButton == MouseButton.Left) + this.DragMove(); + } } } From bace9cd28b33929c6a39551e9a7a71b76a23a817 Mon Sep 17 00:00:00 2001 From: Gergo F Date: Thu, 2 Mar 2017 13:19:01 +0000 Subject: [PATCH 15/60] Implemented Oper command --- Floe.Net/Irc/IrcSession.cs | 93 +++++++++++---------- Floe.UI/ChatControl/ChatControl_Commands.cs | 12 ++- 2 files changed, 59 insertions(+), 46 deletions(-) diff --git a/Floe.Net/Irc/IrcSession.cs b/Floe.Net/Irc/IrcSession.cs index 472784e..e32fc27 100644 --- a/Floe.Net/Irc/IrcSession.cs +++ b/Floe.Net/Irc/IrcSession.cs @@ -198,7 +198,7 @@ private set /// /// Fires when the topic of a channel has been changed. /// - public event EventHandler TopicChanged; + public event EventHandler TopicChanged; /// /// Fires when the session has been invited to a channel. @@ -391,6 +391,15 @@ public void Quote(string rawText) this.Send(new IrcMessage(rawText)); } + /// + /// Request an oper + /// + /// The optional command parameters. + public void Oper(params string[] parameters) + { + this.Send("OPER", parameters); + } + /// /// Change the nickname. /// @@ -897,9 +906,9 @@ private void OnMessageReceived(IrcEventArgs e) case "MODE": this.OnMode(e.Message); break; - case "CAP": - this.OnCap(e.Message); - break; + case "CAP": + this.OnCap(e.Message); + break; default: this.OnOther(e.Message); break; @@ -963,15 +972,15 @@ private void OnJoin(IrcMessage message) { var handler = this.Joined; var e = new IrcJoinEventArgs(message); - if (e.Who == null) - { - handler = this.SelfJoined; - } - else if (this.IsSelf(e.Who.Nickname)) - { - handler = this.SelfJoined; - } - this.RaiseEvent(handler, e); + if (e.Who == null) + { + handler = this.SelfJoined; + } + else if (this.IsSelf(e.Who.Nickname)) + { + handler = this.SelfJoined; + } + this.RaiseEvent(handler, e); } private void OnPart(IrcMessage message) @@ -1026,30 +1035,30 @@ private void OnMode(IrcMessage message) } } - // IRCv3 Client Capability Negotiation - private void OnCap(IrcMessage message) - { - if (message.Parameters.Count >= 2) - { - switch (message.Parameters[1].ToUpper()) - { - // RIGHT NOW WE DON'T CARE, we're just supporting one thing and ZNC 1.4 doesn't really - // follow the spec like I thought it would... - // We don't really even need to do anything about "ACK" but we might want to handle "NAK" - // in case ZNC 1.5 or whatever drops znc.in/server-time-iso in favor of server-time... - case "LS": // Server listed capabilities. END or REQ. - break; - case "ACK": // Server acknowledged. Turn it on. - break; - case "NAK": // Server rejected. Turn it off. - break; - case "LIST": // Server listed. Make sure we match? - break; - default: // Who cares? - break; - } - } - } + // IRCv3 Client Capability Negotiation + private void OnCap(IrcMessage message) + { + if (message.Parameters.Count >= 2) + { + switch (message.Parameters[1].ToUpper()) + { + // RIGHT NOW WE DON'T CARE, we're just supporting one thing and ZNC 1.4 doesn't really + // follow the spec like I thought it would... + // We don't really even need to do anything about "ACK" but we might want to handle "NAK" + // in case ZNC 1.5 or whatever drops znc.in/server-time-iso in favor of server-time... + case "LS": // Server listed capabilities. END or REQ. + break; + case "ACK": // Server acknowledged. Turn it on. + break; + case "NAK": // Server rejected. Turn it off. + break; + case "LIST": // Server listed. Make sure we match? + break; + default: // Who cares? + break; + } + } + } private void OnOther(IrcMessage message) { @@ -1116,10 +1125,10 @@ private void _conn_Connected(object sender, EventArgs e) Dns.GetHostEntry(string.Empty).AddressList .Where((ip) => ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork).FirstOrDefault(); - // IRCv3 Client Capability Negotiation - //_conn.QueueMessage(new IrcMessage("CAP", "LS")); - // NEGOTIATION? I MEANT A ONE-SIDED DEMAND. - _conn.QueueMessage(new IrcMessage("CAP", "REQ", "znc.in/server-time-iso")); + // IRCv3 Client Capability Negotiation + //_conn.QueueMessage(new IrcMessage("CAP", "LS")); + // NEGOTIATION? I MEANT A ONE-SIDED DEMAND. + _conn.QueueMessage(new IrcMessage("CAP", "REQ", "znc.in/server-time-iso")); if (!string.IsNullOrEmpty(_password)) { @@ -1145,6 +1154,6 @@ private void _conn_Heartbeat(object sender, EventArgs e) _isWaitingForActivity = true; this.Send("PING", this.Server); } - } + } } } diff --git a/Floe.UI/ChatControl/ChatControl_Commands.cs b/Floe.UI/ChatControl/ChatControl_Commands.cs index a4a26ec..1bd7cc5 100644 --- a/Floe.UI/ChatControl/ChatControl_Commands.cs +++ b/Floe.UI/ChatControl/ChatControl_Commands.cs @@ -357,10 +357,14 @@ private void Execute(string command, string arguments) switch (command) { - case "QUOTE": - args = Split(command, arguments, 1, 1); - this.Session.Quote(args[0]); - break; + case "QUOTE": + args = Split(command, arguments, 1, 1); + this.Session.Quote(args[0]); + break; + case "OPER": + args = Split(command, arguments, 1, 2); + this.Session.Oper(args); + break; case "QUIT": args = Split(command, arguments, 0, 1); this.Session.AutoReconnect = false; From 3bdf0c4b2ed4676498cf84adef74f134e2ac7539 Mon Sep 17 00:00:00 2001 From: Gergo F Date: Sat, 4 Mar 2017 16:55:27 +0000 Subject: [PATCH 16/60] TreeViewItems changes color according to NotifyState --- Floe.UI/ChatWindow/ChatPage.cs | 24 ++++- Floe.UI/ChatWindow/ChatWindow.xaml | 7 +- Floe.UI/ChatWindow/ChatWindow.xaml.cs | 109 +++++++++++++++++++++- Floe.UI/ChatWindow/ChatWindow_Events.cs | 10 +- Floe.UI/ChatWindow/ChatWindow_TreeView.cs | 89 +++++++++++++++++- 5 files changed, 228 insertions(+), 11 deletions(-) diff --git a/Floe.UI/ChatWindow/ChatPage.cs b/Floe.UI/ChatWindow/ChatPage.cs index 9d37c9a..1cf154b 100644 --- a/Floe.UI/ChatWindow/ChatPage.cs +++ b/Floe.UI/ChatWindow/ChatPage.cs @@ -59,13 +59,35 @@ public double Progress } public static readonly DependencyProperty NotifyStateProperty = - DependencyProperty.Register("NotifyState", typeof(NotifyState), typeof(ChatPage)); + DependencyProperty.Register("NotifyState", typeof(NotifyState), typeof(ChatPage), + new PropertyMetadata(OnNotifyStateChangedCallBack)); public NotifyState NotifyState { get { return (NotifyState)this.GetValue(NotifyStateProperty); } set { this.SetValue(NotifyStateProperty, value); } } + private static void OnNotifyStateChangedCallBack(DependencyObject sender, DependencyPropertyChangedEventArgs e) + { + ChatPage senderPage = sender as ChatPage; + var window = Window.GetWindow(senderPage); + if (window is ChatWindow) + { + ChatWindow chatwindow = (ChatWindow)window; + var treeItem = chatwindow.FindTreeViewItem(senderPage); + if (treeItem is NetworkTreeViewItem) + { + NetworkTreeViewItem ntreeItem = (NetworkTreeViewItem)treeItem; + ntreeItem.OnNotifyStateChanged(); + } + if (treeItem is ChannelTreeViewItem) + { + ChannelTreeViewItem ctreeItem = (ChannelTreeViewItem)treeItem; + ctreeItem.OnNotifyStateChanged(); + } + } + } + public static readonly DependencyProperty IsCloseableProperty = DependencyProperty.Register("IsCloseable", typeof(bool), typeof(ChatPage)); public bool IsCloseable diff --git a/Floe.UI/ChatWindow/ChatWindow.xaml b/Floe.UI/ChatWindow/ChatWindow.xaml index 1009a1c..34de798 100644 --- a/Floe.UI/ChatWindow/ChatWindow.xaml +++ b/Floe.UI/ChatWindow/ChatWindow.xaml @@ -166,11 +166,14 @@ - + - + +                     diff --git a/Floe.UI/ChatWindow/ChatWindow.xaml.cs b/Floe.UI/ChatWindow/ChatWindow.xaml.cs index bd64008..5346cba 100644 --- a/Floe.UI/ChatWindow/ChatWindow.xaml.cs +++ b/Floe.UI/ChatWindow/ChatWindow.xaml.cs @@ -5,6 +5,7 @@ using System.Windows.Controls; using System.Windows.Input; using Floe.Net; +using System.Windows.Media; namespace Floe.UI { @@ -22,19 +23,104 @@ public ChatWindow() InitializeComponent(); this.Loaded += new RoutedEventHandler(ChatWindow_Loaded); + this.tabsChat.SelectionChanged += TabsChat_SelectionChanged; chatTreeView.ItemsSource = NetworkTreeViewList; chatTreeView.SelectedItemChanged += ChatTreeView_SelectedItemChanged; } + private void TabsChat_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + ChatTabItem oldTabItem = null; + ChatTabItem newTabItem = null; + if (e.RemovedItems.Count > 0) + oldTabItem = (ChatTabItem)e.RemovedItems[0]; + if (e.AddedItems.Count > 0) + newTabItem = (ChatTabItem)e.AddedItems[0]; + if (oldTabItem != null && newTabItem != null) + { + if (newTabItem.Page.Type == ChatPageType.Server) + { + NetworkTreeViewItem newNetworkItem = this.NetworkTreeViewList.Where((tr) => tr.Page == newTabItem.Page).FirstOrDefault(); + SelectTreeViewItem(chatTreeView.Items, newNetworkItem.NetworkName); + } + else + { + var newChanItem = FindTreeViewItem(newTabItem.Page); + if (newChanItem is ChannelTreeViewItem) + { + ChannelTreeViewItem cItem = newChanItem as ChannelTreeViewItem; + SelectTreeViewItem(chatTreeView.Items, cItem.ChannelName); + } + } + } + } + + private void SelectTreeViewItem(ItemCollection Collection, String Header) + { + if (Collection == null) return; + foreach (var Item in Collection) + { + if (Item is NetworkTreeViewItem) + { + NetworkTreeViewItem nItem = Item as NetworkTreeViewItem; + var tvItem = chatTreeView.ItemContainerGenerator.ContainerFromItem(nItem) as TreeViewItem; + if (tvItem != null) + { + if (nItem.NetworkName.Equals(Header)) + { + tvItem.IsSelected = true; + return; + } + SelectTreeViewItem(tvItem.Items, Header); + } + } + if (Item is ChannelTreeViewItem) + { + ChannelTreeViewItem cItem = Item as ChannelTreeViewItem; + if (cItem.ChannelName.Equals(Header)) + { + foreach (var tItem in chatTreeView.Items) + { + TreeViewItem TV = tItem as TreeViewItem; + if (TV != null) + { + var tvItem = TV.ItemContainerGenerator.ContainerFromItem(cItem) as TreeViewItem; + if (tvItem != null) + { + tvItem.IsSelected = true; + return; + } + } + } + } + } + } + } + private void ChatTreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs e) { if (e.NewValue is NetworkTreeViewItem) { - SwitchToPage(((NetworkTreeViewItem)e.NewValue).Page); + NetworkTreeViewItem newItem = (NetworkTreeViewItem)e.NewValue; + newItem.IsSelected = true; + SwitchToPage(newItem.Page); + if (e.OldValue is NetworkTreeViewItem) + { + NetworkTreeViewItem oldItem = (NetworkTreeViewItem)e.OldValue; + oldItem.IsSelected = false; + } } if (e.NewValue is ChannelTreeViewItem) { - SwitchToPage(((ChannelTreeViewItem)e.NewValue).Page); + //SwitchToPage(((ChannelTreeViewItem)e.NewValue).Page); + ChannelTreeViewItem newItem = (ChannelTreeViewItem)e.NewValue; + newItem.IsSelected = true; + SwitchToPage(newItem.Page); + if (e.OldValue is ChannelTreeViewItem) + { + ChannelTreeViewItem oldItem = (ChannelTreeViewItem)e.OldValue; + oldItem.IsSelected = false; + } } } @@ -113,6 +199,25 @@ public void SwitchToPage(ChatPage page) tabsChat.SelectedIndex = index; } + public object FindTreeViewItem(ChatPage page) + { + if (page.Type == ChatPageType.Server) + { + return this.NetworkTreeViewList.Where((tr) => tr.Page == page).FirstOrDefault(); + } + else + { + for (int i = this.NetworkTreeViewList.Count - 1; i >= 0; --i) + { + if (this.NetworkTreeViewList[i].Page.Session == page.Session) + { + return this.NetworkTreeViewList[i].ChannelItems.Where(c => c.Page == page).FirstOrDefault(); + } + } + } + return null; + } + public ChatPage FindPage(ChatPageType type, IrcSession session, IrcTarget target) { return this.Items.Where((i) => i.Page.Type == type && i.Page.Session == session && i.Page.Target != null && diff --git a/Floe.UI/ChatWindow/ChatWindow_Events.cs b/Floe.UI/ChatWindow/ChatWindow_Events.cs index 22db4c8..0fae021 100644 --- a/Floe.UI/ChatWindow/ChatWindow_Events.cs +++ b/Floe.UI/ChatWindow/ChatWindow_Events.cs @@ -122,11 +122,11 @@ private void session_RawMessageReceived(object sender, IrcEventArgs e) _notifyIcon.Show("IRC Message", string.Format("You received a message from {0}.", ((IrcPeer)e.Message.From).Nickname)); } } - else if (_notifyIcon != null && _notifyIcon.IsVisible && e.Message.From is IrcPeer) - { - var title = String.Format("{0} : {1}", e.Message.Parameters[0], ((IrcPeer)e.Message.From).Nickname); - _notifyIcon.Show(title, e.Message.Parameters[1]); - } + else if (_notifyIcon != null && _notifyIcon.IsVisible && e.Message.From is IrcPeer) + { + var title = String.Format("{0} : {1}", e.Message.Parameters[0], ((IrcPeer)e.Message.From).Nickname); + _notifyIcon.Show(title, e.Message.Parameters[1]); + } } } diff --git a/Floe.UI/ChatWindow/ChatWindow_TreeView.cs b/Floe.UI/ChatWindow/ChatWindow_TreeView.cs index a674b08..3c3349b 100644 --- a/Floe.UI/ChatWindow/ChatWindow_TreeView.cs +++ b/Floe.UI/ChatWindow/ChatWindow_TreeView.cs @@ -25,8 +25,34 @@ private set } } + private string _activityColor; + public string ActivityColor + { + get { return _activityColor; } + set + { + _activityColor = value; + OnPropertyChanged("ActivityColor"); + } + } + + private bool _isSelected; + public bool IsSelected + { + get { return _isSelected; } + set + { + if (_isSelected != value) + { + _isSelected = value; + } + OnPropertyChanged("IsSelected"); + } + } + public NetworkTreeViewItem(ChatPage page) { + this.ActivityColor = "Black"; this.Page = page; this.Page.Session.StateChanged += Session_StateChanged; ChannelItems = new ObservableCollection(); @@ -39,6 +65,18 @@ private void Session_StateChanged(object sender, EventArgs e) public ObservableCollection ChannelItems { get; set; } + public void OnNotifyStateChanged() + { + if (Page.NotifyState == NotifyState.None) + ActivityColor = "Black"; + if (Page.NotifyState == NotifyState.NoiseActivity) + ActivityColor = "Blue"; + if (Page.NotifyState == NotifyState.ChatActivity) + ActivityColor = "Red"; + if (Page.NotifyState == NotifyState.Alert) + ActivityColor = "#FF00FF00"; + } + public event PropertyChangedEventHandler PropertyChanged; public void OnPropertyChanged(string name) @@ -51,14 +89,63 @@ public void OnPropertyChanged(string name) } } - public class ChannelTreeViewItem + public class ChannelTreeViewItem : INotifyPropertyChanged { public ChatPage Page { get; private set; } public string ChannelName { get { return Page.Target.Name; } } + private string _activityColor; + public string ActivityColor + { + get { return _activityColor; } + set + { + _activityColor = value; + OnPropertyChanged("ActivityColor"); + } + } + + private bool _isSelected; + public bool IsSelected + { + get { return _isSelected; } + set + { + if (_isSelected != value) + { + _isSelected = value; + } + OnPropertyChanged("IsSelected"); + } + } + public ChannelTreeViewItem(ChatPage page) { + this.ActivityColor = "Black"; this.Page = page; } + + public void OnNotifyStateChanged() + { + if (Page.NotifyState == NotifyState.None) + ActivityColor = "Black"; + if (Page.NotifyState == NotifyState.NoiseActivity) + ActivityColor = "Blue"; + if (Page.NotifyState == NotifyState.ChatActivity) + ActivityColor = "Red"; + if (Page.NotifyState == NotifyState.Alert) + ActivityColor = "#FF00FF00"; + } + + public event PropertyChangedEventHandler PropertyChanged; + + public void OnPropertyChanged(string name) + { + var handler = this.PropertyChanged; + if (handler != null) + { + handler(this, new PropertyChangedEventArgs(name)); + } + } } } From b3d8792497eb39553bb72a9ba3ecab98dae20b8a Mon Sep 17 00:00:00 2001 From: Gergo F Date: Sat, 4 Mar 2017 21:49:44 +0000 Subject: [PATCH 17/60] Unfinished feature to switch TreeViewItem on ChatTabItem change --- Floe.UI/ChatWindow/ChatWindow.xaml.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Floe.UI/ChatWindow/ChatWindow.xaml.cs b/Floe.UI/ChatWindow/ChatWindow.xaml.cs index 5346cba..d9f6b55 100644 --- a/Floe.UI/ChatWindow/ChatWindow.xaml.cs +++ b/Floe.UI/ChatWindow/ChatWindow.xaml.cs @@ -30,12 +30,21 @@ public ChatWindow() private void TabsChat_SelectionChanged(object sender, SelectionChangedEventArgs e) { + return; + + /* TODO: + * Disabled because very much seems like TabsChat_SelectionChanged and ChatTreeView_SelectedItemChanged calls each other in an endless loop. + */ ChatTabItem oldTabItem = null; ChatTabItem newTabItem = null; - if (e.RemovedItems.Count > 0) + if ((e.RemovedItems.Count > 0) && (e.RemovedItems[0] is ChatTabItem)) oldTabItem = (ChatTabItem)e.RemovedItems[0]; - if (e.AddedItems.Count > 0) + else + return; + if ((e.AddedItems.Count > 0) && (e.AddedItems[0] is ChatTabItem)) newTabItem = (ChatTabItem)e.AddedItems[0]; + else + return; if (oldTabItem != null && newTabItem != null) { if (newTabItem.Page.Type == ChatPageType.Server) From f20d8e2b33b88b4bb685e44f0e7468e48c7c71d4 Mon Sep 17 00:00:00 2001 From: Seven-7 Date: Thu, 9 Mar 2017 17:11:02 +0000 Subject: [PATCH 18/60] Completed Help.txt --- Floe.UI/Resources/Help.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Floe.UI/Resources/Help.txt b/Floe.UI/Resources/Help.txt index 02bd607..5f2fee7 100644 --- a/Floe.UI/Resources/Help.txt +++ b/Floe.UI/Resources/Help.txt @@ -37,3 +37,5 @@ /WHO - Get info on one or more users /WHOIS [target] - Get extended info on a user /WHOWAS - See if/when a user was logged on +/OPER - Oper-up yourself +/HOP or /CY [#channel] [message] - Part-join a channel with optional part message. From 0aaf7c6d37c034401001fe6f22813191dd263f5b Mon Sep 17 00:00:00 2001 From: Seven-7 Date: Thu, 9 Mar 2017 17:13:28 +0000 Subject: [PATCH 19/60] Order channels always first in list --- Floe.UI/ChatWindow/ChatWindow.xaml.cs | 50 +++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/Floe.UI/ChatWindow/ChatWindow.xaml.cs b/Floe.UI/ChatWindow/ChatWindow.xaml.cs index d9f6b55..c14f40e 100644 --- a/Floe.UI/ChatWindow/ChatWindow.xaml.cs +++ b/Floe.UI/ChatWindow/ChatWindow.xaml.cs @@ -149,6 +149,12 @@ public void AddPage(ChatPage page, bool switchToPage) { if (this.Items[i].Page.Session == page.Session) { + if ((page.Target.IsChannel) + && ((this.Items[i].Page.Target != null) && (this.Items[i].Page.Target.IsChannel == false)) + && (i < (this.Items.Count - 1))) + { + continue; + } this.Items.Insert(i + 1, item); break; } @@ -157,8 +163,48 @@ public void AddPage(ChatPage page, bool switchToPage) { if (this.NetworkTreeViewList[i].Page.Session == page.Session) { - this.NetworkTreeViewList[i].ChannelItems.Add(new ChannelTreeViewItem(item.Page)); - break; + for (int j = 0; j <= this.NetworkTreeViewList[i].ChannelItems.Count; j++) + { + if (this.NetworkTreeViewList[i].ChannelItems.Count == 0) + { + this.NetworkTreeViewList[i].ChannelItems.Add(new ChannelTreeViewItem(item.Page)); + break; + } + if (j == this.NetworkTreeViewList[i].ChannelItems.Count - 1) + { + if (page.Target.IsChannel) + { + if (this.NetworkTreeViewList[i].ChannelItems[j].Page.Target.IsChannel) + { + this.NetworkTreeViewList[i].ChannelItems.Add(new ChannelTreeViewItem(item.Page)); + break; + } + else + { + this.NetworkTreeViewList[i].ChannelItems.Insert(j, new ChannelTreeViewItem(item.Page)); + break; + } + } + else + { + this.NetworkTreeViewList[i].ChannelItems.Add(new ChannelTreeViewItem(item.Page)); + break; + } + } + if (!this.NetworkTreeViewList[i].ChannelItems[j].Page.Target.IsChannel) + { + if (page.Target.IsChannel) + { + this.NetworkTreeViewList[i].ChannelItems.Insert(j, new ChannelTreeViewItem(item.Page)); + break; + } + else + { + this.NetworkTreeViewList[i].ChannelItems.Add(new ChannelTreeViewItem(item.Page)); + break; + } + } + } } } } From 9f09bb942485fc4b6984740f27a7aaf10195ad60 Mon Sep 17 00:00:00 2001 From: Seven-7 Date: Thu, 6 Apr 2017 23:08:24 +0100 Subject: [PATCH 20/60] Minor rewrite for the TreeView --- Floe.UI/ChatWindow/ChatWindow.xaml.cs | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/Floe.UI/ChatWindow/ChatWindow.xaml.cs b/Floe.UI/ChatWindow/ChatWindow.xaml.cs index c14f40e..c28b603 100644 --- a/Floe.UI/ChatWindow/ChatWindow.xaml.cs +++ b/Floe.UI/ChatWindow/ChatWindow.xaml.cs @@ -86,20 +86,13 @@ private void SelectTreeViewItem(ItemCollection Collection, String Header) if (Item is ChannelTreeViewItem) { ChannelTreeViewItem cItem = Item as ChannelTreeViewItem; - if (cItem.ChannelName.Equals(Header)) + var tvItem = chatTreeView.ItemContainerGenerator.ContainerFromItem(cItem) as TreeViewItem; + if (tvItem != null) { - foreach (var tItem in chatTreeView.Items) + if (cItem.ChannelName.Equals(Header)) { - TreeViewItem TV = tItem as TreeViewItem; - if (TV != null) - { - var tvItem = TV.ItemContainerGenerator.ContainerFromItem(cItem) as TreeViewItem; - if (tvItem != null) - { - tvItem.IsSelected = true; - return; - } - } + tvItem.IsSelected = true; + return; } } } @@ -121,7 +114,6 @@ private void ChatTreeView_SelectedItemChanged(object sender, RoutedPropertyChang } if (e.NewValue is ChannelTreeViewItem) { - //SwitchToPage(((ChannelTreeViewItem)e.NewValue).Page); ChannelTreeViewItem newItem = (ChannelTreeViewItem)e.NewValue; newItem.IsSelected = true; SwitchToPage(newItem.Page); From ee7e4e9a693136145944855516e85f1e9db589c6 Mon Sep 17 00:00:00 2001 From: Seven-7 Date: Thu, 6 Apr 2017 23:10:16 +0100 Subject: [PATCH 21/60] Accept any CAP capability + some tab-fixes --- Floe.Net/Irc/IrcSession.cs | 4 +++- Floe.UI/ChatControl/NicknameItem.cs | 7 ++++++- Floe.UI/ChatControl/NicknameList.cs | 26 +++++++++++++------------- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/Floe.Net/Irc/IrcSession.cs b/Floe.Net/Irc/IrcSession.cs index e32fc27..5b66d12 100644 --- a/Floe.Net/Irc/IrcSession.cs +++ b/Floe.Net/Irc/IrcSession.cs @@ -1047,8 +1047,10 @@ private void OnCap(IrcMessage message) // We don't really even need to do anything about "ACK" but we might want to handle "NAK" // in case ZNC 1.5 or whatever drops znc.in/server-time-iso in favor of server-time... case "LS": // Server listed capabilities. END or REQ. + _conn.QueueMessage(new IrcMessage("CAP REQ", message.Parameters.Skip(2).ToArray())); break; case "ACK": // Server acknowledged. Turn it on. + _conn.QueueMessage(new IrcMessage("CAP", "END")); break; case "NAK": // Server rejected. Turn it off. break; @@ -1126,7 +1128,7 @@ private void _conn_Connected(object sender, EventArgs e) .Where((ip) => ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork).FirstOrDefault(); // IRCv3 Client Capability Negotiation - //_conn.QueueMessage(new IrcMessage("CAP", "LS")); + _conn.QueueMessage(new IrcMessage("CAP", "LS")); // NEGOTIATION? I MEANT A ONE-SIDED DEMAND. _conn.QueueMessage(new IrcMessage("CAP", "REQ", "znc.in/server-time-iso")); diff --git a/Floe.UI/ChatControl/NicknameItem.cs b/Floe.UI/ChatControl/NicknameItem.cs index 6f10526..8da5302 100644 --- a/Floe.UI/ChatControl/NicknameItem.cs +++ b/Floe.UI/ChatControl/NicknameItem.cs @@ -1,4 +1,5 @@ -using System; +using Floe.Net; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -31,6 +32,10 @@ public NicknameItem(ChannelLevel level, string nick) public NicknameItem(string nick) { + if (nick.Contains("!")) + { + nick = nick[0] + new IrcPeer(nick.Substring(1)).Nickname; + } var level = ChannelLevel.Normal; int i = 0; for (i = 0; i < nick.Length && !IsNickChar(nick[i]); i++) diff --git a/Floe.UI/ChatControl/NicknameList.cs b/Floe.UI/ChatControl/NicknameList.cs index 945e5b0..9bca6a1 100644 --- a/Floe.UI/ChatControl/NicknameList.cs +++ b/Floe.UI/ChatControl/NicknameList.cs @@ -12,7 +12,7 @@ namespace Floe.UI { public class NicknameList : KeyedCollection, INotifyCollectionChanged { - public EventHandler NickListChanged; + public EventHandler NickListChanged; public NicknameList() : base(StringComparer.OrdinalIgnoreCase) { @@ -27,16 +27,16 @@ public void AddRange(IEnumerable nicks) { this.Add(item); } - OnNickListChanged(this, null); - } + OnNickListChanged(this, null); + } - public void Add(string nick) + public void Add(string nick) { this.Add(new NicknameItem(nick)); - OnNickListChanged(this, null); - } + OnNickListChanged(this, null); + } - public void ChangeNick(string oldNick, string newNick) + public void ChangeNick(string oldNick, string newNick) { var item = this[oldNick]; if (item != null) @@ -120,14 +120,14 @@ private void OnCollectionChanged(NotifyCollectionChangedEventArgs args) if (handler != null) { handler(this, args); - OnNickListChanged(this, null); + OnNickListChanged(this, null); } } - protected virtual void OnNickListChanged(object source, EventArgs e) - { - if (NickListChanged != null) - NickListChanged(this, null); - } + protected virtual void OnNickListChanged(object source, EventArgs e) + { + if (NickListChanged != null) + NickListChanged(this, null); + } } } From 339a5fb13eb134bd3475cae33d23810565147451 Mon Sep 17 00:00:00 2001 From: Gergo F Date: Sat, 8 Apr 2017 19:29:00 +0100 Subject: [PATCH 22/60] Input-edit default color is Black --- Floe.Configuration/ColorsElement.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Floe.Configuration/ColorsElement.cs b/Floe.Configuration/ColorsElement.cs index d81787e..2397c5c 100644 --- a/Floe.Configuration/ColorsElement.cs +++ b/Floe.Configuration/ColorsElement.cs @@ -22,7 +22,7 @@ public string EditBackground set { this["editBackground"] = value; OnPropertyChanged("EditBackground"); } } - [ConfigurationProperty("edit", DefaultValue = "#FFC0C0C0")] + [ConfigurationProperty("edit", DefaultValue = "Black")] public string Edit { get { return (string)this["edit"]; } From 05fe217b2a389f2dfbf9a9b1150872365b50a1bb Mon Sep 17 00:00:00 2001 From: Seven-7 Date: Sun, 9 Apr 2017 23:17:13 +0100 Subject: [PATCH 23/60] Allow nick-completion for nicks starting with '=' equal sign --- Floe.UI/ChatControl/NicknameComplete.cs | 4 ++++ Floe.UI/ChatControl/NicknameList.cs | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Floe.UI/ChatControl/NicknameComplete.cs b/Floe.UI/ChatControl/NicknameComplete.cs index b67ae7c..4d32592 100644 --- a/Floe.UI/ChatControl/NicknameComplete.cs +++ b/Floe.UI/ChatControl/NicknameComplete.cs @@ -66,6 +66,10 @@ private string initialInputParse() while ( c != ' ' && i > 0) { c = _txtInput.Text[--i]; + if ((c == '=') && (_txtInput.Text[i - 1] == ' ')) + { + break; + } } if (i == 0) { diff --git a/Floe.UI/ChatControl/NicknameList.cs b/Floe.UI/ChatControl/NicknameList.cs index 9bca6a1..f8889aa 100644 --- a/Floe.UI/ChatControl/NicknameList.cs +++ b/Floe.UI/ChatControl/NicknameList.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Linq; using System.Text; - using Floe.Net; namespace Floe.UI From eadab231f594daaed895e9cd174d40b26aed6199 Mon Sep 17 00:00:00 2001 From: Seven-7 Date: Tue, 23 May 2017 20:25:00 +0100 Subject: [PATCH 24/60] Finished feature switch TreeViewItem on ChatTabItem change --- Floe.UI/ChatWindow/ChatWindow.xaml | 4 +- Floe.UI/ChatWindow/ChatWindow.xaml.cs | 58 ++++----------------------- 2 files changed, 9 insertions(+), 53 deletions(-) diff --git a/Floe.UI/ChatWindow/ChatWindow.xaml b/Floe.UI/ChatWindow/ChatWindow.xaml index 34de798..efdb240 100644 --- a/Floe.UI/ChatWindow/ChatWindow.xaml +++ b/Floe.UI/ChatWindow/ChatWindow.xaml @@ -162,6 +162,7 @@ @@ -171,9 +172,6 @@ -                     diff --git a/Floe.UI/ChatWindow/ChatWindow.xaml.cs b/Floe.UI/ChatWindow/ChatWindow.xaml.cs index c28b603..043a43d 100644 --- a/Floe.UI/ChatWindow/ChatWindow.xaml.cs +++ b/Floe.UI/ChatWindow/ChatWindow.xaml.cs @@ -13,6 +13,7 @@ public partial class ChatWindow : Window { public ObservableCollection Items { get; private set; } public ObservableCollection NetworkTreeViewList; + public ChatControl ActiveControl { get { return tabsChat.SelectedContent as ChatControl; } } public ChatWindow() @@ -30,11 +31,6 @@ public ChatWindow() private void TabsChat_SelectionChanged(object sender, SelectionChangedEventArgs e) { - return; - - /* TODO: - * Disabled because very much seems like TabsChat_SelectionChanged and ChatTreeView_SelectedItemChanged calls each other in an endless loop. - */ ChatTabItem oldTabItem = null; ChatTabItem newTabItem = null; if ((e.RemovedItems.Count > 0) && (e.RemovedItems[0] is ChatTabItem)) @@ -47,54 +43,16 @@ private void TabsChat_SelectionChanged(object sender, SelectionChangedEventArgs return; if (oldTabItem != null && newTabItem != null) { - if (newTabItem.Page.Type == ChatPageType.Server) - { - NetworkTreeViewItem newNetworkItem = this.NetworkTreeViewList.Where((tr) => tr.Page == newTabItem.Page).FirstOrDefault(); - SelectTreeViewItem(chatTreeView.Items, newNetworkItem.NetworkName); - } - else + var newTreeViewItemSelection = FindTreeViewItem(newTabItem.Page); + if (newTreeViewItemSelection is NetworkTreeViewItem) { - var newChanItem = FindTreeViewItem(newTabItem.Page); - if (newChanItem is ChannelTreeViewItem) - { - ChannelTreeViewItem cItem = newChanItem as ChannelTreeViewItem; - SelectTreeViewItem(chatTreeView.Items, cItem.ChannelName); - } + NetworkTreeViewItem nItem = newTreeViewItemSelection as NetworkTreeViewItem; + nItem.IsSelected = true; } - } - } - - private void SelectTreeViewItem(ItemCollection Collection, String Header) - { - if (Collection == null) return; - foreach (var Item in Collection) - { - if (Item is NetworkTreeViewItem) + if (newTreeViewItemSelection is ChannelTreeViewItem) { - NetworkTreeViewItem nItem = Item as NetworkTreeViewItem; - var tvItem = chatTreeView.ItemContainerGenerator.ContainerFromItem(nItem) as TreeViewItem; - if (tvItem != null) - { - if (nItem.NetworkName.Equals(Header)) - { - tvItem.IsSelected = true; - return; - } - SelectTreeViewItem(tvItem.Items, Header); - } - } - if (Item is ChannelTreeViewItem) - { - ChannelTreeViewItem cItem = Item as ChannelTreeViewItem; - var tvItem = chatTreeView.ItemContainerGenerator.ContainerFromItem(cItem) as TreeViewItem; - if (tvItem != null) - { - if (cItem.ChannelName.Equals(Header)) - { - tvItem.IsSelected = true; - return; - } - } + ChannelTreeViewItem cItem = newTreeViewItemSelection as ChannelTreeViewItem; + cItem.IsSelected = true; } } } From 226558691a82aeddbaa15a6f336c4ce787f0258f Mon Sep 17 00:00:00 2001 From: Seven-7 Date: Wed, 11 Oct 2017 00:15:54 +0100 Subject: [PATCH 25/60] Own Action is also an action, not Own plain text --- Floe.UI/ChatControl/ChatControl_Commands.cs | 2 +- Floe.UI/ChatControl/ChatControl_Slap.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Floe.UI/ChatControl/ChatControl_Commands.cs b/Floe.UI/ChatControl/ChatControl_Commands.cs index 1bd7cc5..4033514 100644 --- a/Floe.UI/ChatControl/ChatControl_Commands.cs +++ b/Floe.UI/ChatControl/ChatControl_Commands.cs @@ -558,7 +558,7 @@ private void Execute(string command, string arguments) if (this.IsConnected) { args = Split(command, arguments, 1, int.MaxValue); - this.Write("Own", string.Format("{0} {1}", this.Session.Nickname, string.Join(" ", args))); + this.Write("Action", string.Format("{0} {1}", this.Session.Nickname, string.Join(" ", args))); if (this.Type == ChatPageType.Chat) { this.Session.SendCtcp(this.Target, new CtcpCommand("ACTION", args), false); diff --git a/Floe.UI/ChatControl/ChatControl_Slap.cs b/Floe.UI/ChatControl/ChatControl_Slap.cs index 369f57b..7a4cf45 100644 --- a/Floe.UI/ChatControl/ChatControl_Slap.cs +++ b/Floe.UI/ChatControl/ChatControl_Slap.cs @@ -88,7 +88,7 @@ private void ExecuteSlap(object sender, ExecutedRoutedEventArgs e) if (this.IsConnected) { this.Session.SendCtcp(this.Target, new CtcpCommand("ACTION", slapString.Split(' ')), false); - this.Write("Own", string.Format("{0} {1}", this.Session.Nickname, slapString)); + this.Write("Action", string.Format("{0} {1}", this.Session.Nickname, slapString)); } } } From f533529d0578856afe1625c8ee428cdb739ed989 Mon Sep 17 00:00:00 2001 From: Seven-7 Date: Sat, 27 Jan 2018 13:03:30 +0000 Subject: [PATCH 26/60] Fix sync between TreeView and TabItems, and other fixes --- Floe.UI/ChatWindow/ChatWindow.xaml.cs | 26 ++++++++++++++++------- Floe.UI/ChatWindow/ChatWindow_TreeView.cs | 2 +- Floe.UI/ListControl/ListControl.xaml.cs | 2 +- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/Floe.UI/ChatWindow/ChatWindow.xaml.cs b/Floe.UI/ChatWindow/ChatWindow.xaml.cs index 043a43d..d3c57a8 100644 --- a/Floe.UI/ChatWindow/ChatWindow.xaml.cs +++ b/Floe.UI/ChatWindow/ChatWindow.xaml.cs @@ -35,13 +35,23 @@ private void TabsChat_SelectionChanged(object sender, SelectionChangedEventArgs ChatTabItem newTabItem = null; if ((e.RemovedItems.Count > 0) && (e.RemovedItems[0] is ChatTabItem)) oldTabItem = (ChatTabItem)e.RemovedItems[0]; - else - return; if ((e.AddedItems.Count > 0) && (e.AddedItems[0] is ChatTabItem)) newTabItem = (ChatTabItem)e.AddedItems[0]; - else - return; - if (oldTabItem != null && newTabItem != null) + if (oldTabItem != null) + { + var newTreeViewItemSelection = FindTreeViewItem(oldTabItem.Page); + if (newTreeViewItemSelection is NetworkTreeViewItem) + { + NetworkTreeViewItem nItem = newTreeViewItemSelection as NetworkTreeViewItem; + nItem.IsSelected = false; + } + if (newTreeViewItemSelection is ChannelTreeViewItem) + { + ChannelTreeViewItem cItem = newTreeViewItemSelection as ChannelTreeViewItem; + cItem.IsSelected = false; + } + } + if (newTabItem != null) { var newTreeViewItemSelection = FindTreeViewItem(newTabItem.Page); if (newTreeViewItemSelection is NetworkTreeViewItem) @@ -99,7 +109,7 @@ public void AddPage(ChatPage page, bool switchToPage) { if (this.Items[i].Page.Session == page.Session) { - if ((page.Target.IsChannel) + if (((page.Target != null) && (page.Target.IsChannel)) && ((this.Items[i].Page.Target != null) && (this.Items[i].Page.Target.IsChannel == false)) && (i < (this.Items.Count - 1))) { @@ -122,7 +132,7 @@ public void AddPage(ChatPage page, bool switchToPage) } if (j == this.NetworkTreeViewList[i].ChannelItems.Count - 1) { - if (page.Target.IsChannel) + if (page.Target != null && page.Target.IsChannel) { if (this.NetworkTreeViewList[i].ChannelItems[j].Page.Target.IsChannel) { @@ -143,7 +153,7 @@ public void AddPage(ChatPage page, bool switchToPage) } if (!this.NetworkTreeViewList[i].ChannelItems[j].Page.Target.IsChannel) { - if (page.Target.IsChannel) + if (page.Target != null && page.Target.IsChannel) { this.NetworkTreeViewList[i].ChannelItems.Insert(j, new ChannelTreeViewItem(item.Page)); break; diff --git a/Floe.UI/ChatWindow/ChatWindow_TreeView.cs b/Floe.UI/ChatWindow/ChatWindow_TreeView.cs index 3c3349b..230542a 100644 --- a/Floe.UI/ChatWindow/ChatWindow_TreeView.cs +++ b/Floe.UI/ChatWindow/ChatWindow_TreeView.cs @@ -92,7 +92,7 @@ public void OnPropertyChanged(string name) public class ChannelTreeViewItem : INotifyPropertyChanged { public ChatPage Page { get; private set; } - public string ChannelName { get { return Page.Target.Name; } } + public string ChannelName { get { return Page.Target != null ? Page.Target.Name : "Channel List"; } } private string _activityColor; public string ActivityColor diff --git a/Floe.UI/ListControl/ListControl.xaml.cs b/Floe.UI/ListControl/ListControl.xaml.cs index b1d2e0d..e7f365a 100644 --- a/Floe.UI/ListControl/ListControl.xaml.cs +++ b/Floe.UI/ListControl/ListControl.xaml.cs @@ -81,7 +81,7 @@ private void Session_InfoReceived(object sender, IrcInfoEventArgs e) case IrcCode.RPL_LISTEND: this.IsCloseable = true; this.Session.InfoReceived -= new EventHandler(Session_InfoReceived); - _channels.Sort(); + _channels = _channels.OrderByDescending(c => c.Count).ToList(); foreach (var c in _channels) { lstChannels.Items.Add(c); From 4c6dbdd88fd17eadd433a6a88d8f30921badc31a Mon Sep 17 00:00:00 2001 From: Seven-7 Date: Sat, 27 Jan 2018 20:22:33 +0000 Subject: [PATCH 27/60] A fix for /LIST (now switches properly between Status window) --- Floe.UI/ChatWindow/ChatWindow.xaml.cs | 4 ++-- Floe.UI/ListControl/ListControl.xaml.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Floe.UI/ChatWindow/ChatWindow.xaml.cs b/Floe.UI/ChatWindow/ChatWindow.xaml.cs index d3c57a8..b4e18bd 100644 --- a/Floe.UI/ChatWindow/ChatWindow.xaml.cs +++ b/Floe.UI/ChatWindow/ChatWindow.xaml.cs @@ -134,7 +134,7 @@ public void AddPage(ChatPage page, bool switchToPage) { if (page.Target != null && page.Target.IsChannel) { - if (this.NetworkTreeViewList[i].ChannelItems[j].Page.Target.IsChannel) + if ((this.NetworkTreeViewList[i].ChannelItems[j].Page.Target != null) && (this.NetworkTreeViewList[i].ChannelItems[j].Page.Target.IsChannel)) { this.NetworkTreeViewList[i].ChannelItems.Add(new ChannelTreeViewItem(item.Page)); break; @@ -207,7 +207,7 @@ public void SwitchToPage(ChatPage page) { foreach (var tbItem in this.Items) { - if (tbItem.Page.Session == page.Session && tbItem.Page.Target == page.Target) + if ((tbItem.Page.Session == page.Session) && (tbItem.Page.Type == page.Type) && (tbItem.Page.Target == page.Target)) index = this.Items.IndexOf(tbItem); } } diff --git a/Floe.UI/ListControl/ListControl.xaml.cs b/Floe.UI/ListControl/ListControl.xaml.cs index e7f365a..92fc134 100644 --- a/Floe.UI/ListControl/ListControl.xaml.cs +++ b/Floe.UI/ListControl/ListControl.xaml.cs @@ -81,7 +81,7 @@ private void Session_InfoReceived(object sender, IrcInfoEventArgs e) case IrcCode.RPL_LISTEND: this.IsCloseable = true; this.Session.InfoReceived -= new EventHandler(Session_InfoReceived); - _channels = _channels.OrderByDescending(c => c.Count).ToList(); + _channels = _channels.OrderByDescending(c => c.Count).OrderBy(n => n.Name).ToList(); foreach (var c in _channels) { lstChannels.Items.Add(c); From 80b5a6228fad34710d7dad9ef4b7b0b6cc736ba8 Mon Sep 17 00:00:00 2001 From: Seven-7 Date: Sat, 27 Jan 2018 23:56:47 +0000 Subject: [PATCH 28/60] The right way for sorting /LIST channels --- Floe.UI/ListControl/ListControl.xaml.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Floe.UI/ListControl/ListControl.xaml.cs b/Floe.UI/ListControl/ListControl.xaml.cs index 92fc134..2f25c51 100644 --- a/Floe.UI/ListControl/ListControl.xaml.cs +++ b/Floe.UI/ListControl/ListControl.xaml.cs @@ -81,8 +81,8 @@ private void Session_InfoReceived(object sender, IrcInfoEventArgs e) case IrcCode.RPL_LISTEND: this.IsCloseable = true; this.Session.InfoReceived -= new EventHandler(Session_InfoReceived); - _channels = _channels.OrderByDescending(c => c.Count).OrderBy(n => n.Name).ToList(); - foreach (var c in _channels) + _channels = _channels.OrderByDescending(c => c.Count).ThenBy(n => n.Name).ToList(); + foreach (var c in _channels) { lstChannels.Items.Add(c); } From a15122a2a949c7ec089bf3da03b984dc46400a3d Mon Sep 17 00:00:00 2001 From: Seven-7 Date: Wed, 31 Jan 2018 13:28:30 +0000 Subject: [PATCH 29/60] Addded menus to TreeView items --- Floe.UI/ChatWindow/ChatWindow.xaml | 12 +++++++++--- Floe.UI/ChatWindow/ChatWindow_Events.cs | 12 ++++++------ Floe.UI/ChatWindow/ChatWindow_TreeView.cs | 14 +++++++++++--- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/Floe.UI/ChatWindow/ChatWindow.xaml b/Floe.UI/ChatWindow/ChatWindow.xaml index efdb240..78e5a6c 100644 --- a/Floe.UI/ChatWindow/ChatWindow.xaml +++ b/Floe.UI/ChatWindow/ChatWindow.xaml @@ -167,10 +167,16 @@ - - + + + + + + + + - +                     diff --git a/Floe.UI/ChatWindow/ChatWindow_Events.cs b/Floe.UI/ChatWindow/ChatWindow_Events.cs index 0fae021..d5bf11c 100644 --- a/Floe.UI/ChatWindow/ChatWindow_Events.cs +++ b/Floe.UI/ChatWindow/ChatWindow_Events.cs @@ -103,7 +103,7 @@ private void Session_CtcpCommandReceived(object sender, CtcpEventArgs e) } } - private void session_RawMessageReceived(object sender, IrcEventArgs e) + private void Session_RawMessageReceived(object sender, IrcEventArgs e) { if (e.Message.Command == "PRIVMSG" && e.Message.Parameters.Count == 2 && (!CtcpCommand.IsCtcpCommand(e.Message.Parameters[1]) || @@ -203,7 +203,7 @@ protected override void OnClosing(System.ComponentModel.CancelEventArgs e) } } - private void session_InfoReceived(object sender, IrcInfoEventArgs e) + private void Session_InfoReceived(object sender, IrcInfoEventArgs e) { var session = sender as IrcSession; switch (e.Code) @@ -236,8 +236,8 @@ private void SubscribeEvents(IrcSession session) session.SelfKicked += new EventHandler(Session_SelfKicked); session.StateChanged += new EventHandler(Session_StateChanged); session.CtcpCommandReceived += new EventHandler(Session_CtcpCommandReceived); - session.RawMessageReceived += new EventHandler(session_RawMessageReceived); - session.InfoReceived += new EventHandler(session_InfoReceived); + session.RawMessageReceived += new EventHandler(Session_RawMessageReceived); + session.InfoReceived += new EventHandler(Session_InfoReceived); } public void UnsubscribeEvents(IrcSession session) @@ -247,8 +247,8 @@ public void UnsubscribeEvents(IrcSession session) session.SelfKicked -= new EventHandler(Session_SelfKicked); session.StateChanged -= new EventHandler(Session_StateChanged); session.CtcpCommandReceived -= new EventHandler(Session_CtcpCommandReceived); - session.RawMessageReceived -= new EventHandler(session_RawMessageReceived); - session.InfoReceived -= new EventHandler(session_InfoReceived); + session.RawMessageReceived -= new EventHandler(Session_RawMessageReceived); + session.InfoReceived -= new EventHandler(Session_InfoReceived); } } } diff --git a/Floe.UI/ChatWindow/ChatWindow_TreeView.cs b/Floe.UI/ChatWindow/ChatWindow_TreeView.cs index 230542a..3573476 100644 --- a/Floe.UI/ChatWindow/ChatWindow_TreeView.cs +++ b/Floe.UI/ChatWindow/ChatWindow_TreeView.cs @@ -94,6 +94,8 @@ public class ChannelTreeViewItem : INotifyPropertyChanged public ChatPage Page { get; private set; } public string ChannelName { get { return Page.Target != null ? Page.Target.Name : "Channel List"; } } + public ContextMenu CloseMenu { get; private set; } + private string _activityColor; public string ActivityColor { @@ -123,9 +125,15 @@ public ChannelTreeViewItem(ChatPage page) { this.ActivityColor = "Black"; this.Page = page; - } - - public void OnNotifyStateChanged() + this.Page.IsCloseable = true; + CloseMenu = new ContextMenu(); + MenuItem CloseItem = new MenuItem(); + CloseItem.Command = ChatWindow.CloseTabCommand; + CloseItem.CommandParameter = this.Page; + CloseMenu.Items.Add(CloseItem); + } + + public void OnNotifyStateChanged() { if (Page.NotifyState == NotifyState.None) ActivityColor = "Black"; From 9ee7c0ef389e977fbafe7e61de53eecbc8ff46e9 Mon Sep 17 00:00:00 2001 From: Seven-7 Date: Wed, 31 Jan 2018 16:13:39 +0000 Subject: [PATCH 30/60] Always show Nickname in Title-bar (even if disconnected), always announce nickchange in Status-window -- IrcSession is constructed with Setting's default nickname --- Floe.Net/Irc/IrcSession.cs | 3 ++- Floe.UI/ChatControl/ChatControl.xaml | 3 +-- Floe.UI/ChatControl/ChatControl.xaml.cs | 2 +- Floe.UI/ChatControl/ChatControl_Commands.cs | 5 ++++- Floe.UI/ChatWindow/ChatWindow_Commands.cs | 2 +- Floe.UI/ChatWindow/ChatWindow_Events.cs | 4 ++-- 6 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Floe.Net/Irc/IrcSession.cs b/Floe.Net/Irc/IrcSession.cs index 5b66d12..a7f0bc3 100644 --- a/Floe.Net/Irc/IrcSession.cs +++ b/Floe.Net/Irc/IrcSession.cs @@ -238,9 +238,10 @@ private set /// /// Default constructor. /// - public IrcSession() + public IrcSession(string nickName = null) { this.State = IrcSessionState.Disconnected; + this.Nickname = nickName; this.UserModes = new char[0]; _syncContext = SynchronizationContext.Current; diff --git a/Floe.UI/ChatControl/ChatControl.xaml b/Floe.UI/ChatControl/ChatControl.xaml index e703e5d..acda8ed 100755 --- a/Floe.UI/ChatControl/ChatControl.xaml +++ b/Floe.UI/ChatControl/ChatControl.xaml @@ -219,8 +219,7 @@ FontSize="{Binding Source={x:Static local:App.Settings}, Path=Current.Formatting.FontSize, Mode=OneWay}" FontStyle="{Binding Source={x:Static local:App.Settings}, Path=Current.Formatting.FontStyle, Mode=OneWay}" FontWeight="{Binding Source={x:Static local:App.Settings}, Path=Current.Formatting.FontWeight, Mode=OneWay}" - Padding="1,2,2,2" Margin="0" BorderThickness="0" Height="Auto" TextWrapping="Wrap" MaxLength="512" SpellCheck.IsEnabled="True" - ContextMenuOpening="txtInput_ContextMenuOpening"> + Padding="1,2,2,2" Margin="0" BorderThickness="0" Height="Auto" TextWrapping="Wrap" MaxLength="512" SpellCheck.IsEnabled="True"> diff --git a/Floe.UI/ChatControl/ChatControl.xaml.cs b/Floe.UI/ChatControl/ChatControl.xaml.cs index b71ab70..858d177 100644 --- a/Floe.UI/ChatControl/ChatControl.xaml.cs +++ b/Floe.UI/ChatControl/ChatControl.xaml.cs @@ -290,7 +290,7 @@ private void SetTitle() case ChatPageType.Server: if (this.Session.State == IrcSessionState.Disconnected) { - this.Title = string.Format("{0} - Not Connected", App.Product); + this.Title = string.Format("{0} - {1} - Not Connected", App.Product, this.Session.Nickname); } else { diff --git a/Floe.UI/ChatControl/ChatControl_Commands.cs b/Floe.UI/ChatControl/ChatControl_Commands.cs index 4033514..6c7dd18 100644 --- a/Floe.UI/ChatControl/ChatControl_Commands.cs +++ b/Floe.UI/ChatControl/ChatControl_Commands.cs @@ -373,7 +373,10 @@ private void Execute(string command, string arguments) case "NICK": args = Split(command, arguments, 1, 1); this.Session.Nick(args[0]); - break; + this.SetTitle(); + if (this.IsServer) + this.Write("Nick", DateTime.Now, string.Format(" *** You are now known as {0}", args[0])); + break; case "NOTICE": case "N": args = Split(command, arguments, 2, 2); diff --git a/Floe.UI/ChatWindow/ChatWindow_Commands.cs b/Floe.UI/ChatWindow/ChatWindow_Commands.cs index 3089a54..a3aa598 100644 --- a/Floe.UI/ChatWindow/ChatWindow_Commands.cs +++ b/Floe.UI/ChatWindow/ChatWindow_Commands.cs @@ -73,7 +73,7 @@ private void ExecuteCloseTab(object sender, ExecutedRoutedEventArgs e) private void ExecuteNewTab(object sender, ExecutedRoutedEventArgs e) { - this.AddPage(new ChatControl(ChatPageType.Server, new IrcSession(), null), true); + this.AddPage(new ChatControl(ChatPageType.Server, new IrcSession(App.Settings.Current.User.Nickname), null), true); } private void ExecuteDetach(object sender, ExecutedRoutedEventArgs e) diff --git a/Floe.UI/ChatWindow/ChatWindow_Events.cs b/Floe.UI/ChatWindow/ChatWindow_Events.cs index d5bf11c..57bd6b3 100644 --- a/Floe.UI/ChatWindow/ChatWindow_Events.cs +++ b/Floe.UI/ChatWindow/ChatWindow_Events.cs @@ -132,7 +132,7 @@ private void Session_RawMessageReceived(object sender, IrcEventArgs e) private void ChatWindow_Loaded(object sender, RoutedEventArgs e) { - this.AddPage(new ChatControl(ChatPageType.Server, new IrcSession(), null), true); + this.AddPage(new ChatControl(ChatPageType.Server, new IrcSession(App.Settings.Current.User.Nickname), null), true); if (Application.Current.MainWindow == this) { @@ -148,7 +148,7 @@ private void ChatWindow_Loaded(object sender, RoutedEventArgs e) { if (i++ > 0) { - this.AddPage(new ChatControl(ChatPageType.Server, new IrcSession(), null), false); + this.AddPage(new ChatControl(ChatPageType.Server, new IrcSession(App.Settings.Current.User.Nickname), null), false); } var page = this.Items[this.Items.Count - 1] as ChatTabItem; if (page != null) From 2e63da8afc642644f31717457b09476349d971b3 Mon Sep 17 00:00:00 2001 From: Seven-7 Date: Wed, 31 Jan 2018 18:14:21 +0000 Subject: [PATCH 31/60] Shortcut for /server /s, /query /q, minor adjustment for disconnected-state nickchange --- Floe.UI/ChatControl/ChatControl_Commands.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Floe.UI/ChatControl/ChatControl_Commands.cs b/Floe.UI/ChatControl/ChatControl_Commands.cs index 6c7dd18..458f9f6 100644 --- a/Floe.UI/ChatControl/ChatControl_Commands.cs +++ b/Floe.UI/ChatControl/ChatControl_Commands.cs @@ -374,8 +374,8 @@ private void Execute(string command, string arguments) args = Split(command, arguments, 1, 1); this.Session.Nick(args[0]); this.SetTitle(); - if (this.IsServer) - this.Write("Nick", DateTime.Now, string.Format(" *** You are now known as {0}", args[0])); + if (this.IsServer && this.Session.State == IrcSessionState.Disconnected) + this.Write("Own", string.Format("Your nick is now {0}", args[0])); break; case "NOTICE": case "N": @@ -522,8 +522,9 @@ private void Execute(string command, string arguments) } break; case "SERVER": - { - args = Split(command, arguments, 1, 3); + case "S": + { + args = Split(command, arguments, 1, 3); int port = 0; bool useSsl = false; if (args.Length > 1 && (args[1] = args[1].Trim()).Length > 0) @@ -633,7 +634,8 @@ private void Execute(string command, string arguments) new CtcpCommand(args[1], args.Skip(2).ToArray()), false); break; case "QUERY": - args = Split(command, arguments, 1, 1); + case "Q": + args = Split(command, arguments, 1, 1); ChatWindow.ChatCommand.Execute(args[0], this); break; case "BAN": From 568bce4add429c9ee04df967ab6516caeba5adcb Mon Sep 17 00:00:00 2001 From: Seven-7 Date: Wed, 31 Jan 2018 22:00:21 +0000 Subject: [PATCH 32/60] Implemented /debug command to view raw data --- .gitignore | 3 + Floe.UI/ChatControl/ChatControl_Commands.cs | 9 ++- Floe.UI/ChatWindow/ChatPage.cs | 3 +- Floe.UI/ChatWindow/ChatWindow_TreeView.cs | 17 +++- Floe.UI/DebugControl/DebugControl.xaml | 39 +++++++++ Floe.UI/DebugControl/DebugControl.xaml.cs | 88 +++++++++++++++++++++ Floe.UI/Floe.UI.csproj | 7 ++ 7 files changed, 163 insertions(+), 3 deletions(-) create mode 100644 Floe.UI/DebugControl/DebugControl.xaml create mode 100644 Floe.UI/DebugControl/DebugControl.xaml.cs diff --git a/.gitignore b/.gitignore index 0bc8230..b94ba44 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,6 @@ obj/ [Rr]elease*/ _ReSharper*/ [Tt]est[Rr]esult* +#Don't ignore DebugControl UI Control +!Floe.UI/DebugControl/ +!Floe.UI/DebugControl/* \ No newline at end of file diff --git a/Floe.UI/ChatControl/ChatControl_Commands.cs b/Floe.UI/ChatControl/ChatControl_Commands.cs index 458f9f6..76e1aba 100644 --- a/Floe.UI/ChatControl/ChatControl_Commands.cs +++ b/Floe.UI/ChatControl/ChatControl_Commands.cs @@ -357,7 +357,14 @@ private void Execute(string command, string arguments) switch (command) { - case "QUOTE": + case "DEBUG": + args = Split(command, arguments, 0, 1); + if (args.Length == 1) + App.Create(this.Session, new DebugControl.DebugControl(this.Session, args[0]), true); + else + App.ChatWindow.AddPage(new DebugControl.DebugControl(this.Session), true); + break; + case "QUOTE": args = Split(command, arguments, 1, 1); this.Session.Quote(args[0]); break; diff --git a/Floe.UI/ChatWindow/ChatPage.cs b/Floe.UI/ChatWindow/ChatPage.cs index 1cf154b..8d366b6 100644 --- a/Floe.UI/ChatWindow/ChatPage.cs +++ b/Floe.UI/ChatWindow/ChatPage.cs @@ -13,7 +13,8 @@ public enum ChatPageType Chat, DccFile, DccChat, - ChannelList + ChannelList, + Debug } public class ChatPage : UserControl, IDisposable diff --git a/Floe.UI/ChatWindow/ChatWindow_TreeView.cs b/Floe.UI/ChatWindow/ChatWindow_TreeView.cs index 3573476..a33aca6 100644 --- a/Floe.UI/ChatWindow/ChatWindow_TreeView.cs +++ b/Floe.UI/ChatWindow/ChatWindow_TreeView.cs @@ -92,7 +92,22 @@ public void OnPropertyChanged(string name) public class ChannelTreeViewItem : INotifyPropertyChanged { public ChatPage Page { get; private set; } - public string ChannelName { get { return Page.Target != null ? Page.Target.Name : "Channel List"; } } + public string ChannelName + { + get + { + if (Page.Target != null) + return Page.Target.Name; + + if (Page.Type == ChatPageType.ChannelList) + return "Channel List"; + + if (Page.Type == ChatPageType.Debug) + return Page.Id; + + return "Unknown ChatPageType"; + } + } public ContextMenu CloseMenu { get; private set; } diff --git a/Floe.UI/DebugControl/DebugControl.xaml b/Floe.UI/DebugControl/DebugControl.xaml new file mode 100644 index 0000000..e873df1 --- /dev/null +++ b/Floe.UI/DebugControl/DebugControl.xaml @@ -0,0 +1,39 @@ + + + + + + + + + + + + diff --git a/Floe.UI/DebugControl/DebugControl.xaml.cs b/Floe.UI/DebugControl/DebugControl.xaml.cs new file mode 100644 index 0000000..809a5d0 --- /dev/null +++ b/Floe.UI/DebugControl/DebugControl.xaml.cs @@ -0,0 +1,88 @@ +using Floe.Net; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Floe.UI.DebugControl +{ + /// + /// Interaction logic for DebugControl.xaml + /// + public partial class DebugControl : ChatPage + { + public DebugControl(IrcSession session, string id = "@debug") + : base(ChatPageType.Debug, session, null, id) + { + InitializeComponent(); + this.Header = base.Id; + this.Title = string.Format("{0} - {1} - Debug data on {2}", App.Product, this.Session.Nickname, this.Session.NetworkName); + SubscribeEvents(); + } + + private void SubscribeEvents() + { + this.Session.RawMessageReceived += new EventHandler(Session_RawMessageReceived); + this.Session.RawMessageSent += new EventHandler(Session_RawMessageSent); + } + + private void UnsubscribeEvents() + { + this.Session.RawMessageReceived -= new EventHandler(Session_RawMessageReceived); + this.Session.RawMessageSent -= new EventHandler(Session_RawMessageSent); + } + + private void Session_RawMessageReceived(object sender, IrcEventArgs e) + { + Write("Default", string.Format("[ IN] {0}", e.Message.ToString())); + } + + private void Session_RawMessageSent(object sender, IrcEventArgs e) + { + Write("Default", string.Format("[OUT] {0}", e.Message.ToString())); + } + + #region Write-ies + private void Write(string styleKey, DateTime date, int nickHashCode, string nick, string text) + { + var cl = new ChatLine(styleKey, date, nickHashCode, nick, text, ChatMarker.None); + + if (this.VisualParent == null) + { + this.NotifyState = NotifyState.ChatActivity; + } + + debugOutputBox.AppendLine(cl); + } + + private void Write(string styleKey, int nickHashCode, string nick, string text) + { + Write(styleKey, DateTime.Now, nickHashCode, nick, text); + } + + private void Write(string styleKey, DateTime date, string text) + { + this.Write(styleKey, date, 0, null, text); + } + + private void Write(string styleKey, string text) + { + this.Write(styleKey, DateTime.Now, 0, null, text); + } + #endregion + + public override void Dispose() + { + UnsubscribeEvents(); + } + } +} diff --git a/Floe.UI/Floe.UI.csproj b/Floe.UI/Floe.UI.csproj index 729c47a..3075781 100644 --- a/Floe.UI/Floe.UI.csproj +++ b/Floe.UI/Floe.UI.csproj @@ -151,6 +151,9 @@ + + DebugControl.xaml + ConfirmDialog.xaml @@ -214,6 +217,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile From 3799d94b9f6f23beb3b7e9649209146d665d0dd6 Mon Sep 17 00:00:00 2001 From: Seven-7 Date: Wed, 31 Jan 2018 22:15:20 +0000 Subject: [PATCH 33/60] Probably would be better to stick to tabbed identing --- Floe.UI/ChatControl/ChatControl_Commands.cs | 14 +- Floe.UI/ChatWindow/ChatPage.cs | 2 +- Floe.UI/ChatWindow/ChatWindow_TreeView.cs | 38 +++--- Floe.UI/DebugControl/DebugControl.xaml.cs | 134 +++++++++----------- 4 files changed, 88 insertions(+), 100 deletions(-) diff --git a/Floe.UI/ChatControl/ChatControl_Commands.cs b/Floe.UI/ChatControl/ChatControl_Commands.cs index 76e1aba..b3c6486 100644 --- a/Floe.UI/ChatControl/ChatControl_Commands.cs +++ b/Floe.UI/ChatControl/ChatControl_Commands.cs @@ -357,13 +357,13 @@ private void Execute(string command, string arguments) switch (command) { - case "DEBUG": - args = Split(command, arguments, 0, 1); - if (args.Length == 1) - App.Create(this.Session, new DebugControl.DebugControl(this.Session, args[0]), true); - else - App.ChatWindow.AddPage(new DebugControl.DebugControl(this.Session), true); - break; + case "DEBUG": + args = Split(command, arguments, 0, 1); + if (args.Length == 1) + App.Create(this.Session, new DebugControl.DebugControl(this.Session, args[0]), true); + else + App.ChatWindow.AddPage(new DebugControl.DebugControl(this.Session), true); + break; case "QUOTE": args = Split(command, arguments, 1, 1); this.Session.Quote(args[0]); diff --git a/Floe.UI/ChatWindow/ChatPage.cs b/Floe.UI/ChatWindow/ChatPage.cs index 8d366b6..3ed60f1 100644 --- a/Floe.UI/ChatWindow/ChatPage.cs +++ b/Floe.UI/ChatWindow/ChatPage.cs @@ -14,7 +14,7 @@ public enum ChatPageType DccFile, DccChat, ChannelList, - Debug + Debug } public class ChatPage : UserControl, IDisposable diff --git a/Floe.UI/ChatWindow/ChatWindow_TreeView.cs b/Floe.UI/ChatWindow/ChatWindow_TreeView.cs index a33aca6..89efd16 100644 --- a/Floe.UI/ChatWindow/ChatWindow_TreeView.cs +++ b/Floe.UI/ChatWindow/ChatWindow_TreeView.cs @@ -93,23 +93,23 @@ public class ChannelTreeViewItem : INotifyPropertyChanged { public ChatPage Page { get; private set; } public string ChannelName - { - get - { - if (Page.Target != null) - return Page.Target.Name; + { + get + { + if (Page.Target != null) + return Page.Target.Name; - if (Page.Type == ChatPageType.ChannelList) - return "Channel List"; + if (Page.Type == ChatPageType.ChannelList) + return "Channel List"; - if (Page.Type == ChatPageType.Debug) - return Page.Id; + if (Page.Type == ChatPageType.Debug) + return Page.Id; - return "Unknown ChatPageType"; - } + return "Unknown ChatPageType"; + } } - public ContextMenu CloseMenu { get; private set; } + public ContextMenu CloseMenu { get; private set; } private string _activityColor; public string ActivityColor @@ -140,13 +140,13 @@ public ChannelTreeViewItem(ChatPage page) { this.ActivityColor = "Black"; this.Page = page; - this.Page.IsCloseable = true; - CloseMenu = new ContextMenu(); - MenuItem CloseItem = new MenuItem(); - CloseItem.Command = ChatWindow.CloseTabCommand; - CloseItem.CommandParameter = this.Page; - CloseMenu.Items.Add(CloseItem); - } + this.Page.IsCloseable = true; + CloseMenu = new ContextMenu(); + MenuItem CloseItem = new MenuItem(); + CloseItem.Command = ChatWindow.CloseTabCommand; + CloseItem.CommandParameter = this.Page; + CloseMenu.Items.Add(CloseItem); + } public void OnNotifyStateChanged() { diff --git a/Floe.UI/DebugControl/DebugControl.xaml.cs b/Floe.UI/DebugControl/DebugControl.xaml.cs index 809a5d0..b48a280 100644 --- a/Floe.UI/DebugControl/DebugControl.xaml.cs +++ b/Floe.UI/DebugControl/DebugControl.xaml.cs @@ -1,88 +1,76 @@ -using Floe.Net; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; +using System; +using Floe.Net; namespace Floe.UI.DebugControl { - /// - /// Interaction logic for DebugControl.xaml - /// - public partial class DebugControl : ChatPage - { - public DebugControl(IrcSession session, string id = "@debug") - : base(ChatPageType.Debug, session, null, id) - { - InitializeComponent(); - this.Header = base.Id; - this.Title = string.Format("{0} - {1} - Debug data on {2}", App.Product, this.Session.Nickname, this.Session.NetworkName); - SubscribeEvents(); - } + /// + /// Interaction logic for DebugControl.xaml + /// + public partial class DebugControl : ChatPage + { + public DebugControl(IrcSession session, string id = "@debug") + : base(ChatPageType.Debug, session, null, id) + { + InitializeComponent(); + this.Header = base.Id; + this.Title = string.Format("{0} - {1} - Debug data on {2}", App.Product, this.Session.Nickname, this.Session.NetworkName); + SubscribeEvents(); + } - private void SubscribeEvents() - { - this.Session.RawMessageReceived += new EventHandler(Session_RawMessageReceived); - this.Session.RawMessageSent += new EventHandler(Session_RawMessageSent); - } + private void SubscribeEvents() + { + this.Session.RawMessageReceived += new EventHandler(Session_RawMessageReceived); + this.Session.RawMessageSent += new EventHandler(Session_RawMessageSent); + } - private void UnsubscribeEvents() - { - this.Session.RawMessageReceived -= new EventHandler(Session_RawMessageReceived); - this.Session.RawMessageSent -= new EventHandler(Session_RawMessageSent); - } + private void UnsubscribeEvents() + { + this.Session.RawMessageReceived -= new EventHandler(Session_RawMessageReceived); + this.Session.RawMessageSent -= new EventHandler(Session_RawMessageSent); + } - private void Session_RawMessageReceived(object sender, IrcEventArgs e) - { - Write("Default", string.Format("[ IN] {0}", e.Message.ToString())); - } + private void Session_RawMessageReceived(object sender, IrcEventArgs e) + { + Write("Default", string.Format("[ IN] {0}", e.Message.ToString())); + } - private void Session_RawMessageSent(object sender, IrcEventArgs e) - { - Write("Default", string.Format("[OUT] {0}", e.Message.ToString())); - } + private void Session_RawMessageSent(object sender, IrcEventArgs e) + { + Write("Default", string.Format("[OUT] {0}", e.Message.ToString())); + } - #region Write-ies - private void Write(string styleKey, DateTime date, int nickHashCode, string nick, string text) - { - var cl = new ChatLine(styleKey, date, nickHashCode, nick, text, ChatMarker.None); + #region Write-ies + private void Write(string styleKey, DateTime date, int nickHashCode, string nick, string text) + { + var cl = new ChatLine(styleKey, date, nickHashCode, nick, text, ChatMarker.None); - if (this.VisualParent == null) - { - this.NotifyState = NotifyState.ChatActivity; - } + if (this.VisualParent == null) + { + this.NotifyState = NotifyState.ChatActivity; + } - debugOutputBox.AppendLine(cl); - } + debugOutputBox.AppendLine(cl); + } - private void Write(string styleKey, int nickHashCode, string nick, string text) - { - Write(styleKey, DateTime.Now, nickHashCode, nick, text); - } + private void Write(string styleKey, int nickHashCode, string nick, string text) + { + Write(styleKey, DateTime.Now, nickHashCode, nick, text); + } - private void Write(string styleKey, DateTime date, string text) - { - this.Write(styleKey, date, 0, null, text); - } + private void Write(string styleKey, DateTime date, string text) + { + this.Write(styleKey, date, 0, null, text); + } - private void Write(string styleKey, string text) - { - this.Write(styleKey, DateTime.Now, 0, null, text); - } - #endregion + private void Write(string styleKey, string text) + { + this.Write(styleKey, DateTime.Now, 0, null, text); + } + #endregion - public override void Dispose() - { - UnsubscribeEvents(); - } - } + public override void Dispose() + { + UnsubscribeEvents(); + } + } } From 1e4e387a361550bb8371e9feead8956edb62643f Mon Sep 17 00:00:00 2001 From: Seven-7 Date: Wed, 31 Jan 2018 22:19:07 +0000 Subject: [PATCH 34/60] Nah ... --- Floe.UI/ChatWindow/ChatWindow_TreeView.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Floe.UI/ChatWindow/ChatWindow_TreeView.cs b/Floe.UI/ChatWindow/ChatWindow_TreeView.cs index 89efd16..518583f 100644 --- a/Floe.UI/ChatWindow/ChatWindow_TreeView.cs +++ b/Floe.UI/ChatWindow/ChatWindow_TreeView.cs @@ -107,7 +107,7 @@ public string ChannelName return "Unknown ChatPageType"; } - } + } public ContextMenu CloseMenu { get; private set; } @@ -148,7 +148,7 @@ public ChannelTreeViewItem(ChatPage page) CloseMenu.Items.Add(CloseItem); } - public void OnNotifyStateChanged() + public void OnNotifyStateChanged() { if (Page.NotifyState == NotifyState.None) ActivityColor = "Black"; From 485eebd38f2dfb72f17a8656ea6c090e5a58c0c5 Mon Sep 17 00:00:00 2001 From: Seven-7 Date: Mon, 26 Feb 2018 21:30:09 +0000 Subject: [PATCH 35/60] Implemented ChannelInfoWindow, started UserInfoWindow --- Floe.Net/Floe.Net.csproj | 1 + Floe.Net/Irc/IrcMessage.cs | 2 +- Floe.Net/Irc/IrcSession.cs | 16 + Floe.Net/Utils/UnixTimeStamp.cs | 113 ++ Floe.UI/ChatControl/ChatControl.xaml | 20 +- Floe.UI/ChatControl/ChatControl.xaml.cs | 10 +- Floe.UI/ChatControl/ChatControl_Commands.cs | 47 +- Floe.UI/ChatControl/ChatControl_Events.cs | 28 +- Floe.UI/ChatWindow/ChatPage.cs | 2 + Floe.UI/Floe.UI.csproj | 14 + Floe.UI/InfoWindows/ChannelInfoWindow.xaml | 127 ++ Floe.UI/InfoWindows/ChannelInfoWindow.xaml.cs | 1020 +++++++++++++++++ Floe.UI/InfoWindows/UserInfoWindow.xaml | 12 + Floe.UI/InfoWindows/UserInfoWindow.xaml.cs | 177 +++ 14 files changed, 1572 insertions(+), 17 deletions(-) create mode 100644 Floe.Net/Utils/UnixTimeStamp.cs create mode 100644 Floe.UI/InfoWindows/ChannelInfoWindow.xaml create mode 100644 Floe.UI/InfoWindows/ChannelInfoWindow.xaml.cs create mode 100644 Floe.UI/InfoWindows/UserInfoWindow.xaml create mode 100644 Floe.UI/InfoWindows/UserInfoWindow.xaml.cs diff --git a/Floe.Net/Floe.Net.csproj b/Floe.Net/Floe.Net.csproj index 0b7b8ef..5c3099c 100644 --- a/Floe.Net/Floe.Net.csproj +++ b/Floe.Net/Floe.Net.csproj @@ -83,6 +83,7 @@ + diff --git a/Floe.Net/Irc/IrcMessage.cs b/Floe.Net/Irc/IrcMessage.cs index d7c26c1..c4aefa8 100644 --- a/Floe.Net/Irc/IrcMessage.cs +++ b/Floe.Net/Irc/IrcMessage.cs @@ -78,7 +78,7 @@ public override string ToString() } sb.Append(' '); - if ((i == this.Parameters.Count - 1) && (this.Command != "PASS")) + if ((i == this.Parameters.Count - 1) && (this.Command != "PASS") && (this.Parameters[i] != ":")) sb.Append(':'); sb.Append(this.Parameters[i]); } diff --git a/Floe.Net/Irc/IrcSession.cs b/Floe.Net/Irc/IrcSession.cs index a7f0bc3..0f68fe5 100644 --- a/Floe.Net/Irc/IrcSession.cs +++ b/Floe.Net/Irc/IrcSession.cs @@ -508,6 +508,14 @@ public void Topic(string channel) this.Send("TOPIC", channel); } + /// + /// Query the actual list of channels invited to. + /// + public void Invite() + { + this.Send("INVITE"); + } + /// /// Invite another user to a channel. The session must have the appropriate permissions on the channel. /// @@ -763,6 +771,14 @@ public bool RemoveHandler(IrcCodeHandler capture) } } + public bool ContainsHandler(IrcCodeHandler capture) + { + lock (_captures) + { + return _captures.Contains(capture); + } + } + private void RaiseEvent(EventHandler evt, T e) where T : EventArgs { if (evt != null) diff --git a/Floe.Net/Utils/UnixTimeStamp.cs b/Floe.Net/Utils/UnixTimeStamp.cs new file mode 100644 index 0000000..35b1c91 --- /dev/null +++ b/Floe.Net/Utils/UnixTimeStamp.cs @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2010-2012 Dani J + * Copyright (C) 2016 Gergo F. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Floe.Net +{ + /// + /// Converts a DateTime to and from a Unix timestamp + /// (number of seconds since 1-1-1970) + /// + public class UnixTimestamp + { + /// + /// Default constructor + /// + public UnixTimestamp() + { + Timestamp = 0; + } + /// + /// Constructs a UnixTimestamp from an integer value + /// + /// + public UnixTimestamp(int timestamp) + { + Timestamp = timestamp; + } + /// + /// Constructs a UnixTimestamp from a DateTime value + /// + /// + public UnixTimestamp(DateTime dateTime) + { + DateTime = dateTime; + } + /// + /// Gets or sets the timestamp + /// + public int Timestamp { get; set; } + /// + /// Gets or sets the timestamp + /// + public DateTime DateTime + { + get + { + return DateTimeFromTimestamp(Timestamp); + } + set + { + Timestamp = TimestampFromDateTime(value); + } + } + /// + /// Converts a UnixTimestamp to a string + /// + /// + public override string ToString() + { + return Timestamp.ToString(); + } + /// + /// Calculates the current timestamp + /// + /// + public static UnixTimestamp CurrentTimestamp() + { + return new UnixTimestamp( + (int)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds + ); + } + /// + /// Converts a DateTime to a timestamp + /// + /// + /// + public static int TimestampFromDateTime(DateTime value) + { + return (int)(value - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds; + } + /// + /// Converts a timestamp to a DateTime + /// + /// + /// + public static DateTime DateTimeFromTimestamp(int value) + { + DateTime result = new DateTime(1970, 1, 1, 0, 0, 0); + result = result.AddSeconds(value); + result = result.Add(DateTime.Now - DateTime.UtcNow); + return result; + } + } +} diff --git a/Floe.UI/ChatControl/ChatControl.xaml b/Floe.UI/ChatControl/ChatControl.xaml index acda8ed..cb817ba 100755 --- a/Floe.UI/ChatControl/ChatControl.xaml +++ b/Floe.UI/ChatControl/ChatControl.xaml @@ -13,7 +13,8 @@ - + + @@ -38,7 +39,9 @@ - + + + @@ -102,11 +105,20 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Floe.UI/InfoWindows/ChannelInfoWindow.xaml.cs b/Floe.UI/InfoWindows/ChannelInfoWindow.xaml.cs new file mode 100644 index 0000000..b4ca590 --- /dev/null +++ b/Floe.UI/InfoWindows/ChannelInfoWindow.xaml.cs @@ -0,0 +1,1020 @@ +using System; +using System.Windows; +using System.ComponentModel; +using System.Collections.Generic; +using System.Windows.Controls; +using System.Windows.Input; +using System.Windows.Media; +using System.Collections.ObjectModel; +using System.Windows.Controls.Primitives; +using System.Linq; +using System.Windows.Data; +using Floe.Net; + +namespace Floe.UI +{ + public class InviteItem + { + public string InvitedTo { get; } + public string InvitedBy { get; } + public DateTime? Timestamp { get; } + + public InviteItem(string invitedTo, string invitedBy, DateTime? timestamp) + { + this.InvitedTo = invitedTo; + this.InvitedBy = invitedBy; + this.Timestamp = timestamp; + } + + public InviteItem(string invitedTo) : this(invitedTo, null, null) + { + } + } +} + +namespace Floe.UI.InfoWindows +{ + public class MaskItem + { + public string Mask { get; set; } + public string SetBy { get; private set; } + public DateTime Timestamp { get; private set; } + + public MaskItem(string mask, string setby, DateTime timestamp) + { + Mask = mask; + SetBy = setby; + Timestamp = timestamp; + } + } + + public class BanItem : MaskItem + { + public BanItem(string mask, string setby, DateTime timestamp) + :base(mask, setby, timestamp) + { + + } + } + + public class ExceptItem : MaskItem + { + public ExceptItem(string mask, string setby, DateTime timestamp) + : base(mask, setby, timestamp) + { + + } + } + + public class MaskListType : ObservableCollection + { + private int _selectedMaskIndex = -1; + public int SelectedMaskIndex + { + get + { + return _selectedMaskIndex; + } + set + { + _selectedMaskIndex = value; + ChannelInfoWindow.IsBanChanged = false; + ChannelInfoWindow.IsExceptChanged = false; + if (typeof(T) == typeof(BanItem)) + ChannelInfoWindow.IsBanChanged = true; + if (typeof(T) == typeof(ExceptItem)) + ChannelInfoWindow.IsExceptChanged = true; + } + } + + public T SelectedMaskItem + { + get + { + if (SelectedMaskIndex > -1) + return this[SelectedMaskIndex]; + else + return default(T); + } + } + } + + public class BanListType : MaskListType + { } + + public class ExceptListType : MaskListType + { } + + /// + /// Interaction logic for ChannelInfoWindow.xaml + /// + public partial class ChannelInfoWindow : Window, INotifyPropertyChanged + { + public static bool IsBanChanged = false; + public static bool IsExceptChanged = false; + private bool IsNewRowAdding = false; + private bool bSkipKeySet = false; + private ChatControl ChatControl; + private readonly IrcSession Session; + private readonly IrcTarget Target; + + public readonly static RoutedUICommand AddBanMaskCommand = new RoutedUICommand("Add", "AddBanMask", typeof(ChannelInfoWindow)); + public readonly static RoutedUICommand EditBanMaskCommand = new RoutedUICommand("Edit", "EditBanMask", typeof(ChannelInfoWindow)); + public readonly static RoutedUICommand RemoveBanMaskCommand = new RoutedUICommand("Remove", "RemoveBanMask", typeof(ChannelInfoWindow)); + + public readonly static RoutedUICommand Mode_s_Command = new RoutedUICommand("Mode s toggle", "Mode_s_toggle", typeof(ChannelInfoWindow)); + public readonly static RoutedUICommand Mode_p_Command = new RoutedUICommand("Mode p toggle", "Mode_p_toggle", typeof(ChannelInfoWindow)); + public readonly static RoutedUICommand Mode_m_Command = new RoutedUICommand("Mode m toggle", "Mode_m_toggle", typeof(ChannelInfoWindow)); + public readonly static RoutedUICommand Mode_t_Command = new RoutedUICommand("Mode t toggle", "Mode_t_toggle", typeof(ChannelInfoWindow)); + public readonly static RoutedUICommand Mode_i_Command = new RoutedUICommand("Mode i toggle", "Mode_i_toggle", typeof(ChannelInfoWindow)); + public readonly static RoutedUICommand Mode_n_Command = new RoutedUICommand("Mode n toggle", "Mode_n_toggle", typeof(ChannelInfoWindow)); + public readonly static RoutedUICommand Mode_r_Command = new RoutedUICommand("Mode r toggle", "Mode_r_toggle", typeof(ChannelInfoWindow)); + public readonly static RoutedUICommand Mode_D_Command = new RoutedUICommand("Mode D toggle", "Mode_D_toggle", typeof(ChannelInfoWindow)); + public readonly static RoutedUICommand Mode_d_Command = new RoutedUICommand("Mode d toggle", "Mode_d_toggle", typeof(ChannelInfoWindow)); + public readonly static RoutedUICommand Mode_R_Command = new RoutedUICommand("Mode R toggle", "Mode_R_toggle", typeof(ChannelInfoWindow)); + public readonly static RoutedUICommand Mode_l_Command = new RoutedUICommand("Mode l toggle", "Mode_l_toggle", typeof(ChannelInfoWindow)); + public readonly static RoutedUICommand Mode_k_Command = new RoutedUICommand("Mode k toggle", "Mode_k_toggle", typeof(ChannelInfoWindow)); + + private string _topicStr; + public string TopicStr + { + get { return _topicStr; } + set + { + if ((_topicStr != value) && ((!this.Session.ContainsHandler(topicHandler)) && (!this.Session.ContainsHandler(noTopicHandler)))) + { + if (String.IsNullOrEmpty(value)) + this.Session.Topic(this.Target.Name, ":"); + else + this.Session.Topic(this.Target.Name, value); + } + _topicStr = value; + OnPropertyChanged("TopicStr"); + } + } + + private string _limitStrNr; + public string LimitStrNr + { + get { return _limitStrNr; } + set + { + if (!String.IsNullOrEmpty(value) && !int.TryParse(value, out int intval)) + return; + + if ((_limitStrNr != value) && (!this.Session.ContainsHandler(modesHandler))) + { + if (!String.IsNullOrEmpty(value)) + this.Session.Mode(this.Target.Name, "+l " + value); + else + this.Session.Mode(this.Target.Name, "-l"); + } + _limitStrNr = value; + OnPropertyChanged("LimitStrNr"); + } + } + + private string _keyStr; + public string KeyStr + { + get { return _keyStr; } + set + { + if ((_keyStr != value) && (!this.Session.ContainsHandler(modesHandler))) + { + if (!String.IsNullOrEmpty(value)) + { + if (!String.IsNullOrEmpty(_keyStr)) + { + bSkipKeySet = true; + this.Session.Mode(this.Target.Name, "-k " + _keyStr); + } + this.Session.Mode(this.Target.Name, "+k " + value); + } + else if (!String.IsNullOrEmpty(_keyStr)) + this.Session.Mode(this.Target.Name, "-k " + _keyStr); + } + _keyStr = value; + OnPropertyChanged("KeyStr"); + } + } + + #region Mode_x_Toggleds + private bool _mode_s_Toggled; + public bool Mode_s_Toggled + { + get { return _mode_s_Toggled; } + set { _mode_s_Toggled = value; OnPropertyChanged("Mode_s_Toggled"); } + } + + private bool _mode_p_Toggled; + public bool Mode_p_Toggled + { + get { return _mode_p_Toggled; } + set { _mode_p_Toggled = value; OnPropertyChanged("Mode_p_Toggled"); } + } + + private bool _mode_m_Toggled; + public bool Mode_m_Toggled + { + get { return _mode_m_Toggled; } + set { _mode_m_Toggled = value; OnPropertyChanged("Mode_m_Toggled"); } + } + + private bool _mode_t_Toggled; + public bool Mode_t_Toggled + { + get { return _mode_t_Toggled; } + set { _mode_t_Toggled = value; OnPropertyChanged("Mode_t_Toggled"); } + } + + private bool _mode_i_Toggled; + public bool Mode_i_Toggled + { + get { return _mode_i_Toggled; } + set { _mode_i_Toggled = value; OnPropertyChanged("Mode_i_Toggled"); } + } + + private bool _mode_n_Toggled; + public bool Mode_n_Toggled + { + get { return _mode_n_Toggled; } + set { _mode_n_Toggled = value; OnPropertyChanged("Mode_n_Toggled"); } + } + + private bool _mode_r_Toggled; + public bool Mode_r_Toggled + { + get { return _mode_r_Toggled; } + set { _mode_r_Toggled = value; OnPropertyChanged("Mode_r_Toggled"); } + } + + private bool _mode_D_Toggled; + public bool Mode_D_Toggled + { + get { return _mode_D_Toggled; } + set { _mode_D_Toggled = value; OnPropertyChanged("Mode_D_Toggled"); } + } + + private bool _mode_d_Toggled; + public bool Mode_d_Toggled + { + get { return _mode_d_Toggled; } + set { _mode_d_Toggled = value; OnPropertyChanged("Mode_d_Toggled"); } + } + + private bool _mode_R_Toggled; + public bool Mode_R_Toggled + { + get { return _mode_R_Toggled; } + set { _mode_R_Toggled = value; OnPropertyChanged("Mode_R_Toggled"); } + } + + private bool _mode_l_Toggled; + public bool Mode_l_Toggled + { + get { return _mode_l_Toggled; } + set { _mode_l_Toggled = value; OnPropertyChanged("Mode_l_Toggled"); } + } + + private bool _mode_k_Toggled; + public bool Mode_k_Toggled + { + get { return _mode_k_Toggled; } + set { _mode_k_Toggled = value; OnPropertyChanged("Mode_k_Toggled"); } + } + #endregion + + public BanListType BanList { get; set; } + private List burstBanList; + private List burstExceptList; + public ExceptListType ExceptsList { get; set; } + public ObservableCollection InvitesList { get; private set; } + + private IrcCodeHandler noTopicHandler, topicHandler, topicSetByHandler; + private IrcCodeHandler modesHandler, channelCreatedOnHandler; + private IrcCodeHandler bansHandler, bansEndHandler; + private IrcCodeHandler exceptionsHandler, exceptionsEndHandler; + private IrcCodeHandler invitesHandler, invitesEndHandler; + + public event PropertyChangedEventHandler PropertyChanged; + + public void OnPropertyChanged(string name) + { + var handler = this.PropertyChanged; + if (handler != null) + { + handler(this, new PropertyChangedEventArgs(name)); + } + } + + public ChannelInfoWindow(ChatControl chatControl) + { + this.ChatControl = chatControl; + this.Session = this.ChatControl.Session; + this.Target = this.ChatControl.Target; + InitializeComponent(); + this.Title = "Channel info " + Target.Name; + BanList = new BanListType(); + burstBanList = new List(); + burstExceptList = new List(); + ExceptsList = new ExceptListType(); + InvitesList = ChatControl.InvitesList; + SubscribeEvents(); + CaptureTopic(); + CaptureModes(); + CaptureBans(); + CaptureExceptions(); + CaptureInvites(); + this.DataContext = this; + } + + private void CaptureTopic() + { + noTopicHandler = new IrcCodeHandler((e) => + { + TopicStr = null; + e.Handled = true; + return true; + }, IrcCode.RPL_NOTOPIC); + + topicHandler = new IrcCodeHandler((e) => + { + TopicStr = e.Message.Parameters[2]; + e.Handled = true; + return true; + }, IrcCode.RPL_TOPIC); + + topicSetByHandler = new IrcCodeHandler((e) => + { + e.Handled = true; + return true; + }, IrcCode.RPL_TOPICSETBY); + + this.Session.AddHandler(topicHandler); + this.Session.AddHandler(noTopicHandler); + this.Session.AddHandler(topicSetByHandler); + this.Session.Topic(this.Target.Name); + } + + private void CaptureModes() + { + modesHandler = new IrcCodeHandler((e) => + { + ToggleModeButtons(IrcChannelMode.ParseModes(String.Join(" ", e.Message.Parameters.Skip(2)))); + e.Handled = true; + return true; + }, IrcCode.RPL_CHANNELMODEIS); + + channelCreatedOnHandler = new IrcCodeHandler((e) => + { + e.Handled = true; + return true; + }, IrcCode.RPL_CHANNELCREATEDON); + + this.Session.AddHandler(modesHandler); + this.Session.AddHandler(channelCreatedOnHandler); + this.Session.Mode(this.Target); + } + + private void CaptureBans() + { + bansHandler = new IrcCodeHandler((e) => + { + if (e.Message.Parameters.Count == 5 && this.Target.Equals(new IrcTarget(e.Message.Parameters[1]))) + { + burstBanList.Add(new BanItem(e.Message.Parameters[2], e.Message.Parameters[3], UnixTimestamp.DateTimeFromTimestamp(int.Parse(e.Message.Parameters[4])))); + } + this.Session.AddHandler(bansHandler); + e.Handled = true; + return true; + }, IrcCode.RPL_BANLIST); + + bansEndHandler = new IrcCodeHandler((e) => + { + this.Session.RemoveHandler(bansHandler); + burstBanList = burstBanList.OrderBy(b => b.Timestamp).ToList(); + foreach (BanItem item in burstBanList) + BanList.Add(item); + e.Handled = true; + return true; + }, IrcCode.RPL_ENDOFBANLIST); + + this.Session.AddHandler(bansHandler); + this.Session.AddHandler(bansEndHandler); + this.Session.Mode(this.Target.Name, "+b"); + } + + private void CaptureExceptions() + { + exceptionsHandler = new IrcCodeHandler((e) => + { + if (e.Message.Parameters.Count == 5 && this.Target.Equals(new IrcTarget(e.Message.Parameters[1]))) + { + burstExceptList.Add(new ExceptItem(e.Message.Parameters[2], e.Message.Parameters[3], UnixTimestamp.DateTimeFromTimestamp(int.Parse(e.Message.Parameters[4])))); + } + this.Session.AddHandler(exceptionsHandler); + e.Handled = true; + return true; + }, IrcCode.RPL_EXCEPTLIST); + + exceptionsEndHandler = new IrcCodeHandler((e) => + { + this.Session.RemoveHandler(exceptionsHandler); + burstExceptList = burstExceptList.OrderBy(b => b.Timestamp).ToList(); + foreach (ExceptItem item in burstExceptList) + ExceptsList.Add(item); + e.Handled = true; + return true; + }, IrcCode.RPL_ENDOFEXCEPTLIST); + + this.Session.AddHandler(exceptionsHandler); + this.Session.AddHandler(exceptionsEndHandler); + this.Session.Mode(this.Target.Name, "+e"); + } + + private void CaptureInvites() + { + invitesHandler = new IrcCodeHandler((e) => + { + // ** Disabled, since ircds sends only the invited channel names without the other paramters like who sent the invite, + // so we use ChatControl's always complete InvitesList ** // + //InvitesList.Add(new InviteItem(e.Text)); + //this.Session.AddHandler(invitesHandler); + e.Handled = true; + return true; + }, IrcCode.RPL_INVITELIST); + + invitesEndHandler = new IrcCodeHandler((e) => + { + this.Session.RemoveHandler(noTopicHandler); + this.Session.RemoveHandler(topicHandler); + this.Session.RemoveHandler(topicSetByHandler); + this.Session.RemoveHandler(modesHandler); + this.Session.RemoveHandler(channelCreatedOnHandler); + this.Session.RemoveHandler(bansHandler); + this.Session.RemoveHandler(bansEndHandler); + this.Session.RemoveHandler(exceptionsHandler); + this.Session.RemoveHandler(exceptionsEndHandler); + this.Session.RemoveHandler(invitesHandler); + this.Session.RemoveHandler(invitesEndHandler); + e.Handled = true; + return true; + }, IrcCode.RPL_ENDOFINVITELIST); + + this.Session.AddHandler(invitesHandler); + this.Session.AddHandler(invitesEndHandler); + this.Session.Invite(); + } + + private void SubscribeEvents() + { + this.Session.InfoReceived += new EventHandler(Session_InfoReceived); + this.Session.TopicChanged += new EventHandler(Session_TopicChanged); + this.Session.ChannelModeChanged += new EventHandler(Session_ChannelModeChanged); + this.Session.Invited += new EventHandler(Session_Invited); + } + + private void UnsubscribeEvents() + { + this.Session.InfoReceived -= new EventHandler(Session_InfoReceived); + this.Session.TopicChanged -= new EventHandler(Session_TopicChanged); + this.Session.ChannelModeChanged -= new EventHandler(Session_ChannelModeChanged); + this.Session.Invited -= new EventHandler(Session_Invited); + } + + private void Session_InfoReceived(object sender, IrcInfoEventArgs e) + { + switch (e.Code) + { + case IrcCode.RPL_TOPIC: + if (e.Message.Parameters.Count == 3 && this.Target.Equals(new IrcTarget(e.Message.Parameters[1]))) + { + TopicStr = e.Message.Parameters[2]; + } + return; + case IrcCode.RPL_TOPICSETBY: + if (e.Message.Parameters.Count == 4 && this.Target.Equals(new IrcTarget(e.Message.Parameters[1]))) + { + //string TopicSetBy = e.Message.Parameters[2]; + //string TopicSetOn = ChatControl.FormatTime(e.Message.Parameters[3]); + } + return; + case IrcCode.RPL_CHANNELCREATEDON: + if (e.Message.Parameters.Count == 3 && this.Target.Equals(new IrcTarget(e.Message.Parameters[1]))) + { + //string ChannelCreatedOn = ChatControl.FormatTime(e.Message.Parameters[2]); + } + return; + case IrcCode.RPL_BANLIST: + if (e.Message.Parameters.Count == 5 && this.Target.Equals(new IrcTarget(e.Message.Parameters[1]))) + { + BanList.Add(new BanItem(e.Message.Parameters[2], e.Message.Parameters[3], UnixTimestamp.DateTimeFromTimestamp(int.Parse(e.Message.Parameters[4])))); + } + return; + case IrcCode.RPL_ENDOFBANLIST: + { + } + return; + case IrcCode.RPL_EXCEPTLIST: + if (e.Message.Parameters.Count == 5 && this.Target.Equals(new IrcTarget(e.Message.Parameters[1]))) + { + ExceptsList.Add(new ExceptItem(e.Message.Parameters[2], e.Message.Parameters[3], UnixTimestamp.DateTimeFromTimestamp(int.Parse(e.Message.Parameters[4])))); + } + return; + case IrcCode.RPL_ENDOFEXCEPTLIST: + { + } + return; + default: + { + e.Handled = true; + } + break; + } + } + + protected override void OnClosing(CancelEventArgs e) + { + base.OnClosing(e); + UnsubscribeEvents(); + } + + private void Session_TopicChanged(object sender, IrcTopicEventArgs e) + { + TopicStr = e.Text; + } + + private void Session_ChannelModeChanged(object sender, IrcChannelModeEventArgs e) + { + ToggleModeButtons(e.Modes); + + IrcChannelMode modeBan = e.Modes.Where(m => m.Mode == 'b').FirstOrDefault(); + var From = IrcPrefix.Parse(e.Who.Prefix); + string setby = From.Prefix; + if (From is IrcPeer FromNick) + setby = FromNick.Nickname; + if (modeBan.Mode != Char.MinValue) + { + if (modeBan.Set == true) + { + BanItem NewBanItem = new BanItem(modeBan.Parameter, setby, DateTime.Now); + IsNewRowAdding = true; + BanList.Add(NewBanItem); + } + if (modeBan.Set == false) + { + BanList.Remove(BanList.Where(b => b.Mask == modeBan.Parameter).FirstOrDefault()); + } + } + IrcChannelMode modeExcept = e.Modes.Where(m => m.Mode == 'e').FirstOrDefault(); + if (modeExcept.Mode != Char.MinValue) + { + if (modeExcept.Set == true) + { + ExceptItem NewExceptItem = new ExceptItem(modeExcept.Parameter, setby, DateTime.Now); + IsNewRowAdding = true; + ExceptsList.Add(NewExceptItem); + } + if (modeExcept.Set == false) + { + ExceptsList.Remove(ExceptsList.Where(b => b.Mask == modeExcept.Parameter).FirstOrDefault()); + } + } + } + + private void Session_Invited(object sender, IrcInviteEventArgs e) + { + InvitesList.Add(new InviteItem(e.Channel, e.From.Nickname, DateTime.Now)); + } + + private void ExecuteAddBanMask(object sender, ExecutedRoutedEventArgs e) + { + DataGrid BanGrid = (DataGrid)sender; + MaskItem NewItem = null; + if (IsBanChanged == false && IsExceptChanged == false) + { + if (BanGrid.ItemsSource.GetType() == typeof(BanListType)) + IsBanChanged = true; + if (BanGrid.ItemsSource.GetType() == typeof(ExceptListType)) + IsExceptChanged = true; + } + if (IsBanChanged) + { + BanItem NewBan = new BanItem("", "You", DateTime.Now); + NewItem = NewBan; + BanList.Add(NewBan); + } + if (IsExceptChanged) + { + ExceptItem NewExcept = new ExceptItem("", "You", DateTime.Now); + NewItem = NewExcept; + ExceptsList.Add(NewExcept); + } + if (BanGrid != null && NewItem != null) + { + BanGrid.SelectedItem = NewItem; + BanGrid.ScrollIntoView(NewItem); + EnterEditMaskCell(BanGrid); + } + return; + } + + private void ExecuteEditBanMask(object sender, ExecutedRoutedEventArgs e) + { + DataGrid BanGrid = (DataGrid)sender; + EnterEditMaskCell(BanGrid); + } + + private void ExecuteRemoveBanMask(object sender, ExecutedRoutedEventArgs e) + { + MessageBoxResult res = MessageBox.Show("Are you sure you want to remove?", "Confirmation!", MessageBoxButton.YesNo, MessageBoxImage.Warning); + if (res == MessageBoxResult.Yes) + { + if (IsBanChanged) + this.Session.Mode(this.Target.Name, "-b " + BanList[BanList.SelectedMaskIndex].Mask); + if (IsExceptChanged) + this.Session.Mode(this.Target.Name, "-e " + ExceptsList[ExceptsList.SelectedMaskIndex].Mask); + } + e.Handled = (res == MessageBoxResult.No); + return; + } + + public bool IsOp() + { + if (!this.ChatControl.IsChannel || !this.ChatControl.Nicknames.Contains(this.Session.Nickname)) + { + return false; + } + var nick = this.ChatControl.Nicknames[this.Session.Nickname]; + return nick != null && (nick.Level & ChannelLevel.Op) > 0; + } + + private void CanExecuteIsOp(object sender, CanExecuteRoutedEventArgs e) + { + bool enabled = IsOp(); + e.CanExecute = enabled; + //ToggleButton TgBttn = e.Source as ToggleButton; + //if (TgBttn != null && TgBttn.IsChecked == true && enabled == false) + // TgBttn.Background = Brushes.Bisque; + if (LimTxtBx != null) + LimTxtBx.IsEnabled = enabled; + if (KeyTxtBx != null) + KeyTxtBx.IsEnabled = enabled; + } + + private void Mode_s_Executed(object sender, ExecutedRoutedEventArgs e) + { + ToggleButton TgBttn = e.Source as ToggleButton; + if (TgBttn.IsChecked == true) + { + Mode_s_Toggled = false; + this.Session.Mode(this.Target.Name, "+s"); + } + else + { + Mode_s_Toggled = true; + this.Session.Mode(this.Target.Name, "-s"); + } + return; + } + + private void Mode_p_Executed(object sender, ExecutedRoutedEventArgs e) + { + ToggleButton TgBttn = e.Source as ToggleButton; + if (TgBttn.IsChecked == true) + { + Mode_p_Toggled = false; + this.Session.Mode(this.Target.Name, "+p"); + } + else + { + Mode_p_Toggled = true; + this.Session.Mode(this.Target.Name, "-p"); + } + return; + } + + private void Mode_m_Executed(object sender, ExecutedRoutedEventArgs e) + { + ToggleButton TgBttn = e.Source as ToggleButton; + if (TgBttn.IsChecked == true) + { + Mode_m_Toggled = false; + this.Session.Mode(this.Target.Name, "+m"); + } + else + { + Mode_m_Toggled = true; + this.Session.Mode(this.Target.Name, "-m"); + } + return; + } + + private void Mode_t_Executed(object sender, ExecutedRoutedEventArgs e) + { + ToggleButton TgBttn = e.Source as ToggleButton; + if (TgBttn.IsChecked == true) + { + Mode_t_Toggled = false; + this.Session.Mode(this.Target.Name, "+t"); + } + else + { + Mode_t_Toggled = true; + this.Session.Mode(this.Target.Name, "-t"); + } + return; + } + + private void Mode_i_Executed(object sender, ExecutedRoutedEventArgs e) + { + ToggleButton TgBttn = e.Source as ToggleButton; + if (TgBttn.IsChecked == true) + { + Mode_i_Toggled = false; + this.Session.Mode(this.Target.Name, "+i"); + } + else + { + Mode_i_Toggled = true; + this.Session.Mode(this.Target.Name, "-i"); + } + return; + } + + private void Mode_n_Executed(object sender, ExecutedRoutedEventArgs e) + { + ToggleButton TgBttn = e.Source as ToggleButton; + if (TgBttn.IsChecked == true) + { + Mode_n_Toggled = false; + this.Session.Mode(this.Target.Name, "+n"); + } + else + { + Mode_n_Toggled = true; + this.Session.Mode(this.Target.Name, "-n"); + } + return; + } + + private void Mode_r_Executed(object sender, ExecutedRoutedEventArgs e) + { + ToggleButton TgBttn = e.Source as ToggleButton; + if (TgBttn.IsChecked == true) + { + Mode_r_Toggled = false; + this.Session.Mode(this.Target.Name, "+r"); + } + else + { + Mode_r_Toggled = true; + this.Session.Mode(this.Target.Name, "-r"); + } + return; + } + + private void Mode_D_Executed(object sender, ExecutedRoutedEventArgs e) + { + ToggleButton TgBttn = e.Source as ToggleButton; + if (TgBttn.IsChecked == true) + { + Mode_D_Toggled = false; + this.Session.Mode(this.Target.Name, "+D"); + } + else + { + Mode_D_Toggled = true; + this.Session.Mode(this.Target.Name, "-D"); + } + return; + } + + private void Mode_d_Executed(object sender, ExecutedRoutedEventArgs e) + { + ToggleButton TgBttn = e.Source as ToggleButton; + TgBttn.IsChecked = Mode_d_Toggled; + } + + private void Mode_R_Executed(object sender, ExecutedRoutedEventArgs e) + { + ToggleButton TgBttn = e.Source as ToggleButton; + if (TgBttn.IsChecked == true) + { + Mode_R_Toggled = false; + this.Session.Mode(this.Target.Name, "+R"); + } + else + { + Mode_R_Toggled = true; + this.Session.Mode(this.Target.Name, "-R"); + } + TgBttn.IsChecked = Mode_R_Toggled; + } + + private void Mode_R_CanExecute(object sender, CanExecuteRoutedEventArgs e) + { + e.CanExecute = IsOp(); + } + + private void Mode_l_Executed(object sender, ExecutedRoutedEventArgs e) + { + ToggleButton TgBttn = e.Source as ToggleButton; + if (TgBttn.IsChecked == true) + { + // Never happen case, LimitStr property changing sends the new limit + } + else + { + LimitStrNr = null; + } + return; + } + + private void Mode_l_CanExecute(object sender, CanExecuteRoutedEventArgs e) + { + ToggleButton TgBttn = e.Source as ToggleButton; + if (String.IsNullOrEmpty(LimitStrNr)) + { + e.CanExecute = false; + return; + } + e.CanExecute = IsOp(); + } + + private void Mode_k_Executed(object sender, ExecutedRoutedEventArgs e) + { + ToggleButton TgBttn = e.Source as ToggleButton; + if (TgBttn.IsChecked == true) + { + // Never happen case, KeyStr property changing sends the new key + } + else + { + KeyStr = null; + } + return; + } + + private void Mode_k_CanExecute(object sender, CanExecuteRoutedEventArgs e) + { + ToggleButton TgBttn = e.Source as ToggleButton; + if (String.IsNullOrEmpty(KeyStr)) + { + e.CanExecute = false; + return; + } + e.CanExecute = IsOp(); + } + + private void UpdateTextBoxSourceProperty(TextBox tBox) + { + DependencyProperty prop = TextBox.TextProperty; + + BindingExpression binding = BindingOperations.GetBindingExpression(tBox, prop); + if (binding != null) { binding.UpdateSource(); } + } + + private void TxtBx_KeyUp(object sender, KeyEventArgs e) + { + if (e.Key == Key.Enter) + UpdateTextBoxSourceProperty((TextBox)sender); + } + + private void DataGrid_BeginningEdit(object sender, DataGridBeginningEditEventArgs e) + { + if (!IsOp()) + e.Cancel = true; + } + + private void DataGrid_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e) + { + DataGrid BanGrid = (DataGrid)sender; + TextBox t = e.EditingElement as TextBox; + DataGridColumn dgc = e.Column; + //if (dgc.Header.ToString() != "Mask") + // return; + if (IsBanChanged) + { + BanItem newBan = e.Row.Item as BanItem; + if (t.Text != newBan.Mask) + { + if (String.IsNullOrEmpty(newBan.Mask)) + BanList.Remove(newBan); + else + { + BanList.Remove(newBan); + this.Session.Mode(this.Target.Name, "-b " + newBan.Mask); + } + this.Session.Mode(this.Target.Name, "+b " + t.Text); + } + } + if (IsExceptChanged) + { + ExceptItem newExcept = e.Row.Item as ExceptItem; + if (t.Text != newExcept.Mask) + { + if (String.IsNullOrEmpty(newExcept.Mask)) + ExceptsList.Remove(newExcept); + else + { + ExceptsList.Remove(newExcept); + this.Session.Mode(this.Target.Name, "-e " + newExcept.Mask); + } + this.Session.Mode(this.Target.Name, "+e " + t.Text); + } + } + } + + private void ExecuteJoin(object sender, ExecutedRoutedEventArgs e) + { + string channel = e.Parameter as string; + if (!string.IsNullOrEmpty(channel)) + { + this.Session.Join(channel); + InvitesList.Remove(InvitesList.Where(i => i.InvitedTo == channel).FirstOrDefault()); + } + } + + private void DataGrid_LoadingRow(object sender, DataGridRowEventArgs e) + { + if (IsNewRowAdding) + { + e.Row.Focus(); + DataGrid BanGrid = (DataGrid)sender; + BanGrid.SelectedIndex = BanGrid.Items.Count - 1; + BanGrid.ScrollIntoView(BanGrid.SelectedItem); + IsNewRowAdding = false; + } + } + + private void CanModifyBans(object sender, CanExecuteRoutedEventArgs e) + { + e.CanExecute = IsOp(); + } + + public void ToggleModeButtons(ICollection Modes) + { + foreach (IrcChannelMode m in Modes) + { + if (m.Mode == 's') Mode_s_Toggled = m.Set; + if (m.Mode == 'p') Mode_p_Toggled = m.Set; + if (m.Mode == 'm') Mode_m_Toggled = m.Set; + if (m.Mode == 't') Mode_t_Toggled = m.Set; + if (m.Mode == 'i') Mode_i_Toggled = m.Set; + if (m.Mode == 'n') Mode_n_Toggled = m.Set; + if (m.Mode == 'r') Mode_r_Toggled = m.Set; + if (m.Mode == 'D') Mode_D_Toggled = m.Set; + if (m.Mode == 'd') Mode_d_Toggled = m.Set; + if (m.Mode == 'R') Mode_R_Toggled = m.Set; + if (m.Mode == 'l') + { + Mode_l_Toggled = m.Set; + if (m.Set == true) + LimitStrNr = m.Parameter; + if (m.Set == false) + LimitStrNr = null; + } + if (m.Mode == 'k') + { + if (!bSkipKeySet) + { + Mode_k_Toggled = m.Set; + if (m.Set == true) + KeyStr = m.Parameter; + if (m.Set == false) + KeyStr = null; + } + else + bSkipKeySet = false; + } + } + } + + private void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + DataGrid BanGrid = (DataGrid)sender; + if (BanGrid != null) + { + // It works + } + } + + private void EnterEditMaskCell(DataGrid dg) + { + if (dg != null) + { + foreach (DataGridCellInfo selCell in dg.SelectedCells) + { + if (selCell.Column.Header.ToString() == "Mask" && IsOp()) + { + dg.CurrentCell = selCell; + dg.BeginEdit(); + break; + } + } + } + } + } +} diff --git a/Floe.UI/InfoWindows/UserInfoWindow.xaml b/Floe.UI/InfoWindows/UserInfoWindow.xaml new file mode 100644 index 0000000..f332b18 --- /dev/null +++ b/Floe.UI/InfoWindows/UserInfoWindow.xaml @@ -0,0 +1,12 @@ + + + + + diff --git a/Floe.UI/InfoWindows/UserInfoWindow.xaml.cs b/Floe.UI/InfoWindows/UserInfoWindow.xaml.cs new file mode 100644 index 0000000..f1adfaa --- /dev/null +++ b/Floe.UI/InfoWindows/UserInfoWindow.xaml.cs @@ -0,0 +1,177 @@ +using Floe.Net; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows; +using System.ComponentModel; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; + +namespace Floe.UI.InfoWindows +{ + /// + /// Interaction logic for UserInfoWindow.xaml + /// + public partial class UserInfoWindow : Window + { + private readonly IrcSession Session; + private IrcCodeHandler whoisUserHandler; + private IrcCodeHandler whoisChannelsHandler; + private IrcCodeHandler whoisServerHandler; + private IrcCodeHandler whoisIdleHandler; + private IrcCodeHandler whoisInvitingHandler; + private IrcCodeHandler whoisEndHandler; + + public UserInfoWindow(IrcSession session, IrcTarget target) + { + InitializeComponent(); + this.Session = session; + this.Title = "User information about " + target.Name; + this.Session.InfoReceived += new EventHandler(Session_InfoReceived); + CaptureWhoisUser(); + CaptureWhoisChannels(); + CaptureWhoisServer(); + CaptureWhoisIdle(); + CaptureWhoisInvitings(); + CaptureWhoisEnd(); + this.Session.WhoIs(target.Name); + } + + private void CaptureWhoisUser() + { + whoisUserHandler = new IrcCodeHandler((e) => + { + e.Handled = true; + return true; + }, IrcCode.RPL_WHOISUSER); + + this.Session.AddHandler(whoisUserHandler); + } + + private void CaptureWhoisChannels() + { + whoisChannelsHandler = new IrcCodeHandler((e) => + { + e.Handled = true; + return true; + }, IrcCode.RPL_WHOISCHANNELS); + + this.Session.AddHandler(whoisChannelsHandler); + } + + private void CaptureWhoisServer() + { + whoisServerHandler = new IrcCodeHandler((e) => + { + e.Handled = true; + return true; + }, IrcCode.RPL_WHOISSERVER); + + this.Session.AddHandler(whoisServerHandler); + } + + private void CaptureWhoisIdle() + { + whoisIdleHandler = new IrcCodeHandler((e) => + { + e.Handled = true; + return true; + }, IrcCode.RPL_WHOISIDLE); + this.Session.AddHandler(whoisIdleHandler); + } + + private void CaptureWhoisInvitings() + { + whoisInvitingHandler = new IrcCodeHandler((e) => + { + e.Handled = true; + return true; + }, IrcCode.RPL_INVITING); + + this.Session.AddHandler(whoisInvitingHandler); + } + + private void CaptureWhoisEnd() + { + whoisEndHandler = new IrcCodeHandler((e) => + { + this.Session.RemoveHandler(whoisUserHandler); + this.Session.RemoveHandler(whoisChannelsHandler); + this.Session.RemoveHandler(whoisServerHandler); + this.Session.RemoveHandler(whoisIdleHandler); + this.Session.RemoveHandler(whoisInvitingHandler); + e.Handled = true; + return true; + }, IrcCode.RPL_ENDOFWHOIS); + + this.Session.AddHandler(whoisEndHandler); + } + + private void Session_InfoReceived(object sender, IrcInfoEventArgs e) + { + switch (e.Code) + { + case IrcCode.RPL_WHOISUSER: + case IrcCode.RPL_WHOWASUSER: + if (e.Message.Parameters.Count == 6) + { + //this.Write("ServerInfo", e.Message.Time, + // string.Format("{1} " + (e.Code == IrcCode.RPL_WHOWASUSER ? "was" : "is") + " {2}@{3} {4} {5}", + // (object[])e.Message.Parameters)); + return; + } + break; + case IrcCode.RPL_WHOISCHANNELS: + if (e.Message.Parameters.Count == 3) + { + //this.Write("ServerInfo", e.Message.Time, string.Format("{1} is on {2}", + // (object[])e.Message.Parameters)); + return; + } + break; + case IrcCode.RPL_WHOISSERVER: + if (e.Message.Parameters.Count == 4) + { + //this.Write("ServerInfo", e.Message.Time, string.Format("{1} using {2} {3}", + // (object[])e.Message.Parameters)); + return; + } + break; + case IrcCode.RPL_WHOISIDLE: + if (e.Message.Parameters.Count == 5) + { + //this.Write("ServerInfo", e.Message.Time, string.Format("{0} has been idle {1}, signed on {2}", + // e.Message.Parameters[1], this.FormatTimeSpan(e.Message.Parameters[2]), + // this.FormatTime(e.Message.Parameters[3]))); + return; + } + break; + case IrcCode.RPL_INVITING: + if (e.Message.Parameters.Count == 3) + { + //this.Write("ServerInfo", e.Message.Time, string.Format("Invited {0} to channel {1}", + // e.Message.Parameters[1], e.Message.Parameters[2])); + return; + } + break; + default: + { + e.Handled = true; + } + break; + } + } + + protected override void OnClosing(CancelEventArgs e) + { + this.Session.InfoReceived -= new EventHandler(Session_InfoReceived); + base.OnClosing(e); + } + } +} From 7f8b95dbe2d26f42dc614fd58fc8789b7b4b3e03 Mon Sep 17 00:00:00 2001 From: Seven-7 Date: Mon, 26 Feb 2018 22:32:51 +0000 Subject: [PATCH 36/60] Still can happen to get invite list from server (znc) --- Floe.UI/InfoWindows/ChannelInfoWindow.xaml.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Floe.UI/InfoWindows/ChannelInfoWindow.xaml.cs b/Floe.UI/InfoWindows/ChannelInfoWindow.xaml.cs index b4ca590..539876b 100644 --- a/Floe.UI/InfoWindows/ChannelInfoWindow.xaml.cs +++ b/Floe.UI/InfoWindows/ChannelInfoWindow.xaml.cs @@ -325,7 +325,8 @@ public ChannelInfoWindow(ChatControl chatControl) CaptureModes(); CaptureBans(); CaptureExceptions(); - CaptureInvites(); + if (InvitesList.Count == 0) + CaptureInvites(); this.DataContext = this; } @@ -437,10 +438,8 @@ private void CaptureInvites() { invitesHandler = new IrcCodeHandler((e) => { - // ** Disabled, since ircds sends only the invited channel names without the other paramters like who sent the invite, - // so we use ChatControl's always complete InvitesList ** // - //InvitesList.Add(new InviteItem(e.Text)); - //this.Session.AddHandler(invitesHandler); + InvitesList.Add(new InviteItem(e.Text)); + this.Session.AddHandler(invitesHandler); e.Handled = true; return true; }, IrcCode.RPL_INVITELIST); From ac128a082775d54dc45d4b23e11254abcc052c90 Mon Sep 17 00:00:00 2001 From: Seven-7 Date: Thu, 1 Mar 2018 18:34:19 +0000 Subject: [PATCH 37/60] So far just a basic-looking UserInfoWindow --- Floe.Net/Irc/IrcCode.cs | 2 + Floe.UI/ChatControl/ChatControl_Events.cs | 10 +- Floe.UI/InfoWindows/UserInfoWindow.xaml | 33 ++++- Floe.UI/InfoWindows/UserInfoWindow.xaml.cs | 144 ++++++++++++++++++--- 4 files changed, 162 insertions(+), 27 deletions(-) diff --git a/Floe.Net/Irc/IrcCode.cs b/Floe.Net/Irc/IrcCode.cs index 4fdf5c9..b8c9be4 100644 --- a/Floe.Net/Irc/IrcCode.cs +++ b/Floe.Net/Irc/IrcCode.cs @@ -32,9 +32,11 @@ public enum IrcCode RPL_CHANNELMODEIS = 324, RPL_UNIQOPIS = 325, RPL_CHANNELCREATEDON = 329, + RPL_WHOISACCOUNT = 330, RPL_NOTOPIC = 331, RPL_TOPIC = 332, RPL_TOPICSETBY = 333, + RPL_WHOISUSERHOST = 338, RPL_INVITING = 341, RPL_SUMMONING = 342, RPL_INVITELIST = 346, diff --git a/Floe.UI/ChatControl/ChatControl_Events.cs b/Floe.UI/ChatControl/ChatControl_Events.cs index 78738ad..562d617 100644 --- a/Floe.UI/ChatControl/ChatControl_Events.cs +++ b/Floe.UI/ChatControl/ChatControl_Events.cs @@ -253,7 +253,7 @@ private void Session_InfoReceived(object sender, IrcInfoEventArgs e) this.Target.Equals(new IrcTarget(e.Message.Parameters[1]))) { this.Write("Topic", e.Message.Time, string.Format("Topic set by {0} on {1}", e.Message.Parameters[2], - this.FormatTime(e.Message.Parameters[3]))); + FormatTime(e.Message.Parameters[3]))); } return; case IrcCode.RPL_CHANNELCREATEDON: @@ -293,8 +293,8 @@ private void Session_InfoReceived(object sender, IrcInfoEventArgs e) if (e.Message.Parameters.Count == 5 && this.IsDefault) { this.Write("ServerInfo", e.Message.Time, string.Format("{0} has been idle {1}, signed on {2}", - e.Message.Parameters[1], this.FormatTimeSpan(e.Message.Parameters[2]), - this.FormatTime(e.Message.Parameters[3]))); + e.Message.Parameters[1], FormatTimeSpan(e.Message.Parameters[2]), + FormatTime(e.Message.Parameters[3]))); return; } break; @@ -1030,7 +1030,7 @@ private void PrepareContextMenus() } } - public string FormatTime(string text) + public static string FormatTime(string text) { int seconds = 0; if (!int.TryParse(text, out seconds)) @@ -1041,7 +1041,7 @@ public string FormatTime(string text) return new DateTime(1970, 1, 1).Add(ts).ToLocalTime().ToString(); } - private string FormatTimeSpan(string text) + public static string FormatTimeSpan(string text) { int seconds = 0; if (!int.TryParse(text, out seconds)) diff --git a/Floe.UI/InfoWindows/UserInfoWindow.xaml b/Floe.UI/InfoWindows/UserInfoWindow.xaml index f332b18..00a4c40 100644 --- a/Floe.UI/InfoWindows/UserInfoWindow.xaml +++ b/Floe.UI/InfoWindows/UserInfoWindow.xaml @@ -7,6 +7,37 @@ mc:Ignorable="d" Title="UserInfoWindow" Height="400" Width="400"> - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Floe.UI/InfoWindows/UserInfoWindow.xaml.cs b/Floe.UI/InfoWindows/UserInfoWindow.xaml.cs index f1adfaa..f7e8f92 100644 --- a/Floe.UI/InfoWindows/UserInfoWindow.xaml.cs +++ b/Floe.UI/InfoWindows/UserInfoWindow.xaml.cs @@ -1,17 +1,7 @@ -using Floe.Net; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System; using System.Windows; using System.ComponentModel; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Shapes; +using Floe.Net; namespace Floe.UI.InfoWindows { @@ -24,6 +14,10 @@ public partial class UserInfoWindow : Window private IrcCodeHandler whoisUserHandler; private IrcCodeHandler whoisChannelsHandler; private IrcCodeHandler whoisServerHandler; + private IrcCodeHandler whoisAwayHandler; + private IrcCodeHandler whoisOperatorHandler; + private IrcCodeHandler whoisAccountHandler; + private IrcCodeHandler whoisUserHostHandler; private IrcCodeHandler whoisIdleHandler; private IrcCodeHandler whoisInvitingHandler; private IrcCodeHandler whoisEndHandler; @@ -37,16 +31,22 @@ public UserInfoWindow(IrcSession session, IrcTarget target) CaptureWhoisUser(); CaptureWhoisChannels(); CaptureWhoisServer(); + CaptureWhoisAway(); + CaptureWhoisOperator(); + CaptureWhoisAccount(); + CaptureWhoisUserHost(); CaptureWhoisIdle(); CaptureWhoisInvitings(); CaptureWhoisEnd(); - this.Session.WhoIs(target.Name); + this.Session.WhoIs(target.Name, target.Name); } private void CaptureWhoisUser() { whoisUserHandler = new IrcCodeHandler((e) => { + TxtBlockRealName.Text = "Real Name:"; + TxtBlockRealNameData.Text = e.Message.Parameters[5]; e.Handled = true; return true; }, IrcCode.RPL_WHOISUSER); @@ -58,6 +58,10 @@ private void CaptureWhoisChannels() { whoisChannelsHandler = new IrcCodeHandler((e) => { + TxtBlockChannels.Visibility = Visibility.Visible; + TxtBlockChannels.Text = "Is on:"; + TxtBlockChannelsData.Visibility = Visibility.Visible; + TxtBlockChannelsData.Text = e.Message.Parameters[2]; e.Handled = true; return true; }, IrcCode.RPL_WHOISCHANNELS); @@ -69,6 +73,8 @@ private void CaptureWhoisServer() { whoisServerHandler = new IrcCodeHandler((e) => { + TxtBlockServer.Text = "Is using:"; + TxtBlockServerData.Text = e.Message.Parameters[2] + " (" + e.Message.Parameters[3] + ")"; e.Handled = true; return true; }, IrcCode.RPL_WHOISSERVER); @@ -76,10 +82,74 @@ private void CaptureWhoisServer() this.Session.AddHandler(whoisServerHandler); } + private void CaptureWhoisAway() + { + whoisAwayHandler = new IrcCodeHandler((e) => + { + TxtBlockAway.Visibility = Visibility.Visible; + TxtBlockAway.Text = "Is away:"; + TxtBlockAwayData.Visibility = Visibility.Visible; + TxtBlockAwayData.Text = e.Message.Parameters[2]; + e.Handled = true; + return true; + }, IrcCode.RPL_AWAY); + + this.Session.AddHandler(whoisAwayHandler); + } + + private void CaptureWhoisOperator() + { + whoisOperatorHandler = new IrcCodeHandler((e) => + { + TxtBlockOper.Visibility = Visibility.Visible; + TxtBlockOper.Text = "Status:"; + TxtBlockOperData.Visibility = Visibility.Visible; + TxtBlockOperData.Text = e.Message.Parameters[2]; + e.Handled = true; + return true; + }, IrcCode.RPL_WHOISOPERATOR); + + this.Session.AddHandler(whoisOperatorHandler); + } + + private void CaptureWhoisAccount() + { + whoisAccountHandler = new IrcCodeHandler((e) => + { + TxtBlockAccount.Visibility = Visibility.Visible; + TxtBlockAccount.Text = "Is logged in as:"; + TxtBlockAccountData.Visibility = Visibility.Visible; + TxtBlockAccountData.Text = e.Message.Parameters[2]; + e.Handled = true; + return true; + }, IrcCode.RPL_WHOISACCOUNT); + + this.Session.AddHandler(whoisAccountHandler); + } + + private void CaptureWhoisUserHost() + { + whoisUserHostHandler = new IrcCodeHandler((e) => + { + TxtBlockUserHost.Visibility = Visibility.Visible; + TxtBlockUserHost.Text = "Actual userhost:"; + TxtBlockUserHostData.Visibility = Visibility.Visible; + TxtBlockUserHostData.Text = e.Message.Parameters[2]; + e.Handled = true; + return true; + }, IrcCode.RPL_WHOISUSERHOST); + + this.Session.AddHandler(whoisUserHostHandler); + } + private void CaptureWhoisIdle() { whoisIdleHandler = new IrcCodeHandler((e) => { + TxtBlockIdle.Visibility = Visibility.Visible; + TxtBlockIdle.Text = "Is idle:"; + TxtBlockIdleData.Visibility = Visibility.Visible; + TxtBlockIdleData.Text = ChatControl.FormatTimeSpan(e.Message.Parameters[2]) + ", Signed on: " + ChatControl.FormatTime(e.Message.Parameters[3]); e.Handled = true; return true; }, IrcCode.RPL_WHOISIDLE); @@ -90,6 +160,10 @@ private void CaptureWhoisInvitings() { whoisInvitingHandler = new IrcCodeHandler((e) => { + TxtBlockInvite.Visibility = Visibility.Visible; + TxtBlockInvite.Text = "Is invited to:"; + TxtBlockInviteData.Visibility = Visibility.Visible; + TxtBlockInviteData.Text = e.Message.Parameters[2]; e.Handled = true; return true; }, IrcCode.RPL_INVITING); @@ -104,6 +178,10 @@ private void CaptureWhoisEnd() this.Session.RemoveHandler(whoisUserHandler); this.Session.RemoveHandler(whoisChannelsHandler); this.Session.RemoveHandler(whoisServerHandler); + this.Session.RemoveHandler(whoisAwayHandler); + this.Session.RemoveHandler(whoisOperatorHandler); + this.Session.RemoveHandler(whoisAccountHandler); + this.Session.RemoveHandler(whoisUserHostHandler); this.Session.RemoveHandler(whoisIdleHandler); this.Session.RemoveHandler(whoisInvitingHandler); e.Handled = true; @@ -130,9 +208,7 @@ private void Session_InfoReceived(object sender, IrcInfoEventArgs e) case IrcCode.RPL_WHOISCHANNELS: if (e.Message.Parameters.Count == 3) { - //this.Write("ServerInfo", e.Message.Time, string.Format("{1} is on {2}", - // (object[])e.Message.Parameters)); - return; + TxtBlockChannelsData.Text = e.Message.Parameters[2]; } break; case IrcCode.RPL_WHOISSERVER: @@ -143,13 +219,30 @@ private void Session_InfoReceived(object sender, IrcInfoEventArgs e) return; } break; - case IrcCode.RPL_WHOISIDLE: + case IrcCode.RPL_AWAY: + if (e.Message.Parameters.Count == 4) + { + TxtBlockAwayData.Text = e.Message.Parameters[2]; + } + break; + case IrcCode.RPL_UNAWAY: + { + TxtBlockAway.Visibility = Visibility.Collapsed; + TxtBlockAwayData.Visibility = Visibility.Collapsed; + TxtBlockAwayData.Text = null; + } + break; + case IrcCode.RPL_WHOISOPERATOR: if (e.Message.Parameters.Count == 5) { - //this.Write("ServerInfo", e.Message.Time, string.Format("{0} has been idle {1}, signed on {2}", - // e.Message.Parameters[1], this.FormatTimeSpan(e.Message.Parameters[2]), - // this.FormatTime(e.Message.Parameters[3]))); - return; + TxtBlockOper.Visibility = Visibility.Visible; + TxtBlockOper.Text = "Status:"; + TxtBlockOperData.Visibility = Visibility.Visible; + TxtBlockOperData.Text = e.Message.Parameters[2]; + } + break; + case IrcCode.RPL_WHOISACCOUNT: + { } break; case IrcCode.RPL_INVITING: @@ -160,6 +253,15 @@ private void Session_InfoReceived(object sender, IrcInfoEventArgs e) return; } break; + case IrcCode.RPL_WHOISIDLE: + if (e.Message.Parameters.Count == 5) + { + TxtBlockIdle.Visibility = Visibility.Visible; + TxtBlockIdle.Text = "Is idle:"; + TxtBlockIdleData.Visibility = Visibility.Visible; + TxtBlockIdleData.Text = ChatControl.FormatTimeSpan(e.Message.Parameters[2]) + ", Signed on: " + ChatControl.FormatTime(e.Message.Parameters[3]); + } + break; default: { e.Handled = true; From 332f97a229053af83ec910f607cad211600ddd75 Mon Sep 17 00:00:00 2001 From: Seven-7 Date: Thu, 22 Mar 2018 16:12:25 +0000 Subject: [PATCH 38/60] Milestone feature: Tab Strip Position now can be Right and Left --- Floe.Configuration/Enums.cs | 4 +- Floe.Configuration/WindowsElement.cs | 9 +- Floe.Net/Properties/AssemblyInfo.cs | 4 +- Floe.UI/ChatWindow/ChatWindow.xaml | 47 +++--- Floe.UI/ChatWindow/ChatWindow.xaml.cs | 10 ++ .../ChatWindow_TabsOrientationTemplating.cs | 151 ++++++++++++++++++ Floe.UI/Floe.UI.csproj | 1 + Floe.UI/Properties/AssemblyInfo.cs | 6 +- 8 files changed, 205 insertions(+), 27 deletions(-) create mode 100644 Floe.UI/ChatWindow/ChatWindow_TabsOrientationTemplating.cs diff --git a/Floe.Configuration/Enums.cs b/Floe.Configuration/Enums.cs index 238ff61..62cb18e 100644 --- a/Floe.Configuration/Enums.cs +++ b/Floe.Configuration/Enums.cs @@ -5,6 +5,8 @@ namespace Floe.Configuration public enum TabStripPosition { Top, - Bottom + Bottom, + Left, + Right } } diff --git a/Floe.Configuration/WindowsElement.cs b/Floe.Configuration/WindowsElement.cs index e12cbb7..eeb211a 100644 --- a/Floe.Configuration/WindowsElement.cs +++ b/Floe.Configuration/WindowsElement.cs @@ -6,6 +6,8 @@ namespace Floe.Configuration { public class WindowsElement : ConfigurationElement, INotifyPropertyChanged { + public static EventHandler OrientationChanged; + [ConfigurationProperty("placement")] public string Placement { @@ -55,11 +57,14 @@ public bool MinimizeToSysTray set { this["minimizeToSysTray"] = value; this.OnPropertyChanged("MinimizeToSysTray"); } } - [ConfigurationProperty("tabStripPosition", DefaultValue=TabStripPosition.Top)] + [ConfigurationProperty("tabStripPosition", DefaultValue=TabStripPosition.Right)] public TabStripPosition TabStripPosition { get { return (TabStripPosition)this["tabStripPosition"]; } - set { this["tabStripPosition"] = value; this.OnPropertyChanged("TabStripPosition"); } + set { this["tabStripPosition"] = value; this.OnPropertyChanged("TabStripPosition"); + if (OrientationChanged != null) + OrientationChanged(this, new EventArgs()); + } } [ConfigurationProperty("minTabWidth", DefaultValue = 75.0)] diff --git a/Floe.Net/Properties/AssemblyInfo.cs b/Floe.Net/Properties/AssemblyInfo.cs index 13ea761..5e406d9 100644 --- a/Floe.Net/Properties/AssemblyInfo.cs +++ b/Floe.Net/Properties/AssemblyInfo.cs @@ -15,6 +15,6 @@ [assembly: Guid("0d14d2ad-80d2-49f5-8868-22a731e328a1")] -[assembly: AssemblyVersion("1.6.1.0")] -[assembly: AssemblyFileVersion("1.6.1.0")] +[assembly: AssemblyVersion("1.8.0.0")] +[assembly: AssemblyFileVersion("1.8.0.0")] [assembly: CLSCompliant(true)] \ No newline at end of file diff --git a/Floe.UI/ChatWindow/ChatWindow.xaml b/Floe.UI/ChatWindow/ChatWindow.xaml index 78e5a6c..64f6deb 100644 --- a/Floe.UI/ChatWindow/ChatWindow.xaml +++ b/Floe.UI/ChatWindow/ChatWindow.xaml @@ -51,7 +51,7 @@ - + @@ -167,16 +167,23 @@ - - - - - - - - + + + + + + + + - + + +                     @@ -269,11 +276,11 @@ - + + HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="{Binding Path=TabsOrientationTemplate.VerticalScrollBarVisibility}"> @@ -292,8 +299,8 @@ - + + @@ -318,7 +325,7 @@ - + @@ -336,10 +343,12 @@ + + @@ -365,8 +374,8 @@ - - + + @@ -378,11 +387,11 @@ - -