// (c) 2010-2011 anis774 (@anis774) <http://d.hatena.ne.jp/anis774/>
// (c) 2010-2011 fantasticswallow (@f_swallow) <http://twitter.com/f_swallow>
// (c) 2011 Egtra (@egtra) <http://dev.activebasic.com/egtra/>
+// (c) 2012 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
// All rights reserved.
//
// This file is part of OpenTween.
namespace OpenTween
{
- public sealed class PostClass : ICloneable
+ public class PostClass : ICloneable
{
public class StatusGeo
{
public double Lng { get; set; }
public double Lat { get; set; }
+
+ public override bool Equals(object obj)
+ {
+ var geo = obj as StatusGeo;
+ return geo != null && geo.Lng == this.Lng && geo.Lat == this.Lat;
+ }
+
+ public override int GetHashCode()
+ {
+ return this.Lng.GetHashCode() ^ this.Lat.GetHashCode();
+ }
}
- private string _Nick;
- private string _textFromApi;
- private string _ImageUrl;
- private string _screenName;
- private DateTime _createdAt;
- private long _statusId;
+ public string Nickname { get; set; }
+ public string TextFromApi { get; set; }
+ public string ImageUrl { get; set; }
+ public string ScreenName { get; set; }
+ public DateTime CreatedAt { get; set; }
+ public long StatusId { get; set; }
private bool _IsFav;
- private string _text;
- private bool _IsRead;
- private bool _IsReply;
- private bool _IsExcludeReply;
+ public string Text { get; set; }
+ public bool IsRead { get; set; }
+ public bool IsReply { get; set; }
+ public bool IsExcludeReply { get; set; }
private bool _IsProtect;
- private bool _IsOWL;
+ public bool IsOwl { get; set; }
private bool _IsMark;
- private string _InReplyToUser;
- private long _InReplyToStatusId;
- private string _Source;
- private string _SourceHtml;
- private List<string> _ReplyToList = new List<string>();
- private bool _IsMe;
- private bool _IsDm;
- private States _states = States.None;
- private long _UserId;
- private bool _FilterHit;
- private string _RetweetedBy = "";
- private long _RetweetedId = 0;
- private string _SearchTabName = "";
+ public string InReplyToUser { get; set; }
+ private long? _InReplyToStatusId;
+ public string Source { get; set; }
+ public string SourceHtml { get; set; }
+ public List<string> ReplyToList { get; set; }
+ public bool IsMe { get; set; }
+ public bool IsDm { get; set; }
+ public long UserId { get; set; }
+ public bool FilterHit { get; set; }
+ public string RetweetedBy { get; set; }
+ public long? RetweetedId { get; set; }
private bool _IsDeleted = false;
- private long _InReplyToUserId = 0;
private StatusGeo _postGeo = new StatusGeo();
public int RetweetedCount { get; set; }
- public long RetweetedByUserId { get; set; }
+ public long? RetweetedByUserId { get; set; }
+ public long? InReplyToUserId { get; set; }
public Dictionary<string, string> Media { get; set; }
+ public string RelTabName { get; set; }
+ public int FavoritedCount { get; set; }
+
+ private States _states = States.None;
+
[Flags]
private enum States
{
bool IsOwl,
bool IsMark,
string InReplyToUser,
- long InReplyToStatusId,
+ long? InReplyToStatusId,
string Source,
string SourceHtml,
List<string> ReplyToList,
long userId,
bool FilterHit,
string RetweetedBy,
- long RetweetedId,
+ long? RetweetedId,
StatusGeo Geo)
: this()
{
- _Nick = Nickname;
- _textFromApi = textFromApi;
- _ImageUrl = ImageUrl;
- _screenName = screenName;
- _createdAt = createdAt;
- _statusId = statusId;
+ this.Nickname = Nickname;
+ this.TextFromApi = textFromApi;
+ this.ImageUrl = ImageUrl;
+ this.ScreenName = screenName;
+ this.CreatedAt = createdAt;
+ this.StatusId = statusId;
_IsFav = IsFav;
- _text = text;
- _IsRead = IsRead;
- _IsReply = IsReply;
- _IsExcludeReply = IsExcludeReply;
+ this.Text = text;
+ this.IsRead = IsRead;
+ this.IsReply = IsReply;
+ this.IsExcludeReply = IsExcludeReply;
_IsProtect = IsProtect;
- _IsOWL = IsOwl;
+ this.IsOwl = IsOwl;
_IsMark = IsMark;
- _InReplyToUser = InReplyToUser;
+ this.InReplyToUser = InReplyToUser;
_InReplyToStatusId = InReplyToStatusId;
- _Source = Source;
- _SourceHtml = SourceHtml;
- _ReplyToList = ReplyToList;
- _IsMe = IsMe;
- _IsDm = IsDm;
- _UserId = userId;
- _FilterHit = FilterHit;
- _RetweetedBy = RetweetedBy;
- _RetweetedId = RetweetedId;
+ this.Source = Source;
+ this.SourceHtml = SourceHtml;
+ this.ReplyToList = ReplyToList;
+ this.IsMe = IsMe;
+ this.IsDm = IsDm;
+ this.UserId = userId;
+ this.FilterHit = FilterHit;
+ this.RetweetedBy = RetweetedBy;
+ this.RetweetedId = RetweetedId;
_postGeo = Geo;
}
public PostClass()
{
- RetweetedCount = 0;
- RetweetedByUserId = 0;
+ RetweetedBy = "";
+ RelTabName = "";
Media = new Dictionary<string, string>();
+ ReplyToList = new List<string>();
}
- public string Nickname
- {
- get
- {
- return _Nick;
- }
- set
- {
- _Nick = value;
- }
- }
- public string TextFromApi
- {
- get
- {
- return _textFromApi;
- }
- set
- {
- _textFromApi = value;
- }
- }
- public string ImageUrl
- {
- get
- {
- return _ImageUrl;
- }
- set
- {
- _ImageUrl = value;
- }
- }
- public string ScreenName
- {
- get
- {
- return _screenName;
- }
- set
- {
- _screenName = value;
- }
- }
- public DateTime CreatedAt
- {
- get
- {
- return _createdAt;
- }
- set
- {
- _createdAt = value;
- }
- }
- public long StatusId
+ public string TextSingleLine
{
get
{
- return _statusId;
- }
- set
- {
- _statusId = value;
+ return this.TextFromApi == null ? null : this.TextFromApi.Replace("\n", " ");
}
}
+
public bool IsFav
{
get
{
- if (this.RetweetedId > 0 && TabInformations.GetInstance().RetweetSource(this.RetweetedId) != null)
- {
- return TabInformations.GetInstance().RetweetSource(this.RetweetedId).IsFav;
- }
- else
+ if (this.RetweetedId != null)
{
- return _IsFav;
+ var post = this.GetRetweetSource(this.RetweetedId.Value);
+ if (post != null)
+ {
+ return post.IsFav;
+ }
}
+
+ return _IsFav;
}
set
{
_IsFav = value;
- if (this.RetweetedId > 0 && TabInformations.GetInstance().RetweetSource(this.RetweetedId) != null)
+ if (this.RetweetedId != null)
{
- TabInformations.GetInstance().RetweetSource(this.RetweetedId).IsFav = value;
+ var post = this.GetRetweetSource(this.RetweetedId.Value);
+ if (post != null)
+ {
+ post.IsFav = value;
+ }
}
}
}
- public string Text
- {
- get
- {
- return _text;
- }
- set
- {
- _text = value;
- }
- }
- public bool IsRead
- {
- get
- {
- return _IsRead;
- }
- set
- {
- _IsRead = value;
- }
- }
- public bool IsReply
- {
- get
- {
- return _IsReply;
- }
- set
- {
- _IsReply = value;
- }
- }
- public bool IsExcludeReply
- {
- get
- {
- return _IsExcludeReply;
- }
- set
- {
- _IsExcludeReply = value;
- }
- }
+
public bool IsProtect
{
get
_IsProtect = value;
}
}
- public bool IsOwl
- {
- get
- {
- return _IsOWL;
- }
- set
- {
- _IsOWL = value;
- }
- }
public bool IsMark
{
get
_IsMark = value;
}
}
- public string InReplyToUser
- {
- get
- {
- return _InReplyToUser;
- }
- set
- {
- _InReplyToUser = value;
- }
- }
- public long InReplyToStatusId
+ public long? InReplyToStatusId
{
get
{
}
set
{
- if (value > 0)
+ if (value != null)
{
_states = _states | States.Reply;
}
}
}
- public long InReplyToUserId
- {
- get
- {
- return _InReplyToUserId;
- }
- set
- {
- _InReplyToUserId = value;
- }
- }
- public string Source
- {
- get
- {
- return _Source;
- }
- set
- {
- _Source = value;
- }
- }
- public string SourceHtml
- {
- get
- {
- return _SourceHtml;
- }
- set
- {
- _SourceHtml = value;
- }
- }
- public List<string> ReplyToList
- {
- get
- {
- return _ReplyToList;
- }
- set
- {
- _ReplyToList = value;
- }
- }
- public bool IsMe
- {
- get
- {
- return _IsMe;
- }
- set
- {
- _IsMe = value;
- }
- }
- public bool IsDm
- {
- get
- {
- return _IsDm;
- }
- set
- {
- _IsDm = value;
- }
- }
- //public readonly int StatusIndex
- //{
- // get
- // {
- // return _statuses;
- // }
- //}
- public long UserId
- {
- get
- {
- return _UserId;
- }
- set
- {
- _UserId = value;
- }
- }
- public bool FilterHit
- {
- get
- {
- return _FilterHit;
- }
- set
- {
- _FilterHit = value;
- }
- }
- public string RetweetedBy
- {
- get
- {
- return _RetweetedBy;
- }
- set
- {
- _RetweetedBy = value;
- }
- }
- public long RetweetedId
- {
- get
- {
- return _RetweetedId;
- }
- set
- {
- _RetweetedId = value;
- }
- }
- public string RelTabName
- {
- get
- {
- return _SearchTabName;
- }
- set
- {
- _SearchTabName = value;
- }
- }
public bool IsDeleted
{
get
{
if (value)
{
- this.InReplyToStatusId = 0;
+ this.InReplyToStatusId = null;
this.InReplyToUser = "";
- this.InReplyToUserId = 0;
+ this.InReplyToUserId = null;
this.IsReply = false;
this.ReplyToList = new List<string>();
this._states = States.None;
}
}
- public int FavoritedCount { get; set; }
-
public StatusGeo PostGeo
{
get
}
}
+ protected virtual PostClass GetRetweetSource(long statusId)
+ {
+ return TabInformations.GetInstance().RetweetSource(statusId);
+ }
+
+ [Obsolete("Use PostClass.Clone() instead.")]
public PostClass Copy()
{
- var post = (PostClass)((ICloneable)this).Clone();
- post.ReplyToList = new List<string>(this.ReplyToList);
- return post;
+ return this.Clone();
+ }
+
+ public PostClass Clone()
+ {
+ return (PostClass)((ICloneable)this).Clone();
}
public override bool Equals(object obj)
(this.InReplyToStatusId == other.InReplyToStatusId) &&
(this.Source == other.Source) &&
(this.SourceHtml == other.SourceHtml) &&
- (this.ReplyToList.Equals(other.ReplyToList)) &&
+ (this.ReplyToList.SequenceEqual(other.ReplyToList)) &&
(this.IsMe == other.IsMe) &&
(this.IsDm == other.IsDm) &&
(this.UserId == other.UserId) &&
(this.InReplyToUserId == other.InReplyToUserId);
}
+
+ public override int GetHashCode()
+ {
+ return this.StatusId.GetHashCode();
+ }
+
#region "IClonable.Clone"
object ICloneable.Clone()
{
- return this.MemberwiseClone();
+ var clone = (PostClass)this.MemberwiseClone();
+ clone.ReplyToList = new List<string>(this.ReplyToList);
+ clone.PostGeo = new StatusGeo { Lng = this.PostGeo.Lng, Lat = this.PostGeo.Lat };
+ clone.Media = new Dictionary<string, string>(this.Media);
+
+ return clone;
}
#endregion
}
private class ScrubGeoInfo
{
- public long UserId;
- public long UpToStatusId;
+ public long UserId = 0;
+ public long UpToStatusId = 0;
}
public List<long> BlockIds = new List<long>();
+ public List<long> MuteUserIds = new List<long>();
//発言の追加
//AddPost(複数回) -> DistributePosts -> SubmitUpdate
private TabInformations()
{
_sorter = new IdComparerClass();
- RemovedTab = _removedTab;
}
public static TabInformations GetInstance()
public bool AddTab(string TabName, MyCommon.TabUsageType TabType, ListElement List)
{
if (_tabs.ContainsKey(TabName)) return false;
- _tabs.Add(TabName, new TabClass(TabName, TabType, List));
- _tabs[TabName].Sorter.Mode = _sorter.Mode;
- _tabs[TabName].Sorter.Order = _sorter.Order;
+ var tb = new TabClass(TabName, TabType, List);
+ _tabs.Add(TabName, tb);
+ tb.Sorter.Mode = _sorter.Mode;
+ tb.Sorter.Order = _sorter.Order;
return true;
}
lock (LockObj)
{
if (IsDefaultTab(TabName)) return; //念のため
- if (!_tabs[TabName].IsInnerStorageTabType)
+ var tb = _tabs[TabName];
+ if (!tb.IsInnerStorageTabType)
{
var homeTab = GetTabByType(MyCommon.TabUsageType.Home);
- var dmName = GetTabByType(MyCommon.TabUsageType.DirectMessage).TabName;
+ var dmTab = GetTabByType(MyCommon.TabUsageType.DirectMessage);
- for (int idx = 0; idx < _tabs[TabName].AllCount; ++idx)
+ for (int idx = 0; idx < tb.AllCount; ++idx)
{
var exist = false;
- var Id = _tabs[TabName].GetId(idx);
+ var Id = tb.GetId(idx);
if (Id < 0) continue;
- foreach (var key in _tabs.Keys)
+ foreach (var tab in _tabs.Values)
{
- if (key != TabName && key != dmName)
+ if (tab != tb && tab != dmTab)
{
- if (_tabs[key].Contains(Id))
+ if (tab.Contains(Id))
{
exist = true;
break;
if (!exist) homeTab.Add(Id, _statuses[Id].IsRead, false);
}
}
- _removedTab.Push(_tabs[TabName]);
+ _removedTab.Push(tb);
_tabs.Remove(TabName);
}
}
- public Stack<TabClass> RemovedTab;
+ public Stack<TabClass> RemovedTab
+ {
+ get { return _removedTab; }
+ }
public bool ContainsTab(string TabText)
{
return _tabs.ContainsValue(ts);
}
+ /// <summary>
+ /// 指定されたタブ名を元に、既存のタブ名との重複を避けた名前を生成します
+ /// </summary>
+ /// <param name="baseTabName">作成したいタブ名</param>
+ /// <returns>生成されたタブ名</returns>
+ /// <exception cref="TabException">タブ名の生成を 100 回試行して失敗した場合</exception>
+ public string MakeTabName(string baseTabName)
+ {
+ return this.MakeTabName(baseTabName, 100);
+ }
+
+ /// <summary>
+ /// 指定されたタブ名を元に、既存のタブ名との重複を避けた名前を生成します
+ /// </summary>
+ /// <param name="baseTabName">作成したいタブ名</param>
+ /// <param name="retryCount">重複を避けたタブ名を生成する試行回数</param>
+ /// <returns>生成されたタブ名</returns>
+ /// <exception cref="TabException">retryCount で指定された回数だけタブ名の生成を試行して失敗した場合</exception>
+ public string MakeTabName(string baseTabName, int retryCount)
+ {
+ if (!this.ContainsTab(baseTabName))
+ return baseTabName;
+
+ foreach (var i in Enumerable.Range(2, retryCount - 1))
+ {
+ var tabName = baseTabName + i;
+ if (!this.ContainsTab(tabName))
+ {
+ return tabName;
+ }
+ }
+
+ var message = string.Format(Properties.Resources.TabNameDuplicate_Text, baseTabName);
+ throw new TabException(message);
+ }
+
public Dictionary<string, TabClass> Tabs
{
get
public void SortPosts()
{
- foreach (var key in _tabs.Keys)
+ foreach (var tab in _tabs.Values)
{
- _tabs[key].Sort();
+ tab.Sort();
}
}
set
{
_sorter.Order = value;
- foreach (var key in _tabs.Keys)
+ foreach (var tab in _tabs.Values)
{
- _tabs[key].Sorter.Order = value;
+ tab.Sorter.Order = value;
}
}
}
set
{
_sorter.Mode = value;
- foreach (var key in _tabs.Keys)
+ foreach (var tab in _tabs.Values)
{
- _tabs[key].Sorter.Mode = value;
+ tab.Sorter.Mode = value;
}
}
}
{
_sorter.Order = SortOrder.Ascending;
}
- foreach (var key in _tabs.Keys)
+ foreach (var tab in _tabs.Values)
{
- _tabs[key].Sorter.Order = _sorter.Order;
+ tab.Sorter.Order = _sorter.Order;
}
}
else
{
_sorter.Mode = SortMode;
_sorter.Order = SortOrder.Ascending;
- foreach (var key in _tabs.Keys)
+ foreach (var tab in _tabs.Values)
{
- _tabs[key].Sorter.Mode = SortMode;
- _tabs[key].Sorter.Order = SortOrder.Ascending;
+ tab.Sorter.Mode = SortMode;
+ tab.Sorter.Order = SortOrder.Ascending;
}
}
this.SortPosts();
// }
public PostClass RetweetSource(long Id)
{
- if (_retweets.ContainsKey(Id))
- {
- return _retweets[Id];
- }
- else
- {
- return null;
- }
+ PostClass status;
+ return _retweets.TryGetValue(Id, out status)
+ ? status
+ : null;
}
public void RemoveFavPost(long Id)
{
lock (LockObj)
{
- PostClass post = null;
+ PostClass post;
var tab = this.GetTabByType(MyCommon.TabUsageType.Favorites);
var tn = tab.TabName;
- if (_statuses.ContainsKey(Id))
+
+ if (_statuses.TryGetValue(Id, out post))
{
- post = _statuses[Id];
//指定タブから該当ID削除
var tType = tab.TabType;
if (tab.Contains(Id))
tab.Remove(Id);
}
//FavタブからRetweet発言を削除する場合は、他の同一参照Retweetも削除
- if (tType == MyCommon.TabUsageType.Favorites && post.RetweetedId > 0)
+ if (tType == MyCommon.TabUsageType.Favorites && post.RetweetedId != null)
{
for (int i = 0; i < tab.AllCount; i++)
{
{
break;
}
- if (rPost.RetweetedId > 0 && rPost.RetweetedId == post.RetweetedId)
+ if (rPost.RetweetedId != null && rPost.RetweetedId == post.RetweetedId)
{
if (tab.UnreadManage && !rPost.IsRead) //未読管理
{
{
lock (LockObj)
{
- PostClass post = null;
- //if (_statuses.ContainsKey(Id))
//各タブから該当ID削除
- foreach (var key in _tabs.Keys)
+ foreach (var tab in _tabs.Values)
{
- var tab = _tabs[key];
if (tab.Contains(Id))
{
- if (!tab.IsInnerStorageTabType)
+ if (tab.UnreadManage && !tab.Posts[Id].IsRead) //未読管理
{
- post = _statuses[Id];
- if (tab.UnreadManage && !post.IsRead) //未読管理
+ lock (LockUnread)
{
- lock (LockUnread)
- {
- tab.UnreadCount--;
- this.SetNextUnreadId(Id, tab);
- }
- }
- }
- else //未読数がずれる可能性があるためtab.Postsの未読も確認する
- {
- if (tab.UnreadManage && !tab.Posts[Id].IsRead) //未読管理
- {
- lock (LockUnread)
- {
- tab.UnreadCount--;
- this.SetNextUnreadId(Id, tab);
- }
+ tab.UnreadCount--;
+ this.SetNextUnreadId(Id, tab);
}
}
tab.Remove(Id);
{
lock (LockObj)
{
- PostClass post = null;
- if (_statuses.ContainsKey(Id))
+ PostClass post;
+ if (_statuses.TryGetValue(Id, out post))
{
- post = _statuses[Id];
post.IsDeleted = true;
}
foreach (var tb in this.GetTabsInnerStorageType())
tb.UnreadCount > 0)
{
//未読アイテムへ
- bool isRead;
- if (!tb.IsInnerStorageTabType)
- {
- isRead = _statuses[tb.OldestUnreadId].IsRead;
- }
- else
- {
- isRead = tb.Posts[tb.OldestUnreadId].IsRead;
- }
+ bool isRead = tb.Posts[tb.OldestUnreadId].IsRead;
if (isRead)
{
//状態不整合(最古未読IDが実は既読)
//最古未読が設定されていて、既読の場合(1発言以上存在)
try
{
- Dictionary<long, PostClass> posts;
- if (!Tab.IsInnerStorageTabType)
- {
- posts = _statuses;
- }
- else
- {
- posts = Tab.Posts;
- }
+ Dictionary<long, PostClass> posts = Tab.Posts;
+
+ PostClass oldestUnreadPost;
if (Tab.OldestUnreadId > -1 &&
- posts.ContainsKey(Tab.OldestUnreadId) &&
- posts[Tab.OldestUnreadId].IsRead &&
+ posts.TryGetValue(Tab.OldestUnreadId, out oldestUnreadPost) &&
+ oldestUnreadPost.IsRead &&
_sorter.Mode == IdComparerClass.ComparerMode.Id) //次の未読探索
{
if (Tab.UnreadCount == 0)
{
//続きから探索
FindUnreadId(idx, Tab);
+ return;
}
- else
- {
- //頭から探索
- FindUnreadId(-1, Tab);
- }
- }
- else
- {
- //頭から探索
- FindUnreadId(-1, Tab);
}
}
- else
- {
- //頭から探索
- FindUnreadId(-1, Tab);
- }
}
catch (KeyNotFoundException)
{
- //頭から探索
- FindUnreadId(-1, Tab);
}
+
+ //頭から探索
+ FindUnreadId(-1, Tab);
}
private void FindUnreadId(int StartIdx, TabClass Tab)
stp = -1;
}
- Dictionary<long, PostClass> posts;
- if (!Tab.IsInnerStorageTabType)
- {
- posts = _statuses;
- }
- else
- {
- posts = Tab.Posts;
- }
+ Dictionary<long, PostClass> posts = Tab.Posts;
- for (int i = StartIdx; i < toIdx; i+= stp)
+ for (int i = StartIdx; ; i+= stp)
{
var id = Tab.GetId(i);
if (id > -1 && !posts[id].IsRead)
Tab.OldestUnreadId = id;
break;
}
+
+ if (i == toIdx) break;
}
}
var mv = false; //移動フラグ(Recent追加有無)
var rslt = MyCommon.HITRESULT.None;
post.IsExcludeReply = false;
- foreach (var tn in _tabs.Keys)
+ foreach (var tab in _tabs.Values)
{
- rslt = _tabs[tn].AddFiltered(post);
+ rslt = tab.AddFiltered(post);
if (rslt != MyCommon.HITRESULT.None && rslt != MyCommon.HITRESULT.Exclude)
{
if (rslt == MyCommon.HITRESULT.CopyAndMark) post.IsMark = true; //マークあり
- if (rslt == MyCommon.HITRESULT.Move)
+ else if (rslt == MyCommon.HITRESULT.Move)
{
mv = true; //移動
post.IsMark = false;
}
- if (_tabs[tn].Notify) add = true; //通知あり
- if (_tabs[tn].SoundFile != "" && _soundFile == "")
+ if (tab.Notify) add = true; //通知あり
+ if (!string.IsNullOrEmpty(tab.SoundFile) && string.IsNullOrEmpty(_soundFile))
{
- _soundFile = _tabs[tn].SoundFile; //wavファイル(未設定の場合のみ)
+ _soundFile = tab.SoundFile; //wavファイル(未設定の場合のみ)
}
post.FilterHit = true;
}
else
{
- if (rslt == MyCommon.HITRESULT.Exclude && _tabs[tn].TabType == MyCommon.TabUsageType.Mentions)
+ if (rslt == MyCommon.HITRESULT.Exclude && tab.TabType == MyCommon.TabUsageType.Mentions)
{
post.IsExcludeReply = true;
}
if (!mv) //移動されなかったらRecentに追加
{
homeTab.Add(post.StatusId, post.IsRead, true);
- if (homeTab.SoundFile != "" && _soundFile == "") _soundFile = homeTab.SoundFile;
+ if (!string.IsNullOrEmpty(homeTab.SoundFile) && string.IsNullOrEmpty(_soundFile)) _soundFile = homeTab.SoundFile;
if (homeTab.Notify) add = true;
}
if (post.IsReply && !post.IsExcludeReply) //除外ルール適用のないReplyならReplyタブに追加
{
replyTab.Add(post.StatusId, post.IsRead, true);
- if (replyTab.SoundFile != "") _soundFile = replyTab.SoundFile;
+ if (!string.IsNullOrEmpty(replyTab.SoundFile)) _soundFile = replyTab.SoundFile;
if (replyTab.Notify) add = true;
}
if (post.IsFav) //Fav済み発言だったらFavoritesタブに追加
}
if (!exist) _notifyPosts.Add(post);
}
- if (tb.SoundFile != "")
+ if (!string.IsNullOrEmpty(tb.SoundFile))
{
- if (tb.TabType == MyCommon.TabUsageType.DirectMessage || _soundFile == "")
+ if (tb.TabType == MyCommon.TabUsageType.DirectMessage || string.IsNullOrEmpty(_soundFile))
{
_soundFile = tb.SoundFile;
}
{
lock (LockObj)
{
- if (Item.RelTabName == "")
+ if (string.IsNullOrEmpty(Item.RelTabName))
{
if (!Item.IsDm)
{
- if (_statuses.ContainsKey(Item.StatusId))
+ PostClass status;
+ if (_statuses.TryGetValue(Item.StatusId, out status))
{
if (Item.IsFav)
{
- if (Item.RetweetedId == 0)
+ if (Item.RetweetedId == null)
{
- _statuses[Item.StatusId].IsFav = true;
+ status.IsFav = true;
}
else
{
}
else
{
- if (Item.IsFav && Item.RetweetedId > 0) Item.IsFav = false;
+ if (Item.IsFav && Item.RetweetedId != null) Item.IsFav = false;
//既に持っている公式RTは捨てる
if (AppendSettingDialog.Instance.HideDuplicatedRetweets &&
!Item.IsMe &&
- this._retweets.ContainsKey(Item.RetweetedId) &&
- this._retweets[Item.RetweetedId].RetweetedCount > 0) return;
- if (BlockIds.Contains(Item.UserId)) return;
+ Item.RetweetedId != null &&
+ this._retweets.TryGetValue(Item.RetweetedId.Value, out status) &&
+ status.RetweetedCount > 0) return;
+
+ if (BlockIds.Contains(Item.UserId))
+ return;
+
+ if (this.IsMuted(Item))
+ return;
+
_statuses.Add(Item.StatusId, Item);
}
- if (Item.RetweetedId > 0)
+ if (Item.RetweetedId != null)
{
this.AddRetweet(Item);
}
{
//公式検索、リスト、関連発言の場合
TabClass tb;
- if (this.Tabs.ContainsKey(Item.RelTabName))
- {
- tb = this.Tabs[Item.RelTabName];
- }
- else
- {
- return;
- }
+ this.Tabs.TryGetValue(Item.RelTabName, out tb);
if (tb == null) return;
if (tb.Contains(Item.StatusId)) return;
//tb.Add(Item.StatusId, Item.IsRead, true);
}
}
+ private bool IsMuted(PostClass post)
+ {
+ // Recent以外のツイートと、リプライはミュート対象外
+ // 参照: https://support.twitter.com/articles/20171399-muting-users-on-twitter
+ if (string.IsNullOrEmpty(post.RelTabName) || post.IsReply)
+ return false;
+
+ if (this.MuteUserIds.Contains(post.UserId))
+ return true;
+
+ if (post.RetweetedByUserId != null && this.MuteUserIds.Contains(post.RetweetedByUserId.Value))
+ return true;
+
+ return false;
+ }
+
private void AddRetweet(PostClass item)
{
+ var retweetedId = item.RetweetedId.Value;
+
//true:追加、False:保持済み
- if (_retweets.ContainsKey(item.RetweetedId))
+ PostClass status;
+ if (_retweets.TryGetValue(retweetedId, out status))
{
- _retweets[item.RetweetedId].RetweetedCount++;
- if (_retweets[item.RetweetedId].RetweetedCount > 10)
+ status.RetweetedCount++;
+ if (status.RetweetedCount > 10)
{
- _retweets[item.RetweetedId].RetweetedCount = 0;
+ status.RetweetedCount = 0;
}
return;
}
_retweets.Add(
- item.RetweetedId,
+ item.RetweetedId.Value,
new PostClass(
item.Nickname,
item.TextFromApi,
item.ImageUrl,
item.ScreenName,
item.CreatedAt,
- item.RetweetedId,
+ item.RetweetedId.Value,
item.IsFav,
item.IsRead,
item.IsReply,
item.UserId,
item.FilterHit,
"",
- 0,
+ null,
item.PostGeo
)
);
- _retweets[item.RetweetedId].RetweetedCount++;
+ _retweets[retweetedId].RetweetedCount++;
}
public void SetReadAllTab(bool Read, string TabName, int Index)
var Id = tb.GetId(Index);
if (Id < 0) return;
- PostClass post;
- if (!tb.IsInnerStorageTabType)
- {
- post = _statuses[Id];
- }
- else
- {
- post = tb.Posts[Id];
- }
+ PostClass post = tb.Posts[Id];
if (post.IsRead == Read) return; //状態変更なければ終了
if (tb.IsInnerStorageTabType)
{
//一般タブ
- if (_statuses.ContainsKey(Id) && !_statuses[Id].IsRead)
+ PostClass status;
+ if (_statuses.TryGetValue(Id, out status) && !status.IsRead)
{
- foreach (var key in _tabs.Keys)
+ foreach (var tab in _tabs.Values)
{
- if (_tabs[key].UnreadManage &&
- _tabs[key].Contains(Id) &&
- !_tabs[key].IsInnerStorageTabType)
+ if (tab.UnreadManage &&
+ !tab.IsInnerStorageTabType &&
+ tab.Contains(Id))
{
- _tabs[key].UnreadCount--;
- if (_tabs[key].OldestUnreadId == Id) _tabs[key].OldestUnreadId = -1;
+ tab.UnreadCount--;
+ if (tab.OldestUnreadId == Id) tab.OldestUnreadId = -1;
}
}
- _statuses[Id].IsRead = true;
+ status.IsRead = true;
}
}
else
{
//一般タブ
- foreach (var key in _tabs.Keys)
+ foreach (var tab in _tabs.Values)
{
- if (key != TabName &&
- _tabs[key].UnreadManage &&
- _tabs[key].Contains(Id) &&
- !_tabs[key].IsInnerStorageTabType)
+ if (tab != tb &&
+ tab.UnreadManage &&
+ !tab.IsInnerStorageTabType &&
+ tab.Contains(Id))
{
- _tabs[key].UnreadCount--;
- if (_tabs[key].OldestUnreadId == Id) _tabs[key].OldestUnreadId = -1;
+ tab.UnreadCount--;
+ if (tab.OldestUnreadId == Id) tab.OldestUnreadId = -1;
}
}
}
//内部保存タブ
- foreach (var key in _tabs.Keys)
+ foreach (var tab in _tabs.Values)
{
- if (key != TabName &&
- _tabs[key].Contains(Id) &&
- _tabs[key].IsInnerStorageTabType &&
- !_tabs[key].Posts[Id].IsRead)
+ if (tab != tb &&
+ tab.IsInnerStorageTabType &&
+ tab.Contains(Id))
{
- if (_tabs[key].UnreadManage)
+ var tPost = tab.Posts[Id];
+ if (!tPost.IsRead)
{
- _tabs[key].UnreadCount--;
- if (_tabs[key].OldestUnreadId == Id) _tabs[key].OldestUnreadId = -1;
+ if (tab.UnreadManage)
+ {
+ tab.UnreadCount--;
+ if (tab.OldestUnreadId == Id) tab.OldestUnreadId = -1;
+ }
+ tPost.IsRead = true;
}
- _tabs[key].Posts[Id].IsRead = true;
}
}
}
if (tb.IsInnerStorageTabType)
{
//一般タブ
- if (_statuses.ContainsKey(Id) && _statuses[Id].IsRead)
+ PostClass status;
+ if (_statuses.TryGetValue(Id, out status) && status.IsRead)
{
- foreach (var key in _tabs.Keys)
+ foreach (var tab in _tabs.Values)
{
- if (_tabs[key].UnreadManage &&
- _tabs[key].Contains(Id) &&
- !_tabs[key].IsInnerStorageTabType)
- _tabs[key].UnreadCount++;
+ if (tab.UnreadManage &&
+ !tab.IsInnerStorageTabType &&
+ tab.Contains(Id))
{
- if (_tabs[key].OldestUnreadId > Id) _tabs[key].OldestUnreadId = Id;
+ tab.UnreadCount++;
+ if (tab.OldestUnreadId > Id) tab.OldestUnreadId = Id;
}
}
- _statuses[Id].IsRead = false;
+ status.IsRead = false;
}
}
else
{
//一般タブ
- foreach (var key in _tabs.Keys)
+ foreach (var tab in _tabs.Values)
{
- if (key != TabName &&
- _tabs[key].UnreadManage &&
- _tabs[key].Contains(Id) &&
- !_tabs[key].IsInnerStorageTabType)
+ if (tab != tb &&
+ tab.UnreadManage &&
+ !tab.IsInnerStorageTabType &&
+ tab.Contains(Id))
{
- _tabs[key].UnreadCount++;
- if (_tabs[key].OldestUnreadId > Id) _tabs[key].OldestUnreadId = Id;
+ tab.UnreadCount++;
+ if (tab.OldestUnreadId > Id) tab.OldestUnreadId = Id;
}
}
}
//内部保存タブ
- foreach (var key in _tabs.Keys)
+ foreach (var tab in _tabs.Values)
{
- if (key != TabName &&
- _tabs[key].Contains(Id) &&
- _tabs[key].IsInnerStorageTabType &&
- _tabs[key].Posts[Id].IsRead)
+ if (tab != tb &&
+ tab.IsInnerStorageTabType &&
+ tab.Contains(Id))
{
- if (_tabs[key].UnreadManage)
+ var tPost = tab.Posts[Id];
+ if (tPost.IsRead)
{
- _tabs[key].UnreadCount++;
- if (_tabs[key].OldestUnreadId > Id) _tabs[key].OldestUnreadId = Id;
+ if (tab.UnreadManage)
+ {
+ tab.UnreadCount++;
+ if (tab.OldestUnreadId > Id) tab.OldestUnreadId = Id;
+ }
+ tPost.IsRead = false;
}
- _tabs[key].Posts[Id].IsRead = false;
}
}
}
var Id = tb.GetId(Index);
if (Id < 0) return;
- PostClass post;
- if (!tb.IsInnerStorageTabType)
- {
- post = _statuses[Id];
- }
- else
- {
- post = tb.Posts[Id];
- }
+ PostClass post = tb.Posts[Id];
- if (post.IsRead = Read) return; //状態変更なければ終了
+ if (post.IsRead == Read) return; //状態変更なければ終了
post.IsRead = Read; //指定の状態に変更
this.SetNextUnreadId(Id, tb); //次の未読セット
//他タブの最古未読IDはタブ切り替え時に。
if (tb.IsInnerStorageTabType) return;
- foreach (var key in _tabs.Keys)
+ foreach (var tab in _tabs.Values)
{
- if (key != TabName &&
- _tabs[key].UnreadManage &&
- _tabs[key].Contains(Id) &&
- !_tabs[key].IsInnerStorageTabType)
+ if (tab != tb &&
+ tab.UnreadManage &&
+ !tab.IsInnerStorageTabType &&
+ tab.Contains(Id))
{
- _tabs[key].UnreadCount--;
- if (_tabs[key].OldestUnreadId == Id) _tabs[key].OldestUnreadId = -1;
+ tab.UnreadCount--;
+ if (tab.OldestUnreadId == Id) tab.OldestUnreadId = -1;
}
}
}
//if (tb.OldestUnreadId > Id || tb.OldestUnreadId == -1) tb.OldestUnreadId = Id;
if (tb.OldestUnreadId > Id) tb.OldestUnreadId = Id;
if (tb.IsInnerStorageTabType) return;
- foreach (var key in _tabs.Keys)
+ foreach (var tab in _tabs.Values)
{
- if (key != TabName &&
- _tabs[key].UnreadManage &&
- _tabs[key].Contains(Id) &&
- !_tabs[key].IsInnerStorageTabType)
+ if (tab != tb &&
+ tab.UnreadManage &&
+ !tab.IsInnerStorageTabType &&
+ tab.Contains(Id))
{
- _tabs[key].UnreadCount++;
- if (_tabs[key].OldestUnreadId > Id) _tabs[key].OldestUnreadId = Id;
+ tab.UnreadCount++;
+ if (tab.OldestUnreadId > Id) tab.OldestUnreadId = Id;
}
}
}
{
var id = tb.GetId(i);
if (id < 0) return;
- if (!_statuses[id].IsReply &&
- !_statuses[id].IsRead &&
- !_statuses[id].FilterHit)
+ var tPost = _statuses[id];
+ if (!tPost.IsReply &&
+ !tPost.IsRead &&
+ !tPost.FilterHit)
{
- _statuses[id].IsRead = true;
+ tPost.IsRead = true;
this.SetNextUnreadId(id, tb); //次の未読セット
- foreach (var key in _tabs.Keys)
+ foreach (var tab in _tabs.Values)
{
- if (_tabs[key].UnreadManage &&
- _tabs[key].Contains(id))
+ if (tab.UnreadManage &&
+ tab.Contains(id))
{
- _tabs[key].UnreadCount--;
- if (_tabs[key].OldestUnreadId == id) _tabs[key].OldestUnreadId = -1;
+ tab.UnreadCount--;
+ if (tab.OldestUnreadId == id) tab.OldestUnreadId = -1;
}
}
}
{
get
{
- if (_statuses.ContainsKey(ID)) return _statuses[ID];
- foreach (var tb in this.GetTabsInnerStorageType())
- {
- if (tb.Contains(ID))
- {
- return tb.Posts[ID];
- }
- }
- return null;
+ PostClass status;
+ return _statuses.TryGetValue(ID, out status)
+ ? status
+ : this.GetTabsInnerStorageType()
+ .Where(t => t.Contains(ID))
+ .Select(t => t.Posts[ID]).FirstOrDefault();
}
}
{
get
{
- if (!_tabs.ContainsKey(TabName)) throw new ArgumentException("TabName=" + TabName + " is not contained.");
- var id = _tabs[TabName].GetId(Index);
- if (id < 0) throw new ArgumentException("Index can//t find. Index=" + Index.ToString() + "/TabName=" + TabName);
+ TabClass tb;
+ if (!_tabs.TryGetValue(TabName, out tb)) throw new ArgumentException("TabName=" + TabName + " is not contained.");
+ var id = tb.GetId(Index);
+ if (id < 0) throw new ArgumentException("Index can't find. Index=" + Index.ToString() + "/TabName=" + TabName);
try
{
- if (_tabs[TabName].IsInnerStorageTabType)
- {
- return _tabs[TabName].Posts[_tabs[TabName].GetId(Index)];
- }
- else
- {
- return _statuses[_tabs[TabName].GetId(Index)];
- }
+ return tb.Posts[tb.GetId(Index)];
}
catch (Exception ex)
{
{
get
{
+ TabClass tb;
+ if (!_tabs.TryGetValue(TabName, out tb)) throw new ArgumentException("TabName=" + TabName + " is not contained.");
var length = EndIndex - StartIndex + 1;
var posts = new PostClass[length];
- if (_tabs[TabName].IsInnerStorageTabType)
- {
- for (int i = 0; i < length; i++)
- {
- posts[i] = _tabs[TabName].Posts[_tabs[TabName].GetId(StartIndex + i)];
- }
- }
- else
+ for (int i = 0; i < length; i++)
{
- for (int i = 0; i < length; i++)
- {
- posts[i] = _statuses[_tabs[TabName].GetId(StartIndex + i)];
- }
+ posts[i] = tb.Posts[tb.GetId(StartIndex + i)];
}
return posts;
}
//DM,公式検索は対応版
lock (LockObj)
{
- if (_tabs.ContainsKey(TabName))
- {
- return _tabs[TabName].Contains(Id);
- }
- else
- {
- return false;
- }
+ TabClass tab;
+ return _tabs.TryGetValue(TabName, out tab) && tab.Contains(Id);
}
}
{
if (Manage)
{
- foreach (var key in _tabs.Keys)
+ foreach (var tab in _tabs.Values)
{
- var tb = _tabs[key];
- if (tb.UnreadManage)
+ if (tab.UnreadManage)
{
lock (LockUnread)
{
var cnt = 0;
var oldest = long.MaxValue;
- Dictionary<long, PostClass> posts;
- if (!tb.IsInnerStorageTabType)
- {
- posts = _statuses;
- }
- else
- {
- posts = tb.Posts;
- }
- foreach (var id in tb.BackupIds)
+ Dictionary<long, PostClass> posts = tab.Posts;
+ foreach (var id in tab.BackupIds)
{
if (!posts[id].IsRead)
{
}
}
if (oldest == long.MaxValue) oldest = -1;
- tb.OldestUnreadId = oldest;
- tb.UnreadCount = cnt;
+ tab.OldestUnreadId = oldest;
+ tab.UnreadCount = cnt;
}
}
}
}
else
{
- foreach (var key in _tabs.Keys)
+ foreach (var tab in _tabs.Values)
{
- var tb = _tabs[key];
- if (tb.UnreadManage && tb.UnreadCount > 0)
+ if (tab.UnreadManage && tab.UnreadCount > 0)
{
lock (LockUnread)
{
- tb.UnreadCount = 0;
- tb.OldestUnreadId = -1;
+ tab.UnreadCount = 0;
+ tab.OldestUnreadId = -1;
}
}
}
tb.ClearIDs();
//////////////フィルター前のIDsを退避。どのタブにも含まれないidはrecentへ追加
//////////////moveフィルターにヒットした際、recentに該当あればrecentから削除
- foreach (var id in _statuses.Keys)
+ foreach (var post in _statuses.Values)
{
- var post = _statuses[id];
if (post.IsDm) continue;
var rslt = MyCommon.HITRESULT.None;
rslt = tb.AddFiltered(post);
//不要なPostを削除
lock (LockObj)
{
- if (!_tabs[TabName].IsInnerStorageTabType)
+ var tb = _tabs[TabName];
+ if (!tb.IsInnerStorageTabType)
{
- foreach (var Id in _tabs[TabName].BackupIds)
+ foreach (var Id in tb.BackupIds)
{
var Hit = false;
- foreach (var tb in _tabs.Values)
+ foreach (var tab in _tabs.Values)
{
- if (tb.Contains(Id))
+ if (tab.Contains(Id))
{
Hit = true;
break;
}
//指定タブをクリア
- _tabs[TabName].ClearIDs();
+ tb.ClearIDs();
}
}
{
var cnt = 0;
var oldest = long.MaxValue;
- Dictionary<long, PostClass> posts;
- if (!tb.IsInnerStorageTabType)
- {
- posts = _statuses;
- }
- else
- {
- posts = tb.Posts;
- }
+ Dictionary<long, PostClass> posts = tb.Posts;
foreach (var id in tb.BackupIds)
{
if (!posts[id].IsRead)
}
else
{
- foreach (var id in _statuses.Keys)
+ foreach (var post in _statuses.Values)
{
- _statuses[id].IsOwl = false;
+ post.IsOwl = false;
}
}
}
//合致しなければnullを返す
lock (LockObj)
{
- foreach (var tb in _tabs.Values)
+ foreach (var tab in _tabs.Values)
{
- if (tb != null && tb.TabType == tabType) return tb;
+ if (tab.TabType == tabType) return tab;
}
return null;
}
{
lock (LockObj)
{
- if (_tabs.ContainsKey(tabName)) return _tabs[tabName];
- return null;
+ TabClass tab;
+ return _tabs.TryGetValue(tabName, out tab)
+ ? tab
+ : null;
}
}
// デフォルトタブの判定処理
public bool IsDefaultTab(string tabName)
{
+ TabClass tab;
if (tabName != null &&
- _tabs.ContainsKey(tabName) &&
- (_tabs[tabName].TabType == MyCommon.TabUsageType.Home ||
- _tabs[tabName].TabType == MyCommon.TabUsageType.Mentions ||
- _tabs[tabName].TabType == MyCommon.TabUsageType.DirectMessage ||
- _tabs[tabName].TabType == MyCommon.TabUsageType.Favorites))
+ _tabs.TryGetValue(tabName, out tab) &&
+ (tab.TabType == MyCommon.TabUsageType.Home ||
+ tab.TabType == MyCommon.TabUsageType.Mentions ||
+ tab.TabType == MyCommon.TabUsageType.DirectMessage ||
+ tab.TabType == MyCommon.TabUsageType.Favorites))
{
return true;
}
- else
- {
- return false;
- }
+
+ return false;
}
//振り分け可能タブの判定処理
public bool IsDistributableTab(string tabName)
{
- return tabName != null &&
- this._tabs.ContainsKey(tabName) &&
- (_tabs[tabName].TabType == MyCommon.TabUsageType.Mentions ||
- _tabs[tabName].TabType == MyCommon.TabUsageType.UserDefined);
+ TabClass tab;
+ if (tabName != null &&
+ _tabs.TryGetValue(tabName, out tab) &&
+ (tab.TabType == MyCommon.TabUsageType.Mentions ||
+ tab.TabType == MyCommon.TabUsageType.UserDefined))
+ {
+ return true;
+ }
+
+ return false;
}
public string GetUniqueTabName()
public sealed class TabClass
{
private bool _unreadManage = false;
- private List<FiltersClass> _filters;
+ private List<PostFilterRule> _filters;
private int _unreadCount = 0;
private List<long> _ids;
private List<TemporaryId> _tmpIds = new List<TemporaryId>();
private MyCommon.TabUsageType _tabType = MyCommon.TabUsageType.Undefined;
+
+ [NonSerialized]
private IdComparerClass _sorter = new IdComparerClass();
private readonly object _lockObj = new object();
#endregion
#region "リスト"
+ [NonSerialized]
private ListElement _listInfo;
public ListElement ListInfo
{
public long SinceId { get; set; }
[XmlIgnore]
- public Dictionary<long, PostClass> Posts { get; set; }
+ public Dictionary<long, PostClass> Posts { get; private set; }
+
+ private Dictionary<long, PostClass> _innerPosts;
public PostClass[] GetTemporaryPosts()
{
public TabClass()
{
- Posts = new Dictionary<long, PostClass>();
+ _innerPosts = new Dictionary<long, PostClass>();
+ Posts = _innerPosts;
SoundFile = "";
OldestUnreadId = -1;
TabName = "";
- _filters = new List<FiltersClass>();
+ _filters = new List<PostFilterRule>();
+ Protected = false;
Notify = true;
SoundFile = "";
_unreadManage = true;
_listInfo = null;
}
- public TabClass(string TabName, MyCommon.TabUsageType TabType, ListElement list)
+ public TabClass(string TabName, MyCommon.TabUsageType TabType, ListElement list) : this()
{
- Posts = new Dictionary<long, PostClass>();
- SoundFile = "";
- OldestUnreadId = -1;
this.TabName = TabName;
- _filters = new List<FiltersClass>();
- Notify = true;
- SoundFile = "";
- _unreadManage = true;
- _ids = new List<long>();
- this.OldestUnreadId = -1;
- _tabType = TabType;
+ this.TabType = TabType;
this.ListInfo = list;
- if (this.IsInnerStorageTabType)
- {
- _sorter.posts = Posts;
- }
- else
- {
- _sorter.posts = TabInformations.GetInstance().Posts;
- }
}
public void Sort()
{
try
{
- switch (ft.IsHit(post)) //フィルタクラスでヒット判定
+ switch (ft.ExecFilter(post)) //フィルタクラスでヒット判定
{
case MyCommon.HITRESULT.None:
break;
}
catch (NullReferenceException)
{
- //IsHitでNullRef出る場合あり。暫定対応
- MyCommon.TraceOut("IsHitでNullRef: " + ft.ToString());
+ // ExecFilterでNullRef出る場合あり。暫定対応
+ MyCommon.TraceOut("ExecFilterでNullRef: " + ft.ToString());
rslt = MyCommon.HITRESULT.None;
}
}
//検索結果の追加
public void AddPostToInnerStorage(PostClass Post)
{
- if (Posts.ContainsKey(Post.StatusId)) return;
- Posts.Add(Post.StatusId, Post);
+ if (_innerPosts.ContainsKey(Post.StatusId)) return;
+ _innerPosts.Add(Post.StatusId, Post);
_tmpIds.Add(new TemporaryId(Post.StatusId, Post.IsRead));
}
{
if (!this._ids.Contains(Id)) return;
this._ids.Remove(Id);
- if (this.IsInnerStorageTabType) Posts.Remove(Id);
+ if (this.IsInnerStorageTabType) _innerPosts.Remove(Id);
}
public void Remove(long Id, bool Read)
}
this._ids.Remove(Id);
- if (this.IsInnerStorageTabType) Posts.Remove(Id);
+ if (this.IsInnerStorageTabType) _innerPosts.Remove(Id);
}
public bool UnreadManage
}
}
+ // v1.0.5で「タブを固定(Locked)」から「タブを保護(Protected)」に名称変更
+ [XmlElement(ElementName = "Locked")]
+ public bool Protected { get; set; }
+
public bool Notify { get; set; }
public string SoundFile { get; set; }
}
}
- public FiltersClass[] GetFilters()
+ public PostFilterRule[] GetFilters()
{
lock (this._lockObj)
{
}
}
- public void RemoveFilter(FiltersClass filter)
+ public void RemoveFilter(PostFilterRule filter)
{
lock (this._lockObj)
{
}
}
- public bool AddFilter(FiltersClass filter)
+ public bool AddFilter(PostFilterRule filter)
{
lock (this._lockObj)
{
}
}
- public void EditFilter(FiltersClass original, FiltersClass modified)
+ public void EditFilter(PostFilterRule original, PostFilterRule modified)
{
- original.BodyFilter = modified.BodyFilter;
- original.NameFilter = modified.NameFilter;
- original.SearchBoth = modified.SearchBoth;
- original.SearchUrl = modified.SearchUrl;
+ original.FilterBody = modified.FilterBody;
+ original.FilterName = modified.FilterName;
+ original.UseNameField = modified.UseNameField;
+ original.FilterByUrl = modified.FilterByUrl;
original.UseRegex = modified.UseRegex;
original.CaseSensitive = modified.CaseSensitive;
- original.IsRt = modified.IsRt;
+ original.FilterRt = modified.FilterRt;
original.UseLambda = modified.UseLambda;
- original.Source = modified.Source;
- original.ExBodyFilter = modified.ExBodyFilter;
- original.ExNameFilter = modified.ExNameFilter;
- original.ExSearchBoth = modified.ExSearchBoth;
- original.ExSearchUrl = modified.ExSearchUrl;
+ original.FilterSource = modified.FilterSource;
+ original.ExFilterBody = modified.ExFilterBody;
+ original.ExFilterName = modified.ExFilterName;
+ original.ExUseNameField = modified.ExUseNameField;
+ original.ExFilterByUrl = modified.ExFilterByUrl;
original.ExUseRegex = modified.ExUseRegex;
original.ExCaseSensitive = modified.ExCaseSensitive;
- original.IsExRt = modified.IsExRt;
+ original.ExFilterRt = modified.ExFilterRt;
original.ExUseLambda = modified.ExUseLambda;
- original.ExSource = modified.ExSource;
- original.MoveFrom = modified.MoveFrom;
- original.SetMark = modified.SetMark;
+ original.ExFilterSource = modified.ExFilterSource;
+ original.MoveMatches = modified.MoveMatches;
+ original.MarkMatches = modified.MarkMatches;
this.FilterModified = true;
}
[XmlIgnore]
- public List<FiltersClass> Filters
+ public List<PostFilterRule> Filters
{
get
{
}
}
- public FiltersClass[] FilterArray
+ public PostFilterRule[] FilterArray
{
get
{
_tmpIds.Clear();
_unreadCount = 0;
this.OldestUnreadId = -1;
- if (Posts != null)
- {
- Posts.Clear();
- }
+ _innerPosts.Clear();
}
public long GetId(int Index)
_tabType = value;
if (this.IsInnerStorageTabType)
{
- _sorter.posts = Posts;
+ Posts = _innerPosts;
}
else
{
- _sorter.posts = TabInformations.GetInstance().Posts;
+ Posts = TabInformations.GetInstance().Posts;
}
+ _sorter.posts = Posts;
}
}
}
}
- [Serializable]
- public sealed class FiltersClass : System.IEquatable<FiltersClass>
- {
- private string _name = "";
- private List<string> _body = new List<string>();
- private bool _searchBoth = true;
- private bool _searchUrl = false;
- private bool _caseSensitive = false;
- private bool _useRegex = false;
- private bool _isRt = false;
- private string _source = "";
- private string _exname = "";
- private List<string> _exbody = new List<string>();
- private bool _exsearchBoth = true;
- private bool _exsearchUrl = false;
- private bool _exuseRegex = false;
- private bool _excaseSensitive = false;
- private bool _isExRt = false;
- private string _exSource = "";
- private bool _moveFrom = false;
- private bool _setMark = true;
- private bool _useLambda = false;
- private bool _exuseLambda = false;
-
- // ラムダ式コンパイルキャッシュ
- private LambdaExpression _lambdaExp = null;
- private Delegate _lambdaExpDelegate = null;
- private LambdaExpression _exlambdaExp = null;
- private Delegate _exlambdaExpDelegate = null;
-
- public FiltersClass() {}
-
- //フィルタ一覧に表示する文言生成
- private string MakeSummary()
- {
- var fs = new StringBuilder();
- if (!string.IsNullOrEmpty(_name) || _body.Count > 0 || _isRt || !string.IsNullOrEmpty(_source))
- {
- if (_searchBoth)
- {
- if (!string.IsNullOrEmpty(_name))
- {
- fs.AppendFormat(Properties.Resources.SetFiltersText1, _name);
- }
- else
- {
- fs.Append(Properties.Resources.SetFiltersText2);
- }
- }
- if (_body.Count > 0)
- {
- fs.Append(Properties.Resources.SetFiltersText3);
- foreach (var bf in _body)
- {
- fs.Append(bf);
- fs.Append(" ");
- }
- fs.Length--;
- fs.Append(Properties.Resources.SetFiltersText4);
- }
- fs.Append("(");
- if (_searchBoth)
- {
- fs.Append(Properties.Resources.SetFiltersText5);
- }
- else
- {
- fs.Append(Properties.Resources.SetFiltersText6);
- }
- if (_useRegex)
- {
- fs.Append(Properties.Resources.SetFiltersText7);
- }
- if (_searchUrl)
- {
- fs.Append(Properties.Resources.SetFiltersText8);
- }
- if (_caseSensitive)
- {
- fs.Append(Properties.Resources.SetFiltersText13);
- }
- if (_isRt)
- {
- fs.Append("RT/");
- }
- if (_useLambda)
- {
- fs.Append("LambdaExp/");
- }
- if (!string.IsNullOrEmpty(_source))
- {
- fs.AppendFormat("Src…{0}/", _source);
- }
- fs.Length--;
- fs.Append(")");
- }
- if (!string.IsNullOrEmpty(_exname) || _exbody.Count > 0 || _isExRt || !string.IsNullOrEmpty(_exSource))
- {
- //除外
- fs.Append(Properties.Resources.SetFiltersText12);
- if (_exsearchBoth)
- {
- if (!string.IsNullOrEmpty(_exname))
- {
- fs.AppendFormat(Properties.Resources.SetFiltersText1, _exname);
- }
- else
- {
- fs.Append(Properties.Resources.SetFiltersText2);
- }
- }
- if (_exbody.Count > 0)
- {
- fs.Append(Properties.Resources.SetFiltersText3);
- foreach (var bf in _exbody)
- {
- fs.Append(bf);
- fs.Append(" ");
- }
- fs.Length--;
- fs.Append(Properties.Resources.SetFiltersText4);
- }
- fs.Append("(");
- if (_exsearchBoth)
- {
- fs.Append(Properties.Resources.SetFiltersText5);
- }
- else
- {
- fs.Append(Properties.Resources.SetFiltersText6);
- }
- if (_exuseRegex)
- {
- fs.Append(Properties.Resources.SetFiltersText7);
- }
- if (_exsearchUrl)
- {
- fs.Append(Properties.Resources.SetFiltersText8);
- }
- if (_excaseSensitive)
- {
- fs.Append(Properties.Resources.SetFiltersText13);
- }
- if (_isExRt)
- {
- fs.Append("RT/");
- }
- if (_exuseLambda)
- {
- fs.Append("LambdaExp/");
- }
- if (!string.IsNullOrEmpty(_exSource))
- {
- fs.AppendFormat("Src…{0}/", _exSource);
- }
- fs.Length--;
- fs.Append(")");
- }
-
- fs.Append("(");
- if (_moveFrom)
- {
- fs.Append(Properties.Resources.SetFiltersText9);
- }
- else
- {
- fs.Append(Properties.Resources.SetFiltersText11);
- }
- if (!_moveFrom && _setMark)
- {
- fs.Append(Properties.Resources.SetFiltersText10);
- }
- else if (!_moveFrom)
- {
- fs.Length--;
- }
-
- fs.Append(")");
-
- return fs.ToString();
- }
-
- public string NameFilter
- {
- get
- {
- return _name;
- }
- set
- {
- _name = value;
- }
- }
-
- public string ExNameFilter
- {
- get
- {
- return _exname;
- }
- set
- {
- _exname = value;
- }
- }
-
- [XmlIgnore]
- public List<string> BodyFilter
- {
- get
- {
- return _body;
- }
- set
- {
- _lambdaExp = null;
- _lambdaExpDelegate = null;
- _body = value;
- }
- }
-
- public string[] BodyFilterArray
- {
- get
- {
- return _body.ToArray();
- }
- set
- {
- _body = new List<string>();
- foreach (var filter in value)
- {
- _body.Add(filter);
- }
- }
- }
-
- [XmlIgnore]
- public List<string> ExBodyFilter
- {
- get
- {
- return _exbody;
- }
- set
- {
- _exlambdaExp = null;
- _exlambdaExpDelegate = null;
- _exbody = value;
- }
- }
-
- public string[] ExBodyFilterArray
- {
- get
- {
- return _exbody.ToArray();
- }
- set
- {
- _exbody = new List<string>();
- foreach (var filter in value)
- {
- _exbody.Add(filter);
- }
- }
- }
-
- public bool SearchBoth
- {
- get
- {
- return _searchBoth;
- }
- set
- {
- _searchBoth = value;
- }
- }
-
- public bool ExSearchBoth
- {
- get
- {
- return _exsearchBoth;
- }
- set
- {
- _exsearchBoth = value;
- }
- }
-
- public bool MoveFrom
- {
- get
- {
- return _moveFrom;
- }
- set
- {
- _moveFrom = value;
- }
- }
-
- public bool SetMark
- {
- get
- {
- return _setMark;
- }
- set
- {
- _setMark = value;
- }
- }
-
- public bool SearchUrl
- {
- get
- {
- return _searchUrl;
- }
- set
- {
- _searchUrl = value;
- }
- }
-
- public bool ExSearchUrl
- {
- get
- {
- return _exsearchUrl;
- }
- set
- {
- _exsearchUrl = value;
- }
- }
-
- public bool CaseSensitive
- {
- get
- {
- return _caseSensitive;
- }
- set
- {
- _caseSensitive = value;
- }
- }
-
- public bool ExCaseSensitive
- {
- get
- {
- return _excaseSensitive;
- }
- set
- {
- _excaseSensitive = value;
- }
- }
-
- public bool UseLambda
- {
- get
- {
- return _useLambda;
- }
- set
- {
- _lambdaExp = null;
- _lambdaExpDelegate = null;
- _useLambda = value;
- }
- }
-
- public bool ExUseLambda
- {
- get
- {
- return _exuseLambda;
- }
- set
- {
- _exlambdaExp = null;
- _exlambdaExpDelegate = null;
- _exuseLambda = value;
- }
- }
-
- public bool UseRegex
- {
- get
- {
- return _useRegex;
- }
- set
- {
- _useRegex = value;
- }
- }
-
- public bool ExUseRegex
- {
- get
- {
- return _exuseRegex;
- }
- set
- {
- _exuseRegex = value;
- }
- }
-
- public bool IsRt
- {
- get
- {
- return _isRt;
- }
- set
- {
- _isRt = value;
- }
- }
-
- public bool IsExRt
- {
- get
- {
- return _isExRt;
- }
- set
- {
- _isExRt = value;
- }
- }
-
- public string Source
- {
- get
- {
- return _source;
- }
- set
- {
- _source = value;
- }
- }
-
- public string ExSource
- {
- get
- {
- return _exSource;
- }
- set
- {
- _exSource = value;
- }
- }
-
- public override string ToString()
- {
- return MakeSummary();
- }
-
- public bool ExecuteLambdaExpression(string expr, PostClass post)
- {
- return false;
- // TODO DynamicQuery相当のGPLv3互換なライブラリで置換する
- }
-
- public bool ExecuteExLambdaExpression(string expr, PostClass post)
- {
- return false;
- // TODO DynamicQuery相当のGPLv3互換なライブラリで置換する
- }
-
- public MyCommon.HITRESULT IsHit(PostClass post)
- {
- var bHit = true;
- string tBody;
- string tSource;
- if (_searchUrl)
- {
- tBody = post.Text;
- tSource = post.SourceHtml;
- }
- else
- {
- tBody = post.TextFromApi;
- tSource = post.Source;
- }
- //検索オプション
- System.StringComparison compOpt;
- System.Text.RegularExpressions.RegexOptions rgOpt;
- if (_caseSensitive)
- {
- compOpt = StringComparison.Ordinal;
- rgOpt = RegexOptions.None;
- }
- else
- {
- compOpt = StringComparison.OrdinalIgnoreCase;
- rgOpt = RegexOptions.IgnoreCase;
- }
- if (_searchBoth)
- {
- if (string.IsNullOrEmpty(_name) ||
- (!_useRegex &&
- (post.ScreenName.Equals(_name, compOpt) ||
- post.RetweetedBy.Equals(_name, compOpt)
- )
- ) ||
- (_useRegex &&
- (Regex.IsMatch(post.ScreenName, _name, rgOpt) ||
- (!string.IsNullOrEmpty(post.RetweetedBy) && Regex.IsMatch(post.RetweetedBy, _name, rgOpt))
- )
- ))
- {
- if (_useLambda)
- {
- if (!ExecuteLambdaExpression(_body[0], post)) bHit = false;
- }
- else
- {
- foreach (var fs in _body)
- {
- if (_useRegex)
- {
- if (!Regex.IsMatch(tBody, fs, rgOpt)) bHit = false;
- }
- else
- {
- if (_caseSensitive)
- {
- if (!tBody.Contains(fs)) bHit = false;
- }
- else
- {
- if (!tBody.ToLower().Contains(fs.ToLower())) bHit = false;
- }
- }
- if (!bHit) break;
- }
- }
- }
- else
- {
- bHit = false;
- }
- }
- else
- {
- if (_useLambda)
- {
- if (!ExecuteLambdaExpression(_body[0], post)) bHit = false;
- }
- else
- {
- foreach (var fs in _body)
- {
- if (_useRegex)
- {
- if (!(Regex.IsMatch(post.ScreenName, fs, rgOpt) ||
- (!string.IsNullOrEmpty(post.RetweetedBy) && Regex.IsMatch(post.RetweetedBy, fs, rgOpt)) ||
- Regex.IsMatch(tBody, fs, rgOpt))) bHit = false;
- }
- else
- {
- if (_caseSensitive)
- {
- if (!(post.ScreenName.Contains(fs) ||
- post.RetweetedBy.Contains(fs) ||
- tBody.Contains(fs))) bHit = false;
- }
- else
- {
- if (!(post.ScreenName.ToLower().Contains(fs.ToLower()) ||
- post.RetweetedBy.ToLower().Contains(fs.ToLower()) ||
- tBody.ToLower().Contains(fs.ToLower()))) bHit = false;
- }
- }
- if (!bHit) break;
- }
- }
- }
- if (_isRt)
- {
- if (post.RetweetedId == 0) bHit = false;
- }
- if (!string.IsNullOrEmpty(_source))
- {
- if (_useRegex)
- {
- if (!Regex.IsMatch(tSource, _source, rgOpt)) bHit = false;
- }
- else
- {
- if (!tSource.Equals(_source, compOpt)) bHit = false;
- }
- }
- if (bHit)
- {
- //除外判定
- if (_exsearchUrl)
- {
- tBody = post.Text;
- tSource = post.SourceHtml;
- }
- else
- {
- tBody = post.TextFromApi;
- tSource = post.Source;
- }
-
- var exFlag = false;
- if (!string.IsNullOrEmpty(_exname) || _exbody.Count > 0)
- {
- if (_excaseSensitive)
- {
- compOpt = StringComparison.Ordinal;
- rgOpt = RegexOptions.None;
- }
- else
- {
- compOpt = StringComparison.OrdinalIgnoreCase;
- rgOpt = RegexOptions.IgnoreCase;
- }
- if (_exsearchBoth)
- {
- if (string.IsNullOrEmpty(_exname) ||
- (!_exuseRegex &&
- (post.ScreenName.Equals(_exname, compOpt) ||
- post.RetweetedBy.Equals(_exname, compOpt)
- )
- ) ||
- (_exuseRegex &&
- (Regex.IsMatch(post.ScreenName, _exname, rgOpt) ||
- (!string.IsNullOrEmpty(post.RetweetedBy) && Regex.IsMatch(post.RetweetedBy, _exname, rgOpt))
- )
- ))
- {
- if (_exbody.Count > 0)
- {
- if (_exuseLambda)
- {
- if (ExecuteExLambdaExpression(_exbody[0], post)) exFlag = true;
- }
- else
- {
- foreach (var fs in _exbody)
- {
- if (_exuseRegex)
- {
- if (Regex.IsMatch(tBody, fs, rgOpt)) exFlag = true;
- }
- else
- {
- if (_excaseSensitive)
- {
- if (tBody.Contains(fs)) exFlag = true;
- }
- else
- {
- if (tBody.ToLower().Contains(fs.ToLower())) exFlag = true;
- }
- }
- if (exFlag) break;
- }
- }
- }
- else
- {
- exFlag = true;
- }
- }
- }
- else
- {
- if (_exuseLambda)
- {
- if (ExecuteExLambdaExpression(_exbody[0], post)) exFlag = true;
- }
- else
- {
- foreach (var fs in _exbody)
- {
- if (_exuseRegex)
- {
- if (Regex.IsMatch(post.ScreenName, fs, rgOpt) ||
- (!string.IsNullOrEmpty(post.RetweetedBy) && Regex.IsMatch(post.RetweetedBy, fs, rgOpt)) ||
- Regex.IsMatch(tBody, fs, rgOpt)) exFlag = true;
- }
- else
- {
- if (_excaseSensitive)
- {
- if (post.ScreenName.Contains(fs) ||
- post.RetweetedBy.Contains(fs) ||
- tBody.Contains(fs)) exFlag = true;
- }
- else
- {
- if (post.ScreenName.ToLower().Contains(fs.ToLower()) ||
- post.RetweetedBy.ToLower().Contains(fs.ToLower()) ||
- tBody.ToLower().Contains(fs.ToLower())) exFlag = true;
- }
- }
- if (exFlag) break;
- }
- }
- }
- }
- if (_isExRt)
- {
- if (post.RetweetedId > 0) exFlag = true;
- }
- if (!string.IsNullOrEmpty(_exSource))
- {
- if (_exuseRegex)
- {
- if (Regex.IsMatch(tSource, _exSource, rgOpt)) exFlag = true;
- }
- else
- {
- if (tSource.Equals(_exSource, compOpt)) exFlag = true;
- }
- }
-
- if (string.IsNullOrEmpty(_name) && _body.Count == 0 && !_isRt && string.IsNullOrEmpty(_source))
- {
- bHit = false;
- }
- if (bHit)
- {
- if (!exFlag)
- {
- if (_moveFrom)
- {
- return MyCommon.HITRESULT.Move;
- }
- else
- {
- if (_setMark)
- {
- return MyCommon.HITRESULT.CopyAndMark;
- }
- return MyCommon.HITRESULT.Copy;
- }
- }
- else
- {
- return MyCommon.HITRESULT.Exclude;
- }
- }
- else
- {
- if (exFlag)
- {
- return MyCommon.HITRESULT.Exclude;
- }
- else
- {
- return MyCommon.HITRESULT.None;
- }
- }
- }
- else
- {
- return MyCommon.HITRESULT.None;
- }
- }
-
- public bool Equals(FiltersClass other)
- {
- if (this.BodyFilter.Count != other.BodyFilter.Count) return false;
- if (this.ExBodyFilter.Count != other.ExBodyFilter.Count) return false;
- for (int i = 0; i < this.BodyFilter.Count; i++)
- {
- if (this.BodyFilter[i] != other.BodyFilter[i]) return false;
- }
- for (int i = 0; i < this.ExBodyFilter.Count; i++)
- {
- if (this.ExBodyFilter[i] != other.ExBodyFilter[i]) return false;
- }
-
- return (this.MoveFrom == other.MoveFrom) &
- (this.SetMark == other.SetMark) &
- (this.NameFilter == other.NameFilter) &
- (this.SearchBoth == other.SearchBoth) &
- (this.SearchUrl == other.SearchUrl) &
- (this.UseRegex == other.UseRegex) &
- (this.ExNameFilter == other.ExNameFilter) &
- (this.ExSearchBoth == other.ExSearchBoth) &
- (this.ExSearchUrl == other.ExSearchUrl) &
- (this.ExUseRegex == other.ExUseRegex) &
- (this.IsRt == other.IsRt) &
- (this.Source == other.Source) &
- (this.IsExRt == other.IsExRt) &
- (this.ExSource == other.ExSource) &
- (this.UseLambda == other.UseLambda) &
- (this.ExUseLambda == other.ExUseLambda);
- }
-
- public FiltersClass CopyTo(FiltersClass destination)
- {
- if (this.BodyFilter.Count > 0)
- {
- foreach (var flt in this.BodyFilter)
- {
- destination.BodyFilter.Add(string.Copy(flt));
- }
- }
-
- if (this.ExBodyFilter.Count > 0)
- {
- foreach (var flt in this.ExBodyFilter)
- {
- destination.ExBodyFilter.Add(string.Copy(flt));
- }
- }
-
- destination.MoveFrom = this.MoveFrom;
- destination.SetMark = this.SetMark;
- destination.NameFilter = this.NameFilter;
- destination.SearchBoth = this.SearchBoth;
- destination.SearchUrl = this.SearchUrl;
- destination.UseRegex = this.UseRegex;
- destination.ExNameFilter = this.ExNameFilter;
- destination.ExSearchBoth = this.ExSearchBoth;
- destination.ExSearchUrl = this.ExSearchUrl;
- destination.ExUseRegex = this.ExUseRegex;
- destination.IsRt = this.IsRt;
- destination.Source = this.Source;
- destination.IsExRt = this.IsExRt;
- destination.ExSource = this.ExSource;
- destination.UseLambda = this.UseLambda;
- destination.ExUseLambda = this.ExUseLambda;
- return destination;
- }
-
- public override bool Equals(object obj)
- {
- if (obj == null || this.GetType() != obj.GetType()) return false;
- return this.Equals((FiltersClass)obj);
- }
-
- public override int GetHashCode()
- {
- return this.MoveFrom.GetHashCode() ^
- this.SetMark.GetHashCode() ^
- this.BodyFilter.GetHashCode() ^
- this.NameFilter.GetHashCode() ^
- this.SearchBoth.GetHashCode() ^
- this.SearchUrl.GetHashCode() ^
- this.UseRegex.GetHashCode() ^
- this.ExBodyFilter.GetHashCode() ^
- this.ExNameFilter.GetHashCode() ^
- this.ExSearchBoth.GetHashCode() ^
- this.ExSearchUrl.GetHashCode() ^
- this.ExUseRegex.GetHashCode() ^
- this.IsRt.GetHashCode() ^
- this.Source.GetHashCode() ^
- this.IsExRt.GetHashCode() ^
- this.ExSource.GetHashCode() ^
- this.UseLambda.GetHashCode() ^
- this.ExUseLambda.GetHashCode();
- }
- }
-
//ソート比較クラス:ID比較のみ
public sealed class IdComparerClass : IComparer<long>
{