1 ' Tween - Client of Twitter
2 ' Copyright (c) 2007-2010 kiri_feather (@kiri_feather) <kiri_feather@gmail.com>
3 ' (c) 2008-2010 Moz (@syo68k) <http://iddy.jp/profile/moz/>
4 ' (c) 2008-2010 takeshik (@takeshik) <http://www.takeshik.org/>
7 ' This file is part of Tween.
9 ' This program is free software; you can redistribute it and/or modify it
10 ' under the terms of the GNU General Public License as published by the Free
11 ' Software Foundation; either version 3 of the License, or (at your option)
14 ' This program is distributed in the hope that it will be useful, but
15 ' WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 ' or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 ' You should have received a copy of the GNU General Public License along
20 ' with this program. If not, see <http://www.gnu.org/licenses/>, or write to
21 ' the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
22 ' Boston, MA 02110-1301, USA.
24 Imports System.Collections.Generic
25 Imports System.Collections.ObjectModel
26 Imports Tween.TweenCustomControl
27 Imports System.Text.RegularExpressions
28 Imports System.Web.HttpUtility
31 Public NotInheritable Class PostClass
33 Private _Nick As String
34 Private _Data As String
35 Private _ImageUrl As String
36 Private _Name As String
37 Private _PDate As Date
39 Private _IsFav As Boolean
40 Private _OrgData As String
41 Private _IsRead As Boolean
42 Private _IsReply As Boolean
43 Private _IsExcludeReply As Boolean
44 Private _IsProtect As Boolean
45 Private _IsOWL As Boolean
46 Private _IsMark As Boolean
47 Private _InReplyToUser As String
48 Private _InReplyToId As Long
49 Private _Source As String
50 Private _SourceHtml As String
51 Private _ReplyToList As New List(Of String)
52 Private _IsMe As Boolean
53 Private _IsDm As Boolean
54 Private _statuses As Statuses = Statuses.None
56 Private _FilterHit As Boolean
57 Private _RetweetedBy As String = ""
58 Private _RetweetedId As Long = 0
59 Private _searchTabName As String = ""
70 Public Sub New(ByVal Nickname As String, _
71 ByVal Data As String, _
72 ByVal OriginalData As String, _
73 ByVal ImageUrl As String, _
74 ByVal Name As String, _
75 ByVal PDate As Date, _
77 ByVal IsFav As Boolean, _
78 ByVal IsRead As Boolean, _
79 ByVal IsReply As Boolean, _
80 ByVal IsExcludeReply As Boolean, _
81 ByVal IsProtect As Boolean, _
82 ByVal IsOwl As Boolean, _
83 ByVal IsMark As Boolean, _
84 ByVal InReplyToUser As String, _
85 ByVal InReplyToId As Long, _
86 ByVal Source As String, _
87 ByVal SourceHtml As String, _
88 ByVal ReplyToList As List(Of String), _
89 ByVal IsMe As Boolean, _
90 ByVal IsDm As Boolean, _
92 ByVal FilterHit As Boolean, _
93 ByVal RetweetedBy As String, _
94 ByVal RetweetedId As Long)
102 _OrgData = OriginalData
105 _IsExcludeReply = IsExcludeReply
106 _IsProtect = IsProtect
109 _InReplyToUser = InReplyToUser
110 _InReplyToId = InReplyToId
112 _SourceHtml = SourceHtml
113 _ReplyToList = ReplyToList
117 _FilterHit = FilterHit
118 _RetweetedBy = RetweetedBy
119 _RetweetedId = RetweetedId
125 Public Property Nickname() As String
129 Set(ByVal value As String)
133 Public Property Data() As String
137 Set(ByVal value As String)
141 Public Property ImageUrl() As String
145 Set(ByVal value As String)
149 Public Property Name() As String
153 Set(ByVal value As String)
157 Public Property PDate() As Date
161 Set(ByVal value As Date)
165 Public Property Id() As Long
169 Set(ByVal value As Long)
173 Public Property IsFav() As Boolean
175 If Me.RetweetedId > 0 AndAlso TabInformations.GetInstance.RetweetSource(Me.RetweetedId) IsNot Nothing Then
176 Return TabInformations.GetInstance.RetweetSource(Me.RetweetedId).IsFav
181 Set(ByVal value As Boolean)
183 If Me.RetweetedId > 0 AndAlso TabInformations.GetInstance.RetweetSource(Me.RetweetedId) IsNot Nothing Then
184 TabInformations.GetInstance.RetweetSource(Me.RetweetedId).IsFav = value
188 Public Property OriginalData() As String
192 Set(ByVal value As String)
196 Public Property IsRead() As Boolean
200 Set(ByVal value As Boolean)
202 _statuses = _statuses Or Statuses.Read
204 _statuses = _statuses And Not Statuses.Read
209 Public Property IsReply() As Boolean
213 Set(ByVal value As Boolean)
217 Public Property IsExcludeReply() As Boolean
219 Return _IsExcludeReply
221 Set(ByVal value As Boolean)
222 _IsExcludeReply = value
225 Public Property IsProtect() As Boolean
229 Set(ByVal value As Boolean)
231 _statuses = _statuses Or Statuses.Protect
233 _statuses = _statuses And Not Statuses.Protect
238 Public Property IsOwl() As Boolean
242 Set(ByVal value As Boolean)
246 Public Property IsMark() As Boolean
250 Set(ByVal value As Boolean)
252 _statuses = _statuses Or Statuses.Mark
254 _statuses = _statuses And Not Statuses.Mark
259 Public Property InReplyToUser() As String
261 Return _InReplyToUser
263 Set(ByVal value As String)
264 _InReplyToUser = value
267 Public Property InReplyToId() As Long
271 Set(ByVal value As Long)
275 Public Property Source() As String
279 Set(ByVal value As String)
283 Public Property SourceHtml() As String
287 Set(ByVal value As String)
291 Public Property ReplyToList() As List(Of String)
295 Set(ByVal value As List(Of String))
299 Public Property IsMe() As Boolean
303 Set(ByVal value As Boolean)
307 Public Property IsDm() As Boolean
311 Set(ByVal value As Boolean)
315 Public ReadOnly Property StatusIndex() As Integer
320 Public Property Uid() As Long
324 Set(ByVal value As Long)
328 Public Property FilterHit() As Boolean
332 Set(ByVal value As Boolean)
336 Public Property RetweetedBy() As String
340 Set(ByVal value As String)
344 Public Property RetweetedId() As Long
348 Set(ByVal value As Long)
352 Public Property RelTabName() As String
354 Return _searchTabName
356 Set(ByVal value As String)
357 _searchTabName = value
361 Public Function Copy() As PostClass
362 Dim post As PostClass = DirectCast(Me.Clone, PostClass)
363 post.ReplyToList = New List(Of String)(Me.ReplyToList)
367 #Region "IClonable.Clone"
368 Private Function Clone() As Object Implements ICloneable.Clone
369 Return Me.MemberwiseClone()
374 Public NotInheritable Class TabInformations
375 '個別タブの情報をDictionaryで保持
376 Private _sorter As IdComparerClass
377 Private _tabs As New Dictionary(Of String, TabClass)
378 Private _statuses As New Dictionary(Of Long, PostClass)
379 Private _addedIds As List(Of Long)
380 Private _retweets As New Dictionary(Of Long, PostClass)
381 Private _removedTab As TabClass = Nothing
384 'AddPost(複数回) -> DistributePosts -> SubmitUpdate
387 Private _addCount As Integer
388 Private _soundFile As String
389 Private _notifyPosts As List(Of PostClass)
390 Private ReadOnly LockObj As New Object
391 Private ReadOnly LockUnread As New Object
393 Private Shared _instance As TabInformations = New TabInformations
396 Private _lists As New List(Of ListElement)
399 _sorter = New IdComparerClass()
402 Public Shared Function GetInstance() As TabInformations
403 Return _instance 'singleton
406 Public Property SubscribableLists() As List(Of ListElement)
410 Set(ByVal value As List(Of ListElement))
411 If value IsNot Nothing AndAlso value.Count > 0 Then
412 For Each tb As TabClass In Me.GetTabsByType(TabUsageType.Lists)
413 For Each list As ListElement In value
414 If tb.ListInfo.Id = list.Id Then
425 Public Sub AddTab(ByVal TabName As String, ByVal TabType As TabUsageType, ByVal List As ListElement)
426 _tabs.Add(TabName, New TabClass(TabName, TabType, List))
427 _tabs(TabName).Sorter.Mode = _sorter.Mode
428 _tabs(TabName).Sorter.Order = _sorter.Order
431 'Public Sub AddTab(ByVal TabName As String, ByVal Tab As TabClass)
432 ' _tabs.Add(TabName, Tab)
435 Public Sub RemoveTab(ByVal TabName As String)
437 If IsDefaultTab(TabName) Then Exit Sub '念のため
438 If Not _tabs(TabName).IsInnerStorageTabType Then
439 Dim homeTab As TabClass = GetTabByType(TabUsageType.Home)
440 Dim dmName As String = GetTabByType(TabUsageType.DirectMessage).TabName
442 For idx As Integer = 0 To _tabs(TabName).AllCount - 1
443 Dim exist As Boolean = False
444 Dim Id As Long = _tabs(TabName).GetId(idx)
445 For Each key As String In _tabs.Keys
446 If Not key = TabName AndAlso key <> dmName Then
447 If _tabs(key).Contains(Id) Then
453 If Not exist Then homeTab.Add(Id, _statuses(Id).IsRead, False)
456 If _removedTab IsNot Nothing Then _removedTab = Nothing
457 _removedTab = _tabs(TabName)
458 _tabs.Remove(TabName)
462 Public Property RemovedTab() As TabClass
466 Set(ByVal value As TabClass)
471 Public Function ContainsTab(ByVal TabText As String) As Boolean
472 Return _tabs.ContainsKey(TabText)
475 Public Function ContainsTab(ByVal ts As TabClass) As Boolean
476 Return _tabs.ContainsValue(ts)
479 Public Property Tabs() As Dictionary(Of String, TabClass)
483 Set(ByVal value As Dictionary(Of String, TabClass))
488 Public ReadOnly Property KeysTab() As Collections.Generic.Dictionary(Of String, TabClass).KeyCollection
494 Public Sub SortPosts()
495 For Each key As String In _tabs.Keys
500 Public Property SortOrder() As SortOrder
504 Set(ByVal value As SortOrder)
505 _sorter.Order = value
506 For Each key As String In _tabs.Keys
507 _tabs(key).Sorter.Order = value
512 Public Property SortMode() As IdComparerClass.ComparerMode
516 Set(ByVal value As IdComparerClass.ComparerMode)
518 For Each key As String In _tabs.Keys
519 _tabs(key).Sorter.Mode = value
524 Public Function ToggleSortOrder(ByVal SortMode As IdComparerClass.ComparerMode) As Windows.Forms.SortOrder
525 If _sorter.Mode = SortMode Then
526 If _sorter.Order = Windows.Forms.SortOrder.Ascending Then
527 _sorter.Order = Windows.Forms.SortOrder.Descending
529 _sorter.Order = Windows.Forms.SortOrder.Ascending
531 For Each key As String In _tabs.Keys
532 _tabs(key).Sorter.Order = _sorter.Order
535 _sorter.Mode = SortMode
536 _sorter.Order = Windows.Forms.SortOrder.Ascending
537 For Each key As String In _tabs.Keys
538 _tabs(key).Sorter.Mode = SortMode
539 _tabs(key).Sorter.Order = Windows.Forms.SortOrder.Ascending
546 Public ReadOnly Property RetweetSource(ByVal Id As Long) As PostClass
548 If _retweets.ContainsKey(Id) Then
556 Public Sub RemoveFavPost(ByVal Id As Long)
558 Dim post As PostClass = Nothing
559 Dim tab As TabClass = Me.GetTabByType(TabUsageType.Favorites)
560 Dim tn As String = tab.TabName
561 If _statuses.ContainsKey(Id) Then
564 Dim tType As TabUsageType = tab.TabType
565 If tab.Contains(Id) Then
566 If tab.UnreadManage AndAlso Not post.IsRead Then '未読管理
569 Me.SetNextUnreadId(Id, tab)
574 'FavタブからRetweet発言を削除する場合は、他の同一参照Retweetも削除
575 If tType = TabUsageType.Favorites AndAlso post.RetweetedId > 0 Then
576 For i As Integer = 0 To tab.AllCount - 1
577 Dim rPost As PostClass = Nothing
579 rPost = Me.Item(tn, i)
580 Catch ex As ArgumentOutOfRangeException
583 If rPost.RetweetedId > 0 AndAlso rPost.RetweetedId = post.RetweetedId Then
584 If tab.UnreadManage AndAlso Not rPost.IsRead Then '未読管理
587 Me.SetNextUnreadId(rPost.Id, tab)
595 ''TabType=PublicSearchの場合(Postの保存先がTabClass内)
596 'If tab.Contains(Id) AndAlso _
597 ' (tab.TabType = TabUsageType.PublicSearch OrElse tab.TabType = TabUsageType.DirectMessage) Then
598 ' post = tab.Posts(Id)
599 ' If tab.UnreadManage AndAlso Not post.IsRead Then '未読管理
600 ' SyncLock LockUnread
601 ' tab.UnreadCount -= 1
602 ' Me.SetNextUnreadId(Id, tab)
610 Public Sub RemovePost(ByVal Id As Long)
612 Dim post As PostClass = Nothing
613 If _statuses.ContainsKey(Id) Then
616 For Each key As String In _tabs.Keys
617 Dim tab As TabClass = _tabs(key)
618 If tab.Contains(Id) Then
619 If tab.UnreadManage AndAlso Not post.IsRead Then '未読管理
622 Me.SetNextUnreadId(Id, tab)
630 For Each tb As TabClass In _tabs.Values
631 If tb.IsInnerStorageTabType AndAlso tb.Contains(Id) Then
633 If tb.UnreadManage AndAlso Not post.IsRead Then
636 Me.SetNextUnreadId(Id, tb)
645 Public Function GetOldestUnreadId(ByVal TabName As String) As Integer
646 Dim tb As TabClass = _tabs(TabName)
647 If tb.OldestUnreadId > -1 AndAlso _
648 tb.Contains(tb.OldestUnreadId) AndAlso _
649 tb.UnreadCount > 0 Then
651 Dim isRead As Boolean
652 If Not tb.IsInnerStorageTabType Then
653 isRead = _statuses(tb.OldestUnreadId).IsRead
655 isRead = tb.Posts(tb.OldestUnreadId).IsRead
660 Me.SetNextUnreadId(-1, tb) '頭から探索
662 If tb.OldestUnreadId = -1 Then
665 Return tb.IndexOf(tb.OldestUnreadId)
668 Return tb.IndexOf(tb.OldestUnreadId) '最短経路
671 '一見未読なさそうだが、未読カウントはあるので探索
672 'If tb.UnreadCount > 0 Then
673 If Not tb.UnreadManage Then Return -1
675 Me.SetNextUnreadId(-1, tb)
677 If tb.OldestUnreadId = -1 Then
680 Return tb.IndexOf(tb.OldestUnreadId)
688 Private Sub SetNextUnreadId(ByVal CurrentId As Long, ByVal Tab As TabClass)
689 'CurrentID:今既読にしたID(OldestIDの可能性あり)
690 '最古未読が設定されていて、既読の場合(1発言以上存在)
692 Dim posts As Dictionary(Of Long, PostClass)
693 If Not Tab.IsInnerStorageTabType Then
698 If Tab.OldestUnreadId > -1 AndAlso _
699 posts.ContainsKey(Tab.OldestUnreadId) AndAlso _
700 posts.Item(Tab.OldestUnreadId).IsRead AndAlso _
701 _sorter.Mode = IdComparerClass.ComparerMode.Id Then '次の未読探索
702 If Tab.UnreadCount = 0 Then
704 Tab.OldestUnreadId = -1
705 ElseIf Tab.OldestUnreadId = CurrentId AndAlso CurrentId > -1 Then
706 '最古IDを既読にしたタイミング→次のIDから続けて探索
707 Dim idx As Integer = Tab.IndexOf(CurrentId)
710 FindUnreadId(idx, Tab)
713 FindUnreadId(-1, Tab)
717 FindUnreadId(-1, Tab)
721 FindUnreadId(-1, Tab)
723 Catch ex As Generic.KeyNotFoundException
725 FindUnreadId(-1, Tab)
729 Private Sub FindUnreadId(ByVal StartIdx As Integer, ByVal Tab As TabClass)
730 If Tab.AllCount = 0 Then
731 Tab.OldestUnreadId = -1
735 Dim toIdx As Integer = 0
736 Dim stp As Integer = 1
737 Tab.OldestUnreadId = -1
738 If _sorter.Order = Windows.Forms.SortOrder.Ascending Then
739 If StartIdx = -1 Then
743 If StartIdx > Tab.AllCount - 1 Then StartIdx = Tab.AllCount - 1 '念のため
745 toIdx = Tab.AllCount - 1
746 If toIdx < 0 Then toIdx = 0 '念のため
749 If StartIdx = -1 Then
750 StartIdx = Tab.AllCount - 1
754 If StartIdx < 0 Then StartIdx = 0 '念のため
758 If Not Tab.IsInnerStorageTabType Then
759 For i As Integer = StartIdx To toIdx Step stp
760 If Not _statuses(Tab.GetId(i)).IsRead Then
761 Tab.OldestUnreadId = Tab.GetId(i)
766 For i As Integer = StartIdx To toIdx Step stp
767 If Not Tab.Posts(Tab.GetId(i)).IsRead Then
768 Tab.OldestUnreadId = Tab.GetId(i)
775 Public Function DistributePosts() As Integer
778 'If _addedIds Is Nothing Then Return 0
779 'If _addedIds.Count = 0 Then Return 0
781 If _addedIds Is Nothing Then _addedIds = New List(Of Long)
782 If _notifyPosts Is Nothing Then _notifyPosts = New List(Of PostClass)
783 Me.Distribute() 'タブに仮振分
784 Dim retCnt As Integer = _addedIds.Count
787 _addedIds = Nothing '後始末
792 Public Function SubmitUpdate(ByRef soundFile As String, ByRef notifyPosts As PostClass(), ByRef isMentionIncluded As Boolean) As Integer
795 If _notifyPosts Is Nothing Then
797 notifyPosts = Nothing
801 For Each tb As TabClass In _tabs.Values
802 If tb.IsInnerStorageTabType Then
803 _addCount += tb.GetTemporaryCount
805 tb.AddSubmit(isMentionIncluded) '振分確定(各タブに反映)
809 soundFile = _soundFile
811 notifyPosts = _notifyPosts.ToArray()
813 _notifyPosts = Nothing
814 Dim retCnt As Integer = _addCount
816 Return retCnt '件数(EndUpdateの戻り値と同じ)
820 Private Sub Distribute()
821 '各タブのフィルターと照合。合致したらタブにID追加
822 '通知メッセージ用に、表示必要な発言リストと再生サウンドを返す
823 'notifyPosts = New List(Of PostClass)
824 Dim homeTab As TabClass = GetTabByType(TabUsageType.Home)
825 Dim replyTab As TabClass = GetTabByType(TabUsageType.Mentions)
826 Dim dmTab As TabClass = GetTabByType(TabUsageType.DirectMessage)
827 Dim favTab As TabClass = GetTabByType(TabUsageType.Favorites)
828 For Each id As Long In _addedIds
829 Dim post As PostClass = _statuses(id)
830 Dim add As Boolean = False '通知リスト追加フラグ
831 Dim mv As Boolean = False '移動フラグ(Recent追加有無)
832 Dim rslt As HITRESULT = HITRESULT.None
833 post.IsExcludeReply = False
834 For Each tn As String In _tabs.Keys
835 rslt = _tabs(tn).AddFiltered(post)
836 If rslt <> HITRESULT.None AndAlso rslt <> HITRESULT.Exclude Then
837 If rslt = HITRESULT.CopyAndMark Then post.IsMark = True 'マークあり
838 If rslt = HITRESULT.Move Then
842 If _tabs(tn).Notify Then add = True '通知あり
843 If Not _tabs(tn).SoundFile = "" AndAlso _soundFile = "" Then
844 _soundFile = _tabs(tn).SoundFile 'wavファイル(未設定の場合のみ)
846 post.FilterHit = True
848 If rslt = HITRESULT.Exclude AndAlso _tabs(tn).TabType = TabUsageType.Mentions Then
849 post.IsExcludeReply = True
851 post.FilterHit = False
854 If Not mv Then '移動されなかったらRecentに追加
855 homeTab.Add(post.Id, post.IsRead, True)
856 If Not homeTab.SoundFile = "" AndAlso _soundFile = "" Then _soundFile = homeTab.SoundFile
857 If homeTab.Notify Then add = True
859 If post.IsReply AndAlso Not post.IsExcludeReply Then '除外ルール適用のないReplyならReplyタブに追加
860 replyTab.Add(post.Id, post.IsRead, True)
861 If Not replyTab.SoundFile = "" Then _soundFile = replyTab.SoundFile
862 If replyTab.Notify Then add = True
864 If post.IsFav Then 'Fav済み発言だったらFavoritesタブに追加
865 If favTab.Contains(post.Id) Then
870 favTab.Add(post.Id, post.IsRead, True)
871 If Not String.IsNullOrEmpty(favTab.SoundFile) AndAlso String.IsNullOrEmpty(_soundFile) Then _soundFile = favTab.SoundFile
872 If favTab.Notify Then add = True
875 If add Then _notifyPosts.Add(post)
877 For Each tb As TabClass In _tabs.Values
878 If tb.IsInnerStorageTabType Then
880 If tb.GetTemporaryCount > 0 Then
881 For Each post As PostClass In tb.GetTemporaryPosts
882 Dim exist As Boolean = False
883 For Each npost As PostClass In _notifyPosts
884 If npost.Id = post.Id Then
889 If Not exist Then _notifyPosts.Add(post)
891 If tb.SoundFile <> "" Then
892 If tb.TabType = TabUsageType.DirectMessage OrElse _soundFile = "" Then
893 _soundFile = tb.SoundFile
902 Public Sub AddPost(ByVal Item As PostClass)
904 If Item.RelTabName = "" Then
905 If Not Item.IsDm Then
906 If _statuses.ContainsKey(Item.Id) Then
908 _statuses.Item(Item.Id).IsFav = True
910 Exit Sub '追加済みなら何もしない
913 _statuses.Add(Item.Id, Item)
915 If Item.RetweetedId > 0 Then
918 If Item.IsFav AndAlso _retweets.ContainsKey(Item.Id) Then
919 Exit Sub 'Fav済みのRetweet元発言は追加しない
921 If _addedIds Is Nothing Then _addedIds = New List(Of Long) 'タブ追加用IDコレクション準備
922 _addedIds.Add(Item.Id)
925 Dim tb As TabClass = Me.GetTabByType(TabUsageType.DirectMessage)
926 If tb.Contains(Item.Id) Then Exit Sub
927 tb.AddPostToInnerStorage(Item)
932 If Me.Tabs.ContainsKey(Item.RelTabName) Then
933 tb = Me.Tabs(Item.RelTabName)
937 If tb Is Nothing Then Exit Sub
938 If tb.Contains(Item.Id) Then Exit Sub
939 'tb.Add(Item.Id, Item.IsRead, True)
940 tb.AddPostToInnerStorage(Item)
945 Private Sub AddRetweet(ByVal item As PostClass)
946 If _retweets.ContainsKey(item.RetweetedId) Then Exit Sub
961 item.IsExcludeReply, _
965 item.InReplyToUser, _
980 Public Sub SetRead(ByVal Read As Boolean, ByVal TabName As String, ByVal Index As Integer)
981 'Read:True=既読へ False=未読へ
982 Dim tb As TabClass = _tabs(TabName)
984 If tb.UnreadManage = False Then Exit Sub '未読管理していなければ終了
986 Dim Id As Long = tb.GetId(Index)
987 Dim post As PostClass
988 If Not tb.IsInnerStorageTabType Then
993 If post.IsRead = Read Then Exit Sub '状態変更なければ終了
995 post.IsRead = Read '指定の状態に変更
1000 Me.SetNextUnreadId(Id, tb) '次の未読セット
1001 '他タブの最古未読IDはタブ切り替え時に。
1002 If tb.IsInnerStorageTabType Then Exit Sub
1003 For Each key As String In _tabs.Keys
1004 If key <> TabName AndAlso _
1005 _tabs(key).UnreadManage AndAlso _
1006 _tabs(key).Contains(Id) AndAlso _
1007 Not _tabs(key).IsInnerStorageTabType Then
1008 _tabs(key).UnreadCount -= 1
1009 If _tabs(key).OldestUnreadId = Id Then _tabs(key).OldestUnreadId = -1
1014 If tb.OldestUnreadId > Id OrElse tb.OldestUnreadId = -1 Then tb.OldestUnreadId = Id
1015 If tb.IsInnerStorageTabType Then Exit Sub
1016 For Each key As String In _tabs.Keys
1017 If Not key = TabName AndAlso _
1018 _tabs(key).UnreadManage AndAlso _
1019 _tabs(key).Contains(Id) AndAlso _
1020 Not _tabs(key).IsInnerStorageTabType Then
1021 _tabs(key).UnreadCount += 1
1022 If _tabs(key).OldestUnreadId > Id Then _tabs(key).OldestUnreadId = Id
1029 Public Sub SetRead()
1030 Dim tb As TabClass = GetTabByType(TabUsageType.Home)
1031 If tb.UnreadManage = False Then Exit Sub
1033 For i As Integer = 0 To tb.AllCount - 1
1034 Dim id As Long = tb.GetId(i)
1035 If Not _statuses(id).IsReply AndAlso _
1036 Not _statuses(id).IsRead AndAlso _
1037 Not _statuses(id).FilterHit Then
1038 _statuses(id).IsRead = True
1039 Me.SetNextUnreadId(id, tb) '次の未読セット
1040 For Each key As String In _tabs.Keys
1041 If _tabs(key).UnreadManage AndAlso _
1042 _tabs(key).Contains(id) Then
1043 _tabs(key).UnreadCount -= 1
1044 If _tabs(key).OldestUnreadId = id Then _tabs(key).OldestUnreadId = -1
1051 Public ReadOnly Property Item(ByVal ID As Long) As PostClass
1053 If _statuses.ContainsKey(ID) Then Return _statuses(ID)
1054 For Each tb As TabClass In _tabs.Values
1055 If tb.IsInnerStorageTabType AndAlso _
1056 tb.Contains(ID) Then
1064 Public ReadOnly Property Item(ByVal TabName As String, ByVal Index As Integer) As PostClass
1066 'If Not _tabs.ContainsKey(TabName) Then Return Nothing
1067 If _tabs(TabName).IsInnerStorageTabType Then
1068 Return _tabs(TabName).Posts(_tabs(TabName).GetId(Index))
1070 Return _statuses(_tabs(TabName).GetId(Index))
1075 Public ReadOnly Property Item(ByVal TabName As String, ByVal StartIndex As Integer, ByVal EndIndex As Integer) As PostClass()
1077 Dim length As Integer = EndIndex - StartIndex + 1
1078 Dim posts() As PostClass = New PostClass(length - 1) {}
1079 If _tabs(TabName).IsInnerStorageTabType Then
1080 For i As Integer = 0 To length - 1
1081 posts(i) = _tabs(TabName).Posts(_tabs(TabName).GetId(StartIndex + i))
1084 For i As Integer = 0 To length - 1
1085 posts(i) = _statuses(_tabs(TabName).GetId(StartIndex + i))
1092 'Public ReadOnly Property ItemCount() As Integer
1095 ' Return _statuses.Count 'DM,公式検索は除く
1100 Public Function ContainsKey(ByVal Id As Long) As Boolean
1103 Return _statuses.ContainsKey(Id)
1107 Public Function ContainsKey(ByVal Id As Long, ByVal TabName As String) As Boolean
1110 Return _tabs(TabName).Contains(Id)
1114 Public Sub SetUnreadManage(ByVal Manage As Boolean)
1116 For Each key As String In _tabs.Keys
1117 Dim tb As TabClass = _tabs(key)
1118 If tb.UnreadManage Then
1120 Dim cnt As Integer = 0
1121 Dim oldest As Long = Long.MaxValue
1122 Dim posts As Dictionary(Of Long, PostClass)
1123 If Not tb.IsInnerStorageTabType Then
1128 For Each id As Long In tb.BackupIds
1129 If Not posts(id).IsRead Then
1131 If oldest > id Then oldest = id
1134 If oldest = Long.MaxValue Then oldest = -1
1135 tb.OldestUnreadId = oldest
1136 tb.UnreadCount = cnt
1141 For Each key As String In _tabs.Keys
1142 Dim tb As TabClass = _tabs(key)
1143 If tb.UnreadManage AndAlso tb.UnreadCount > 0 Then
1146 tb.OldestUnreadId = -1
1153 Public Sub RenameTab(ByVal Original As String, ByVal NewName As String)
1154 Dim tb As TabClass = _tabs(Original)
1155 _tabs.Remove(Original)
1156 tb.TabName = NewName
1157 _tabs.Add(NewName, tb)
1160 Public Sub FilterAll()
1162 Dim tbr As TabClass = GetTabByType(TabUsageType.Home)
1163 Dim replyTab As TabClass = GetTabByType(TabUsageType.Mentions)
1164 For Each key As String In _tabs.Keys
1165 Dim tb As TabClass = _tabs(key)
1166 If tb.FilterModified Then
1167 tb.FilterModified = False
1168 Dim orgIds() As Long = tb.BackupIds()
1170 ''''''''''''''フィルター前のIDsを退避。どのタブにも含まれないidはrecentへ追加
1171 ''''''''''''''moveフィルターにヒットした際、recentに該当あればrecentから削除
1172 For Each id As Long In _statuses.Keys
1173 Dim post As PostClass = _statuses.Item(id)
1174 If post.IsDm Then Continue For
1175 Dim rslt As HITRESULT = HITRESULT.None
1176 rslt = tb.AddFiltered(post)
1178 Case HITRESULT.CopyAndMark
1179 post.IsMark = True 'マークあり
1180 post.FilterHit = True
1182 tbr.Remove(post.Id, post.IsRead)
1184 post.FilterHit = True
1187 post.FilterHit = True
1188 Case HITRESULT.Exclude
1189 If key = replyTab.TabName AndAlso post.IsReply Then post.IsExcludeReply = True
1190 If post.IsFav Then GetTabByType(TabUsageType.Favorites).Add(post.Id, post.IsRead, True)
1191 post.FilterHit = False
1193 If key = replyTab.TabName AndAlso post.IsReply Then replyTab.Add(post.Id, post.IsRead, True)
1194 If post.IsFav Then GetTabByType(TabUsageType.Favorites).Add(post.Id, post.IsRead, True)
1195 post.FilterHit = False
1198 tb.AddSubmit() '振分確定
1199 For Each id As Long In orgIds
1200 Dim hit As Boolean = False
1201 For Each tkey As String In _tabs.Keys
1202 If _tabs(tkey).Contains(id) Then
1207 If Not hit Then tbr.Add(id, _statuses(id).IsRead, False)
1215 Public Function GetId(ByVal TabName As String, ByVal IndexCollection As ListView.SelectedIndexCollection) As Long()
1216 If IndexCollection.Count = 0 Then Return Nothing
1218 Dim tb As TabClass = _tabs(TabName)
1219 Dim Ids(IndexCollection.Count - 1) As Long
1220 For i As Integer = 0 To Ids.Length - 1
1221 Ids(i) = tb.GetId(IndexCollection(i))
1226 Public Function GetId(ByVal TabName As String, ByVal Index As Integer) As Long
1227 Return _tabs(TabName).GetId(Index)
1230 Public Function IndexOf(ByVal TabName As String, ByVal Ids() As Long) As Integer()
1231 If Ids Is Nothing Then Return Nothing
1232 Dim idx(Ids.Length - 1) As Integer
1233 Dim tb As TabClass = _tabs(TabName)
1234 For i As Integer = 0 To Ids.Length - 1
1235 idx(i) = tb.IndexOf(Ids(i))
1240 Public Function IndexOf(ByVal TabName As String, ByVal Id As Long) As Integer
1241 Return _tabs(TabName).IndexOf(Id)
1244 Public Sub ClearTabIds(ByVal TabName As String)
1247 If Not _tabs(TabName).IsInnerStorageTabType Then
1248 For Each Id As Long In _tabs(TabName).BackupIds
1249 Dim Hit As Boolean = False
1250 For Each tb As TabClass In _tabs.Values
1251 If tb.Contains(Id) Then
1256 If Not Hit Then _statuses.Remove(Id)
1261 _tabs(TabName).ClearIDs()
1265 Public Sub SetTabUnreadManage(ByVal TabName As String, ByVal Manage As Boolean)
1266 Dim tb As TabClass = _tabs(TabName)
1269 Dim cnt As Integer = 0
1270 Dim oldest As Long = Long.MaxValue
1271 Dim posts As Dictionary(Of Long, PostClass)
1272 If Not tb.IsInnerStorageTabType Then
1277 For Each id As Long In tb.BackupIds
1278 If Not posts(id).IsRead Then
1280 If oldest > id Then oldest = id
1283 If oldest = Long.MaxValue Then oldest = -1
1284 tb.OldestUnreadId = oldest
1285 tb.UnreadCount = cnt
1287 tb.OldestUnreadId = -1
1291 tb.UnreadManage = Manage
1294 Public Sub RefreshOwl(ByVal follower As List(Of Long))
1296 If follower.Count > 0 Then
1297 For Each post As PostClass In _statuses.Values
1298 'If post.Uid = 0 OrElse post.IsDm Then Continue For
1302 post.IsOwl = Not follower.Contains(post.Uid)
1306 For Each id As Long In _statuses.Keys
1307 _statuses(id).IsOwl = False
1313 Public Function GetTabByType(ByVal tabType As TabUsageType) As TabClass
1314 'Home,Mentions,DM,Favは1つに制限する
1315 'その他のタイプを指定されたら、最初に合致したものを返す
1318 For Each tb As TabClass In _tabs.Values
1319 If tb IsNot Nothing AndAlso tb.TabType = tabType Then Return tb
1325 Public Function GetTabsByType(ByVal tabType As TabUsageType) As List(Of TabClass)
1329 Dim tbs As New List(Of TabClass)
1330 For Each tb As TabClass In _tabs.Values
1331 If (tabType And tb.TabType) = tb.TabType Then tbs.Add(tb)
1337 Public Function GetTabByName(ByVal tabName As String) As TabClass
1339 If _tabs.ContainsKey(tabName) Then Return _tabs(tabName)
1345 Public Function IsDefaultTab(ByVal tabName As String) As Boolean
1346 If tabName IsNot Nothing AndAlso _
1347 _tabs.ContainsKey(tabName) AndAlso _
1348 (_tabs(tabName).TabType = TabUsageType.Home OrElse _
1349 _tabs(tabName).TabType = TabUsageType.Mentions OrElse _
1350 _tabs(tabName).TabType = TabUsageType.DirectMessage OrElse _
1351 _tabs(tabName).TabType = TabUsageType.Favorites) Then
1358 Public Function GetUniqueTabName() As String
1359 Dim tabNameTemp As String = "MyTab" + (_tabs.Count + 1).ToString
1360 For i As Integer = 2 To 100
1361 If _tabs.ContainsKey(tabNameTemp) Then
1362 tabNameTemp = "MyTab" + (_tabs.Count + i).ToString
1370 Public ReadOnly Property Posts() As Dictionary(Of Long, PostClass)
1378 Public NotInheritable Class TabClass
1379 Private _unreadManage As Boolean = False
1380 Private _notify As Boolean = False
1381 Private _soundFile As String = ""
1382 Private _filters As List(Of FiltersClass)
1383 Private _oldestUnreadItem As Long = -1 'ID
1384 Private _unreadCount As Integer = 0
1385 Private _ids As List(Of Long)
1386 Private _filterMod As Boolean = False
1387 Private _tmpIds As New List(Of TemporaryId)
1388 Private _tabName As String = ""
1389 Private _tabType As TabUsageType = TabUsageType.Undefined
1390 Private _posts As New Dictionary(Of Long, PostClass)
1391 Private _sorter As New IdComparerClass
1392 Private _oldestId As Long = Long.MaxValue '古いポスト取得用
1393 Private _sinceId As Long = 0
1394 Private _relationTargetId As Long = 0
1396 Private ReadOnly _lockObj As New Object
1400 Private _searchLang As String = ""
1401 Private _searchWords As String = ""
1403 Public Property SearchLang() As String
1407 Set(ByVal value As String)
1412 Public Property SearchWords() As String
1416 Set(ByVal value As String)
1418 _searchWords = value.Trim
1421 Public Function GetSearchPage(ByVal count As Integer) As Integer
1422 Return ((_ids.Count \ count) + 1)
1424 Private _beforeQuery As New Dictionary(Of String, String)
1425 Public Sub SaveQuery(ByVal more As Boolean)
1426 Dim qry As New Dictionary(Of String, String)
1427 If String.IsNullOrEmpty(_searchWords) Then
1431 qry.Add("q", _searchWords)
1432 If Not String.IsNullOrEmpty(_searchLang) Then qry.Add("lang", _searchLang)
1436 Public Function IsQueryChanged() As Boolean
1437 Dim qry As New Dictionary(Of String, String)
1438 If Not String.IsNullOrEmpty(_searchWords) Then
1439 qry.Add("q", _searchWords)
1440 If Not String.IsNullOrEmpty(_searchLang) Then qry.Add("lang", _searchLang)
1442 If qry.Count <> _beforeQuery.Count Then Return True
1444 For Each kvp As KeyValuePair(Of String, String) In qry
1445 If Not _beforeQuery.ContainsKey(kvp.Key) OrElse _beforeQuery(kvp.Key) <> kvp.Value Then
1453 Private _listInfo As ListElement
1454 Public Property ListInfo() As ListElement
1458 Set(ByVal value As ListElement)
1464 <Xml.Serialization.XmlIgnore()> _
1465 Public Property RelationTargetId() As Long
1467 Return _relationTargetId
1469 Set(ByVal value As Long)
1470 _relationTargetId = value
1474 <Xml.Serialization.XmlIgnore()> _
1475 Public Property OldestId() As Long
1479 Set(ByVal value As Long)
1484 <Xml.Serialization.XmlIgnore()> _
1485 Public Property SinceId() As Long
1489 Set(ByVal value As Long)
1494 <Xml.Serialization.XmlIgnore()> _
1495 Public Property Posts() As Dictionary(Of Long, PostClass)
1499 Set(ByVal value As Dictionary(Of Long, PostClass))
1504 'Public Function SearchedPost(ByVal Id As Long) As PostClass
1505 ' If Not _posts.ContainsKey(Id) Then Return Nothing
1509 Public Function GetTemporaryPosts() As PostClass()
1510 Dim tempPosts As New List(Of PostClass)
1511 If _tmpIds.Count = 0 Then Return tempPosts.ToArray
1512 For Each tempId As TemporaryId In _tmpIds
1513 tempPosts.Add(_posts(tempId.Id))
1515 Return tempPosts.ToArray
1518 Public Function GetTemporaryCount() As Integer
1519 Return _tmpIds.Count
1522 Private Structure TemporaryId
1524 Public Read As Boolean
1526 Public Sub New(ByVal argId As Long, ByVal argRead As Boolean)
1533 _filters = New List(Of FiltersClass)
1536 _unreadManage = True
1537 _ids = New List(Of Long)
1538 _oldestUnreadItem = -1
1539 _tabType = TabUsageType.Undefined
1543 Public Sub New(ByVal TabName As String, ByVal TabType As TabUsageType, ByVal list As ListElement)
1545 _filters = New List(Of FiltersClass)
1548 _unreadManage = True
1549 _ids = New List(Of Long)
1550 _oldestUnreadItem = -1
1553 If Me.IsInnerStorageTabType Then
1554 _sorter.posts = _posts
1556 _sorter.posts = TabInformations.GetInstance.Posts
1561 _ids.Sort(_sorter.CmpMethod)
1564 Public ReadOnly Property Sorter() As IdComparerClass
1571 Private Sub Add(ByVal ID As Long, ByVal Read As Boolean)
1572 If Me._ids.Contains(ID) Then Exit Sub
1576 If Not Read AndAlso Me._unreadManage Then
1577 Me._unreadCount += 1
1578 If Me._oldestUnreadItem = -1 Then
1579 Me._oldestUnreadItem = ID
1581 If ID < Me._oldestUnreadItem Then Me._oldestUnreadItem = ID
1586 Public Sub Add(ByVal ID As Long, ByVal Read As Boolean, ByVal Temporary As Boolean)
1587 If Not Temporary Then
1590 _tmpIds.Add(New TemporaryId(ID, Read))
1595 Public Function AddFiltered(ByVal post As PostClass) As HITRESULT
1596 If Me.IsInnerStorageTabType Then Return HITRESULT.None
1598 Dim rslt As HITRESULT = HITRESULT.None
1600 SyncLock Me._lockObj
1601 For Each ft As FiltersClass In _filters
1602 Select Case ft.IsHit(post) 'フィルタクラスでヒット判定
1605 If rslt <> HITRESULT.CopyAndMark Then rslt = HITRESULT.Copy
1606 Case HITRESULT.CopyAndMark
1607 rslt = HITRESULT.CopyAndMark
1609 rslt = HITRESULT.Move
1610 Case HITRESULT.Exclude
1611 rslt = HITRESULT.Exclude
1617 If rslt <> HITRESULT.None AndAlso rslt <> HITRESULT.Exclude Then
1618 _tmpIds.Add(New TemporaryId(post.Id, post.IsRead))
1621 Return rslt 'マーク付けは呼び出し元で行うこと
1625 Public Sub AddPostToInnerStorage(ByVal Post As PostClass)
1626 If _posts.ContainsKey(Post.Id) Then Exit Sub
1627 _posts.Add(Post.Id, Post)
1628 _tmpIds.Add(New TemporaryId(Post.Id, Post.IsRead))
1631 Public Sub AddSubmit(ByRef isMentionIncluded As Boolean)
1632 If _tmpIds.Count = 0 Then Exit Sub
1633 For Each tId As TemporaryId In _tmpIds
1634 If Me.TabType = TabUsageType.Mentions AndAlso TabInformations.GetInstance.Item(tId.Id).IsReply Then isMentionIncluded = True
1635 Me.Add(tId.Id, tId.Read)
1640 Public Sub AddSubmit()
1641 Dim mention As Boolean
1645 Public Sub Remove(ByVal Id As Long)
1646 If Not Me._ids.Contains(Id) Then Exit Sub
1648 If Me.IsInnerStorageTabType Then _posts.Remove(Id)
1651 Public Sub Remove(ByVal Id As Long, ByVal Read As Boolean)
1652 If Not Me._ids.Contains(Id) Then Exit Sub
1654 If Not Read AndAlso Me._unreadManage Then
1655 Me._unreadCount -= 1
1656 Me._oldestUnreadItem = -1
1660 If Me.IsInnerStorageTabType Then _posts.Remove(Id)
1663 Public Property UnreadManage() As Boolean
1665 Return _unreadManage
1667 Set(ByVal value As Boolean)
1668 Me._unreadManage = value
1670 Me._oldestUnreadItem = -1
1676 Public Property Notify() As Boolean
1680 Set(ByVal value As Boolean)
1685 Public Property SoundFile() As String
1689 Set(ByVal value As String)
1694 <Xml.Serialization.XmlIgnore()> _
1695 Public Property OldestUnreadId() As Long
1697 Return _oldestUnreadItem
1699 Set(ByVal value As Long)
1700 _oldestUnreadItem = value
1704 <Xml.Serialization.XmlIgnore()> _
1705 Public Property UnreadCount() As Integer
1709 Set(ByVal value As Integer)
1710 If value < 0 Then value = 0
1711 _unreadCount = value
1715 Public ReadOnly Property AllCount() As Integer
1717 Return Me._ids.Count
1721 Public Function GetFilters() As FiltersClass()
1722 SyncLock Me._lockObj
1723 Return _filters.ToArray()
1727 Public Sub RemoveFilter(ByVal filter As FiltersClass)
1728 SyncLock Me._lockObj
1729 _filters.Remove(filter)
1734 Public Function AddFilter(ByVal filter As FiltersClass) As Boolean
1735 SyncLock Me._lockObj
1736 If _filters.Contains(filter) Then Return False
1737 _filters.Add(filter)
1743 Public Sub EditFilter(ByVal original As FiltersClass, ByVal modified As FiltersClass)
1744 original.BodyFilter = modified.BodyFilter
1745 original.NameFilter = modified.NameFilter
1746 original.SearchBoth = modified.SearchBoth
1747 original.SearchUrl = modified.SearchUrl
1748 original.UseRegex = modified.UseRegex
1749 original.CaseSensitive = modified.CaseSensitive
1750 original.IsRt = modified.IsRt
1751 original.Source = modified.Source
1752 original.ExBodyFilter = modified.ExBodyFilter
1753 original.ExNameFilter = modified.ExNameFilter
1754 original.ExSearchBoth = modified.ExSearchBoth
1755 original.ExSearchUrl = modified.ExSearchUrl
1756 original.ExUseRegex = modified.ExUseRegex
1757 original.ExCaseSensitive = modified.ExCaseSensitive
1758 original.IsExRt = modified.IsExRt
1759 original.ExSource = modified.ExSource
1760 original.MoveFrom = modified.MoveFrom
1761 original.SetMark = modified.SetMark
1765 <Xml.Serialization.XmlIgnore()> _
1766 Public Property Filters() As List(Of FiltersClass)
1768 SyncLock Me._lockObj
1772 Set(ByVal value As List(Of FiltersClass))
1773 SyncLock Me._lockObj
1779 Public Property FilterArray() As FiltersClass()
1781 SyncLock Me._lockObj
1782 Return _filters.ToArray
1785 Set(ByVal value As FiltersClass())
1786 SyncLock Me._lockObj
1787 For Each filters As FiltersClass In value
1788 _filters.Add(filters)
1793 Public Function Contains(ByVal ID As Long) As Boolean
1794 Return _ids.Contains(ID)
1797 Public Sub ClearIDs()
1801 _oldestUnreadItem = -1
1802 If _posts IsNot Nothing Then
1807 Public Function GetId(ByVal Index As Integer) As Long
1811 Public Function IndexOf(ByVal ID As Long) As Integer
1812 Return _ids.IndexOf(ID)
1815 <Xml.Serialization.XmlIgnore()> _
1816 Public Property FilterModified() As Boolean
1820 Set(ByVal value As Boolean)
1825 Public Function BackupIds() As Long()
1826 Return _ids.ToArray()
1829 Public Property TabName() As String
1833 Set(ByVal value As String)
1838 Public Property TabType() As TabUsageType
1842 Set(ByVal value As TabUsageType)
1844 If Me.IsInnerStorageTabType Then
1845 _sorter.posts = _posts
1847 _sorter.posts = TabInformations.GetInstance.Posts
1852 Public ReadOnly Property IsInnerStorageTabType As Boolean
1854 If _tabType = TabUsageType.PublicSearch OrElse
1855 _tabType = TabUsageType.DirectMessage OrElse
1856 _tabType = TabUsageType.Lists OrElse
1857 _tabType = TabUsageType.Related Then
1867 Public NotInheritable Class FiltersClass
1868 Implements System.IEquatable(Of FiltersClass)
1869 Private _name As String = ""
1870 Private _body As New List(Of String)
1871 Private _searchBoth As Boolean = True
1872 Private _searchUrl As Boolean = False
1873 Private _caseSensitive As Boolean = False
1874 Private _useRegex As Boolean = False
1875 Private _isRt As Boolean = False
1876 Private _source As String = ""
1877 Private _exname As String = ""
1878 Private _exbody As New List(Of String)
1879 Private _exsearchBoth As Boolean = True
1880 Private _exsearchUrl As Boolean = False
1881 Private _exuseRegex As Boolean = False
1882 Private _excaseSensitive As Boolean = False
1883 Private _isExRt As Boolean = False
1884 Private _exSource As String = ""
1885 Private _moveFrom As Boolean = False
1886 Private _setMark As Boolean = True
1893 Private Function MakeSummary() As String
1894 Dim fs As New StringBuilder()
1895 If Not String.IsNullOrEmpty(_name) OrElse _body.Count > 0 OrElse _isRt OrElse Not String.IsNullOrEmpty(_source) Then
1897 If Not String.IsNullOrEmpty(_name) Then
1898 fs.AppendFormat(My.Resources.SetFiltersText1, _name)
1900 fs.Append(My.Resources.SetFiltersText2)
1903 If _body.Count > 0 Then
1904 fs.Append(My.Resources.SetFiltersText3)
1905 For Each bf As String In _body
1910 fs.Append(My.Resources.SetFiltersText4)
1914 fs.Append(My.Resources.SetFiltersText5)
1916 fs.Append(My.Resources.SetFiltersText6)
1919 fs.Append(My.Resources.SetFiltersText7)
1922 fs.Append(My.Resources.SetFiltersText8)
1924 If _caseSensitive Then
1925 fs.Append(My.Resources.SetFiltersText13)
1930 If Not String.IsNullOrEmpty(_source) Then
1931 fs.AppendFormat("Src…{0}/", _source)
1936 If Not String.IsNullOrEmpty(_exname) OrElse _exbody.Count > 0 OrElse _isExRt OrElse Not String.IsNullOrEmpty(_exSource) Then
1938 fs.Append(My.Resources.SetFiltersText12)
1939 If _exsearchBoth Then
1940 If Not String.IsNullOrEmpty(_exname) Then
1941 fs.AppendFormat(My.Resources.SetFiltersText1, _exname)
1943 fs.Append(My.Resources.SetFiltersText2)
1946 If _exbody.Count > 0 Then
1947 fs.Append(My.Resources.SetFiltersText3)
1948 For Each bf As String In _exbody
1953 fs.Append(My.Resources.SetFiltersText4)
1956 If _exsearchBoth Then
1957 fs.Append(My.Resources.SetFiltersText5)
1959 fs.Append(My.Resources.SetFiltersText6)
1962 fs.Append(My.Resources.SetFiltersText7)
1964 If _exsearchUrl Then
1965 fs.Append(My.Resources.SetFiltersText8)
1967 If _excaseSensitive Then
1968 fs.Append(My.Resources.SetFiltersText13)
1973 If Not String.IsNullOrEmpty(_exSource) Then
1974 fs.AppendFormat("Src…{0}/", _exSource)
1982 fs.Append(My.Resources.SetFiltersText9)
1984 fs.Append(My.Resources.SetFiltersText11)
1986 If Not _moveFrom AndAlso _setMark Then
1987 fs.Append(My.Resources.SetFiltersText10)
1988 ElseIf Not _moveFrom Then
1994 Return fs.ToString()
1997 Public Property NameFilter() As String
2001 Set(ByVal value As String)
2006 Public Property ExNameFilter() As String
2010 Set(ByVal value As String)
2015 <Xml.Serialization.XmlIgnore()> _
2016 Public Property BodyFilter() As List(Of String)
2020 Set(ByVal value As List(Of String))
2025 Public Property BodyFilterArray() As String()
2027 Return _body.ToArray
2029 Set(ByVal value As String())
2030 _body = New List(Of String)
2031 For Each filter As String In value
2037 <Xml.Serialization.XmlIgnore()> _
2038 Public Property ExBodyFilter() As List(Of String)
2042 Set(ByVal value As List(Of String))
2047 Public Property ExBodyFilterArray() As String()
2049 Return _exbody.ToArray
2051 Set(ByVal value As String())
2052 _exbody = New List(Of String)
2053 For Each filter As String In value
2059 Public Property SearchBoth() As Boolean
2063 Set(ByVal value As Boolean)
2068 Public Property ExSearchBoth() As Boolean
2070 Return _exsearchBoth
2072 Set(ByVal value As Boolean)
2073 _exsearchBoth = value
2077 Public Property MoveFrom() As Boolean
2081 Set(ByVal value As Boolean)
2086 Public Property SetMark() As Boolean
2090 Set(ByVal value As Boolean)
2095 Public Property SearchUrl() As Boolean
2099 Set(ByVal value As Boolean)
2104 Public Property ExSearchUrl() As Boolean
2108 Set(ByVal value As Boolean)
2109 _exsearchUrl = value
2113 Public Property CaseSensitive() As Boolean
2115 Return _caseSensitive
2117 Set(ByVal value As Boolean)
2118 _caseSensitive = value
2122 Public Property ExCaseSensitive() As Boolean
2124 Return _excaseSensitive
2126 Set(ByVal value As Boolean)
2127 _excaseSensitive = value
2131 Public Property UseRegex() As Boolean
2135 Set(ByVal value As Boolean)
2140 Public Property ExUseRegex() As Boolean
2144 Set(ByVal value As Boolean)
2149 Public Property IsRt() As Boolean
2153 Set(ByVal value As Boolean)
2158 Public Property IsExRt() As Boolean
2162 Set(ByVal value As Boolean)
2167 Public Property Source() As String
2171 Set(ByVal value As String)
2176 Public Property ExSource() As String
2180 Set(ByVal value As String)
2185 Public Overrides Function ToString() As String
2186 Return MakeSummary()
2189 Public Function IsHit(ByVal post As PostClass) As HITRESULT
2190 Dim bHit As Boolean = True
2192 Dim tSource As String
2194 tBody = post.OriginalData
2195 tSource = post.SourceHtml
2198 tSource = post.Source
2201 Dim compOpt As System.StringComparison
2202 Dim rgOpt As System.Text.RegularExpressions.RegexOptions
2203 If _caseSensitive Then
2204 compOpt = StringComparison.Ordinal
2205 rgOpt = RegexOptions.None
2207 compOpt = StringComparison.OrdinalIgnoreCase
2208 rgOpt = RegexOptions.IgnoreCase
2211 If String.IsNullOrEmpty(_name) OrElse
2212 (Not _useRegex AndAlso
2213 (post.Name.Equals(_name, compOpt) OrElse
2214 post.RetweetedBy.Equals(_name, compOpt)
2218 (Regex.IsMatch(post.Name, _name, rgOpt) OrElse
2219 (Not String.IsNullOrEmpty(post.RetweetedBy) AndAlso Regex.IsMatch(post.RetweetedBy, _name, rgOpt))
2222 For Each fs As String In _body
2224 If Not Regex.IsMatch(tBody, fs, rgOpt) Then bHit = False
2226 If _caseSensitive Then
2227 If Not tBody.Contains(fs) Then bHit = False
2229 If Not tBody.ToLower().Contains(fs.ToLower()) Then bHit = False
2232 If Not bHit Then Exit For
2238 For Each fs As String In _body
2240 If Not (Regex.IsMatch(post.Name, fs, rgOpt) OrElse
2241 (Not String.IsNullOrEmpty(post.RetweetedBy) AndAlso Regex.IsMatch(post.RetweetedBy, fs, rgOpt)) OrElse
2242 Regex.IsMatch(tBody, fs, rgOpt)) Then bHit = False
2244 If _caseSensitive Then
2245 If Not (post.Name.Contains(fs) OrElse _
2246 post.RetweetedBy.Contains(fs) OrElse _
2247 tBody.Contains(fs)) Then bHit = False
2249 If Not (post.Name.ToLower().Contains(fs.ToLower()) OrElse _
2250 post.RetweetedBy.ToLower().Contains(fs.ToLower()) OrElse _
2251 tBody.ToLower().Contains(fs.ToLower())) Then bHit = False
2254 If Not bHit Then Exit For
2258 If post.RetweetedId = 0 Then bHit = False
2260 If Not String.IsNullOrEmpty(_source) Then
2262 If Not Regex.IsMatch(tSource, _source, rgOpt) Then bHit = False
2264 If Not tSource.Equals(_source, compOpt) Then bHit = False
2269 If _exsearchUrl Then
2270 tBody = post.OriginalData
2271 tSource = post.SourceHtml
2274 tSource = post.Source
2277 Dim exFlag As Boolean = False
2278 If Not String.IsNullOrEmpty(_exname) OrElse _exbody.Count > 0 Then
2279 If _excaseSensitive Then
2280 compOpt = StringComparison.Ordinal
2281 rgOpt = RegexOptions.None
2283 compOpt = StringComparison.OrdinalIgnoreCase
2284 rgOpt = RegexOptions.IgnoreCase
2286 If _exsearchBoth Then
2287 If String.IsNullOrEmpty(_exname) OrElse
2288 (Not _exuseRegex AndAlso
2289 (post.Name.Equals(_exname, compOpt) OrElse
2290 post.RetweetedBy.Equals(_exname, compOpt)
2293 (_exuseRegex AndAlso _
2294 (Regex.IsMatch(post.Name, _exname, rgOpt) OrElse _
2295 (Not String.IsNullOrEmpty(post.RetweetedBy) AndAlso Regex.IsMatch(post.RetweetedBy, _exname, rgOpt))
2298 If _exbody.Count > 0 Then
2299 For Each fs As String In _exbody
2301 If Regex.IsMatch(tBody, fs, rgOpt) Then exFlag = True
2303 If _excaseSensitive Then
2304 If tBody.Contains(fs) Then exFlag = True
2306 If tBody.ToLower().Contains(fs.ToLower()) Then exFlag = True
2309 If exFlag Then Exit For
2316 For Each fs As String In _exbody
2318 If Regex.IsMatch(post.Name, fs, rgOpt) OrElse
2319 (Not String.IsNullOrEmpty(post.RetweetedBy) AndAlso Regex.IsMatch(post.RetweetedBy, fs, rgOpt)) OrElse
2320 Regex.IsMatch(tBody, fs, rgOpt) Then exFlag = True
2322 If _excaseSensitive Then
2323 If post.Name.Contains(fs) OrElse _
2324 post.RetweetedBy.Contains(fs) OrElse _
2325 tBody.Contains(fs) Then exFlag = True
2327 If post.Name.ToLower().Contains(fs.ToLower()) OrElse _
2328 post.RetweetedBy.ToLower().Contains(fs.ToLower()) OrElse _
2329 tBody.ToLower().Contains(fs.ToLower()) Then exFlag = True
2332 If exFlag Then Exit For
2337 If post.RetweetedId > 0 Then exFlag = True
2339 If Not String.IsNullOrEmpty(_exSource) Then
2341 If Regex.IsMatch(tSource, _exSource, rgOpt) Then exFlag = True
2343 If tSource.Equals(_exSource, compOpt) Then exFlag = True
2347 If String.IsNullOrEmpty(_name) AndAlso _body.Count = 0 AndAlso Not _isRt AndAlso String.IsNullOrEmpty(_source) Then
2353 Return HITRESULT.Move
2356 Return HITRESULT.CopyAndMark
2358 Return HITRESULT.Copy
2361 Return HITRESULT.Exclude
2365 Return HITRESULT.Exclude
2367 Return HITRESULT.None
2371 Return HITRESULT.None
2375 Public Overloads Function Equals(ByVal other As FiltersClass) As Boolean _
2376 Implements System.IEquatable(Of Tween.FiltersClass).Equals
2378 If Me.BodyFilter.Count <> other.BodyFilter.Count Then Return False
2379 If Me.ExBodyFilter.Count <> other.ExBodyFilter.Count Then Return False
2380 For i As Integer = 0 To Me.BodyFilter.Count - 1
2381 If Me.BodyFilter(i) <> other.BodyFilter(i) Then Return False
2383 For i As Integer = 0 To Me.ExBodyFilter.Count - 1
2384 If Me.ExBodyFilter(i) <> other.ExBodyFilter(i) Then Return False
2387 Return (Me.MoveFrom = other.MoveFrom) And _
2388 (Me.SetMark = other.SetMark) And _
2389 (Me.NameFilter = other.NameFilter) And _
2390 (Me.SearchBoth = other.SearchBoth) And _
2391 (Me.SearchUrl = other.SearchUrl) And _
2392 (Me.UseRegex = other.UseRegex) And _
2393 (Me.ExNameFilter = other.ExNameFilter) And _
2394 (Me.ExSearchBoth = other.ExSearchBoth) And _
2395 (Me.ExSearchUrl = other.ExSearchUrl) And _
2396 (Me.ExUseRegex = other.ExUseRegex) And _
2397 (Me.IsRt = other.IsRt) And _
2398 (Me.Source = other.Source) And _
2399 (Me.IsExRt = other.IsExRt) And _
2400 (Me.ExSource = other.ExSource)
2403 Public Function CopyTo(ByVal destination As FiltersClass) As FiltersClass
2405 If Me.BodyFilter.Count > 0 Then
2406 For Each flt As String In Me.BodyFilter
2407 destination.BodyFilter.Add(String.Copy(flt))
2411 If Me.ExBodyFilter.Count > 0 Then
2412 For Each flt As String In Me.ExBodyFilter
2413 destination.ExBodyFilter.Add(String.Copy(flt))
2417 destination.MoveFrom = Me.MoveFrom
2418 destination.SetMark = Me.SetMark
2419 destination.NameFilter = Me.NameFilter
2420 destination.SearchBoth = Me.SearchBoth
2421 destination.SearchUrl = Me.SearchUrl
2422 destination.UseRegex = Me.UseRegex
2423 destination.ExNameFilter = Me.ExNameFilter
2424 destination.ExSearchBoth = Me.ExSearchBoth
2425 destination.ExSearchUrl = Me.ExSearchUrl
2426 destination.ExUseRegex = Me.ExUseRegex
2427 destination.IsRt = Me.IsRt
2428 destination.Source = Me.Source
2429 destination.IsExRt = Me.IsExRt
2430 destination.ExSource = Me.ExSource
2434 Public Overrides Function Equals(ByVal obj As Object) As Boolean
2435 If (obj Is Nothing) OrElse Not (Me.GetType() Is obj.GetType()) Then Return False
2436 Return Me.Equals(CType(obj, FiltersClass))
2439 Public Overrides Function GetHashCode() As Integer
2440 Return Me.MoveFrom.GetHashCode Xor _
2441 Me.SetMark.GetHashCode Xor _
2442 Me.BodyFilter.GetHashCode Xor _
2443 Me.NameFilter.GetHashCode Xor _
2444 Me.SearchBoth.GetHashCode Xor _
2445 Me.SearchUrl.GetHashCode Xor _
2446 Me.UseRegex.GetHashCode Xor _
2447 Me.ExBodyFilter.GetHashCode Xor _
2448 Me.ExNameFilter.GetHashCode Xor _
2449 Me.ExSearchBoth.GetHashCode Xor _
2450 Me.ExSearchUrl.GetHashCode Xor _
2451 Me.ExUseRegex.GetHashCode Xor _
2452 Me.IsRt.GetHashCode Xor _
2453 Me.Source.GetHashCode Xor _
2454 Me.IsExRt.GetHashCode Xor _
2455 Me.ExSource.GetHashCode
2460 Public NotInheritable Class IdComparerClass
2461 Implements IComparer(Of Long)
2466 Public Enum ComparerMode
2474 Private _order As SortOrder
2475 Private _mode As ComparerMode
2476 Private _statuses As Dictionary(Of Long, PostClass)
2477 Private _CmpMethod As Comparison(Of Long)
2480 ''' 昇順か降順か Setの際は同時に比較関数の切り替えを行う
2482 Public Property Order() As SortOrder
2486 Set(ByVal Value As SortOrder)
2488 SetCmpMethod(_mode, _order)
2493 ''' 並び替えの方法 Setの際は同時に比較関数の切り替えを行う
2495 Public Property Mode() As ComparerMode
2499 Set(ByVal Value As ComparerMode)
2501 SetCmpMethod(_mode, _order)
2506 ''' ListViewItemComparerクラスのコンストラクタ(引数付は未使用)
2508 ''' <param name="col">並び替える列番号</param>
2509 ''' <param name="ord">昇順か降順か</param>
2510 ''' <param name="cmod">並び替えの方法</param>
2513 _order = SortOrder.Ascending
2514 _mode = ComparerMode.Id
2515 SetCmpMethod(_mode, _order)
2518 Public WriteOnly Property posts() As Dictionary(Of Long, PostClass)
2519 Set(ByVal value As Dictionary(Of Long, PostClass))
2524 ' 指定したソートモードとソートオーダーに従い使用する比較関数のアドレスを返す
2525 Public Overloads ReadOnly Property CmpMethod(ByVal _sortmode As ComparerMode, ByVal _sortorder As SortOrder) As Comparison(Of Long)
2527 Dim _method As Comparison(Of Long) = Nothing
2528 If _sortorder = SortOrder.Ascending Then
2530 Select Case _sortmode
2531 Case ComparerMode.Data
2532 _method = AddressOf Compare_ModeData_Ascending
2533 Case ComparerMode.Id
2534 _method = AddressOf Compare_ModeId_Ascending
2535 Case ComparerMode.Name
2536 _method = AddressOf Compare_ModeName_Ascending
2537 Case ComparerMode.Nickname
2538 _method = AddressOf Compare_ModeNickName_Ascending
2539 Case ComparerMode.Source
2540 _method = AddressOf Compare_ModeSource_Ascending
2544 Select Case _sortmode
2545 Case ComparerMode.Data
2546 _method = AddressOf Compare_ModeData_Descending
2547 Case ComparerMode.Id
2548 _method = AddressOf Compare_ModeId_Descending
2549 Case ComparerMode.Name
2550 _method = AddressOf Compare_ModeName_Descending
2551 Case ComparerMode.Nickname
2552 _method = AddressOf Compare_ModeNickName_Descending
2553 Case ComparerMode.Source
2554 _method = AddressOf Compare_ModeSource_Descending
2561 ' ソートモードとソートオーダーに従い使用する比較関数のアドレスを返す
2562 ' (overload 現在の使用中の比較関数のアドレスを返す)
2563 Public Overloads ReadOnly Property CmpMethod() As Comparison(Of Long)
2569 ' ソートモードとソートオーダーに従い比較関数のアドレスを切り替え
2570 Private Sub SetCmpMethod(ByVal mode As ComparerMode, ByVal order As SortOrder)
2571 _CmpMethod = Me.CmpMethod(mode, order)
2574 'xがyより小さいときはマイナスの数、大きいときはプラスの数、
2575 '同じときは0を返す (こちらは未使用 一応比較関数群呼び出しの形のまま残しておく)
2576 Public Function Compare(ByVal x As Long, ByVal y As Long) _
2577 As Integer Implements IComparer(Of Long).Compare
2578 Return _CmpMethod(x, y)
2581 ' 比較用関数群 いずれもステータスIDの順序を考慮する
2583 Public Function Compare_ModeData_Ascending(ByVal x As Long, ByVal y As Long) As Integer
2584 Dim result As Integer = String.Compare(_statuses.Item(x).Data, _statuses.Item(y).Data)
2585 If result = 0 Then result = x.CompareTo(y)
2590 Public Function Compare_ModeData_Descending(ByVal x As Long, ByVal y As Long) As Integer
2591 Dim result As Integer = String.Compare(_statuses.Item(y).Data, _statuses.Item(x).Data)
2592 If result = 0 Then result = y.CompareTo(x)
2597 Public Function Compare_ModeId_Ascending(ByVal x As Long, ByVal y As Long) As Integer
2598 Return x.CompareTo(y)
2602 Public Function Compare_ModeId_Descending(ByVal x As Long, ByVal y As Long) As Integer
2603 Return y.CompareTo(x)
2607 Public Function Compare_ModeName_Ascending(ByVal x As Long, ByVal y As Long) As Integer
2608 Dim result As Integer = String.Compare(_statuses.Item(x).Name, _statuses.Item(y).Name)
2609 If result = 0 Then result = x.CompareTo(y)
2614 Public Function Compare_ModeName_Descending(ByVal x As Long, ByVal y As Long) As Integer
2615 Dim result As Integer = String.Compare(_statuses.Item(y).Name, _statuses.Item(x).Name)
2616 If result = 0 Then result = y.CompareTo(x)
2621 Public Function Compare_ModeNickName_Ascending(ByVal x As Long, ByVal y As Long) As Integer
2622 Dim result As Integer = String.Compare(_statuses.Item(x).Nickname, _statuses.Item(y).Nickname)
2623 If result = 0 Then result = x.CompareTo(y)
2628 Public Function Compare_ModeNickName_Descending(ByVal x As Long, ByVal y As Long) As Integer
2629 Dim result As Integer = String.Compare(_statuses.Item(y).Nickname, _statuses.Item(x).Nickname)
2630 If result = 0 Then result = y.CompareTo(x)
2635 Public Function Compare_ModeSource_Ascending(ByVal x As Long, ByVal y As Long) As Integer
2636 Dim result As Integer = String.Compare(_statuses.Item(x).Source, _statuses.Item(y).Source)
2637 If result = 0 Then result = x.CompareTo(y)
2642 Public Function Compare_ModeSource_Descending(ByVal x As Long, ByVal y As Long) As Integer
2643 Dim result As Integer = String.Compare(_statuses.Item(y).Source, _statuses.Item(x).Source)
2644 If result = 0 Then result = y.CompareTo(x)