/// /// Copyright © 2003-2008 JetBrains s.r.o. /// You may distribute under the terms of the GNU General Public License, as published by the Free Software Foundation, version 2 (see License.txt in the repository root folder). /// using System; using JetBrains.Omea.Base; using JetBrains.Omea.Containers; using JetBrains.Omea.Diagnostics; using JetBrains.Omea.FiltersManagement; using JetBrains.Omea.OpenAPI; namespace JetBrains.Omea.RSSPlugin { public class RSSDataUpgrade : IViewsConstructor { public void RegisterViewsFirstRun() { int percent = 0; const string Message = "Upgrading RSS Feeds Database"; IResourceList allItems = Core.ResourceStore.GetAllResources( Props.RSSItemResource ); if( Core.ProgressWindow != null ) Core.ProgressWindow.UpdateProgress( 0, Message, null ); for( int i = 0; i < allItems.Count; i++ ) { allItems[ i ].DeleteProp( Props.Author ); if( Core.ProgressWindow != null ) { int newPercent = i * 100 / allItems.Count; if( newPercent != percent ) { percent = newPercent; if( Core.ProgressWindow != null ) Core.ProgressWindow.UpdateProgress( percent, Message, null ); } } } if( Core.ProgressWindow != null ) Core.ProgressWindow.UpdateProgress( 100, Message, null ); } public void RegisterViewsEachRun() {} } public class RSSDataUpgrade2 : IViewsConstructor { public void RegisterViewsFirstRun() { int percent = 0; const string Message = "Upgrading RSS Feeds Links"; IResourceList allItems = Core.ResourceStore.FindResourcesWithProp( Props.RSSItemResource, Core.Props.Reply ); if( Core.ProgressWindow != null ) Core.ProgressWindow.UpdateProgress( 0, Message, null ); // Substitute "Reply" links between feed items with a more semantic-neutral // "LinkedPost" link. This also removes "Reply" link from the pointless // Link Pane and adds necessary anchors directly into the feed post // representation. for( int i = 0; i < allItems.Count; i++ ) { IResourceList linked = allItems[ i ].GetLinksFrom( Props.RSSItemResource, Core.Props.Reply ); allItems[ i ].DeleteLinks( Core.Props.Reply ); foreach( IResource res in linked ) allItems[ i ].AddLink( Props.LinkedPost, res ); if( Core.ProgressWindow != null ) { int newPercent = i * 100 / allItems.Count; if( newPercent != percent ) { percent = newPercent; if( Core.ProgressWindow != null ) Core.ProgressWindow.UpdateProgress( percent, Message, null ); } } } if( Core.ProgressWindow != null ) Core.ProgressWindow.UpdateProgress( 100, Message, null ); } public void RegisterViewsEachRun() {} } public class RSSViewsConstructor : IViewsConstructor { public const string RSSConditionsGroup = "RSS Conditions"; public const string AuthorWrotePostName = "Author wrote an rss post"; public const string AuthorWrotePostDeep = "wrotepost"; public const string AuthorHasFeedName = "Author has an rss feed"; public const string AuthorHasFeedDeep = "hasfeed"; public const string PostHasEnclosuredName = "Post has enclosure"; public const string PostHasEnclosuredDeep = "hasenclosure"; public const string PostHasCommentName = "Post has comment(s)"; public const string PostHasCommentDeep = "hascomment"; public const string PostIsACommentName = "Post is a comment"; public const string PostIsACommentDeep = "postiscomment"; public const string PostIsAuthorsCommentName = "Post is a comment from blog author"; public const string PostIsAuthorsCommentDeep = "postisauthorcomment"; public const string DownloadFailedName = "Enclosure downloading is failed"; public const string DownloadFailedDeep = "encfailed"; public const string DownloadCompletedName = "Enclosure downloading is completed"; public const string DownloadCompletedDeep = "enccompleted"; public const string DownloadNotName = "Enclosure is not downloaded"; public const string DownloadNotDeep = "notdownloaded"; public const string DownloadPlannedName = "Enclosure downloading is planned"; public const string DownloadPlannedDeep = "encplanned"; public const string PostInFeedName = "Post is in %feed%"; public const string PostInFeedDeep = "postinfeed"; public const string FeedInFolderName = "Post's feed is in the %folder%"; public const string FeedInFolderDeep = "FeedInFolder"; public const string PostInSearchFeedName = "Post is in the search feed"; public const string PostInSearchFeedDeep = "postinsearchfeed"; public const string PostInCategoryName = "Post in %publisher's category%"; public const string PostInCategoryDeep = "postincategory"; public const string EnclosureSizeName = "Enclosure size is %in range% (in bytes)"; public const string EnclosureSizeDeep = "encsize"; public const string EnclosureTypeName = "Enclosure is of %specified% type"; public const string EnclosureTypeDeep = "enctype"; public const string DownloadEnclosureName = "Download enclosures"; public const string DownloadEnclosureDeep = "downloadenclosure"; public const string DownloadEnclosureToName = "Download enclosures to %folder%"; public const string DownloadEnclosureToDeep = "downloadenclosureto"; #region IViewsConstructor Members /// /// Method is called when a plugin that implements this interface is loaded first time. /// public void RegisterViewsFirstRun() { IResource res; string[] applType = new string[] { "RSSItem" }, contactType = new string[] {"Contact"}; IFilterRegistry fMgr = Core.FilterRegistry; IResource myResType = Core.ResourceStore.FindUniqueResource( "ResourceType", "Name", "RSSItem" ); res = fMgr.CreateStandardCondition( AuthorWrotePostName, AuthorWrotePostDeep, contactType, "LinkedResourcesOfType", ConditionOp.In, myResType.ToResourceList() ); fMgr.AssociateConditionWithGroup( res, "Address and Contact Conditions" ); res = fMgr.CreateStandardCondition( AuthorHasFeedName, AuthorHasFeedDeep, contactType, "Weblog", ConditionOp.HasLink ); fMgr.AssociateConditionWithGroup( res, "Address and Contact Conditions" ); res = fMgr.CreateStandardCondition( PostHasEnclosuredName, PostHasEnclosuredDeep, applType, "EnclosureURL", ConditionOp.HasProp ); fMgr.AssociateConditionWithGroup( res, RSSConditionsGroup ); res = fMgr.CreateStandardCondition( PostHasCommentName, PostHasCommentDeep, applType, "CommentCount", ConditionOp.Gt, "0" ); fMgr.AssociateConditionWithGroup( res, RSSConditionsGroup ); res = fMgr.CreateStandardCondition( PostIsACommentName, PostIsACommentDeep, applType, "FeedComment", ConditionOp.HasLink ); fMgr.AssociateConditionWithGroup( res, RSSConditionsGroup ); res = fMgr.CreateStandardCondition( DownloadFailedName, DownloadFailedDeep, applType, "EnclosureDownloadingState", ConditionOp.In, "3" ); fMgr.RenameCondition( "Enclosure downloading failed", "Enclosure downloading is failed" ); fMgr.AssociateConditionWithGroup( res, RSSConditionsGroup ); res = fMgr.CreateStandardCondition( DownloadCompletedName, DownloadCompletedDeep, applType, "EnclosureDownloadingState", ConditionOp.In, "2" ); fMgr.RenameCondition( "Enclosure downloading completed", "Enclosure downloading is completed" ); fMgr.AssociateConditionWithGroup( res, RSSConditionsGroup ); res = fMgr.CreateStandardCondition( DownloadNotName, DownloadNotDeep, applType, "EnclosureDownloadingState", ConditionOp.In, "0" ); fMgr.RenameCondition( "Enclosure not downloaded", "Enclosure is not downloaded" ); fMgr.AssociateConditionWithGroup( res, RSSConditionsGroup ); res = fMgr.CreateStandardCondition( DownloadPlannedName, DownloadPlannedDeep, applType, "EnclosureDownloadingState", ConditionOp.In, "1", "4" ); fMgr.RenameCondition( "Enclosure downloading planned", "Enclosure downloading is planned" ); fMgr.AssociateConditionWithGroup( res, RSSConditionsGroup ); res = fMgr.CreateConditionTemplate( EnclosureSizeName, EnclosureSizeDeep, applType, ConditionOp.InRange, "EnclosureSize", "0", Int32.MaxValue.ToString() ); fMgr.AssociateConditionWithGroup( res, RSSConditionsGroup ); res = fMgr.CreateConditionTemplate( EnclosureTypeName, EnclosureTypeDeep, applType, ConditionOp.Eq, "EnclosureType" ); fMgr.AssociateConditionWithGroup( res, RSSConditionsGroup ); } /// /// Method is called when a plugin that implements this interface is loaded. /// Usually this method contains code which creates rule actions and performs /// corrections to the resources created during the first start of the plugin. /// public void RegisterViewsEachRun() { string[] applType = new string[] { "RSSItem" }; IFilterRegistry fMgr = Core.FilterRegistry; INotificationManager notifMgr = Core.NotificationManager; notifMgr.RegisterNotifyMeResourceType( "RSSFeed", "RSSItem" ); notifMgr.RegisterNotifyMeResourceType( "RSSItem", "RSSItem" ); // Conditions/Templates IResource feedCondition = fMgr.CreateConditionTemplate( PostInFeedName, PostInFeedDeep, applType, ConditionOp.In, "RSSFeed", "RSSItem" ); fMgr.AssociateConditionWithGroup( feedCondition, RSSConditionsGroup ); notifMgr.RegisterNotifyMeCondition( "RSSFeed", feedCondition, 0 ); notifMgr.RegisterNotifyMeCondition( "RSSItem", feedCondition, -Props.RSSItem ); feedCondition = fMgr.RegisterCustomCondition( PostInSearchFeedName, PostInSearchFeedDeep, applType, new PostInSearchFeedCondition() ); fMgr.AssociateConditionWithGroup( feedCondition, RSSConditionsGroup ); feedCondition = fMgr.RegisterCustomCondition( PostIsAuthorsCommentName, PostIsAuthorsCommentDeep, applType, new PostIsAuthorsCommentCondition() ); fMgr.AssociateConditionWithGroup( feedCondition, RSSConditionsGroup ); // Rule Actions Core.FilterEngine.RegisterRuleApplicableResourceType( "RSSItem" ); fMgr.RegisterRuleAction( DownloadEnclosureName, DownloadEnclosureDeep, new EnclosureDownloadRuleAction(), applType ); fMgr.RegisterRuleActionTemplate( DownloadEnclosureToName, DownloadEnclosureToDeep, new EnclosureDownloadToDirRuleActionTemplate(), applType, ConditionOp.In, "ExternalDir" ); } #endregion } public class RSSUgrade1ViewsConstructor : IViewsConstructor { #region IViewsConstructor Members public void RegisterViewsFirstRun() { IResource res; string[] applType = new string[] { "RSSItem" }; IFilterRegistry fMgr = Core.FilterRegistry; //----------------------------------------------------------------- // All conditions, templates and actions must have their deep names //----------------------------------------------------------------- res = Core.ResourceStore.FindUniqueResource( FilterManagerProps.ConditionResName, "Name", RSSViewsConstructor.AuthorWrotePostName ); if( res != null ) res.SetProp( "DeepName", RSSViewsConstructor.AuthorWrotePostDeep ); res = Core.ResourceStore.FindUniqueResource( FilterManagerProps.ConditionResName, "Name", RSSViewsConstructor.AuthorHasFeedName ); if( res != null ) res.SetProp( "DeepName", RSSViewsConstructor.AuthorHasFeedDeep ); res = Core.ResourceStore.FindUniqueResource( FilterManagerProps.ConditionResName, "Name", RSSViewsConstructor.PostHasEnclosuredName ); if( res != null ) res.SetProp( "DeepName", RSSViewsConstructor.PostHasEnclosuredDeep ); res = Core.ResourceStore.FindUniqueResource( FilterManagerProps.ConditionResName, "Name", RSSViewsConstructor.PostHasCommentName ); if( res != null ) res.SetProp( "DeepName", RSSViewsConstructor.PostHasCommentDeep ); res = Core.ResourceStore.FindUniqueResource( FilterManagerProps.ConditionResName, "Name", RSSViewsConstructor.DownloadFailedName ); if( res != null ) res.SetProp( "DeepName", RSSViewsConstructor.DownloadFailedDeep ); res = Core.ResourceStore.FindUniqueResource( FilterManagerProps.ConditionResName, "Name", RSSViewsConstructor.DownloadCompletedName ); if( res != null ) res.SetProp( "DeepName", RSSViewsConstructor.DownloadCompletedDeep ); res = Core.ResourceStore.FindUniqueResource( FilterManagerProps.ConditionResName, "Name", RSSViewsConstructor.DownloadNotName ); if( res != null ) res.SetProp( "DeepName", RSSViewsConstructor.DownloadNotDeep ); res = Core.ResourceStore.FindUniqueResource( FilterManagerProps.ConditionResName, "Name", RSSViewsConstructor.DownloadPlannedName ); if( res != null ) res.SetProp( "DeepName", RSSViewsConstructor.DownloadPlannedDeep ); res = Core.ResourceStore.FindUniqueResource( FilterManagerProps.ConditionTemplateResName, "Name", RSSViewsConstructor.PostInFeedName ); if( res != null ) res.SetProp( "DeepName", RSSViewsConstructor.PostInFeedDeep ); res = Core.ResourceStore.FindUniqueResource( FilterManagerProps.ConditionTemplateResName, "Name", RSSViewsConstructor.PostInCategoryName ); if( res != null ) res.SetProp( "DeepName", RSSViewsConstructor.PostInCategoryDeep ); res = Core.ResourceStore.FindUniqueResource( FilterManagerProps.ConditionTemplateResName, "Name", RSSViewsConstructor.EnclosureSizeName ); if( res != null ) res.SetProp( "DeepName", RSSViewsConstructor.EnclosureSizeDeep ); res = Core.ResourceStore.FindUniqueResource( FilterManagerProps.ConditionTemplateResName, "Name", RSSViewsConstructor.EnclosureTypeName ); if( res != null ) res.SetProp( "DeepName", RSSViewsConstructor.EnclosureTypeDeep ); res = Core.ResourceStore.FindUniqueResource( FilterManagerProps.RuleActionResName, "Name", RSSViewsConstructor.DownloadEnclosureName ); if( res != null ) res.SetProp( "DeepName", RSSViewsConstructor.DownloadEnclosureDeep ); // Tray Icon Rules and Notifications Core.TrayIconManager.RegisterTrayIconRule( "Unread RSS/ATOM Posts", applType, new IResource[] { fMgr.Std.ResourceIsUnread }, null, RSSPlugin.LoadIconFromAssembly( "RSSItemUnread.ico" ) ); } public void RegisterViewsEachRun() {} #endregion } public class RSSUgrade2ViewsConstructor : IViewsConstructor { public void RegisterViewsFirstRun() { IResourceList list = Core.ResourceStore.FindResources( FilterManagerProps.ConditionTemplateResName, "Name", RSSViewsConstructor.PostInCategoryName ); IResource one = Core.ResourceStore.FindUniqueResource( FilterManagerProps.ConditionTemplateResName, "DeepName", RSSViewsConstructor.PostInCategoryName ); if( one != null ) { list = list.Minus( one.ToResourceList() ); list.DeleteAll(); one.SetProp( "DeepName", RSSViewsConstructor.PostInCategoryDeep ); } else { IFilterRegistry mgr = Core.FilterRegistry; IResource res = mgr.CreateConditionTemplate( RSSViewsConstructor.PostInCategoryName, RSSViewsConstructor.PostInCategoryDeep, new string[] {"RSSItem"}, ConditionOp.Eq, "RSSCategory" ); mgr.AssociateConditionWithGroup( res, RSSViewsConstructor.RSSConditionsGroup ); } } public void RegisterViewsEachRun() {} } public class RSSUgrade3ViewsConstructor : IViewsConstructor { public void RegisterViewsFirstRun() { IFilterRegistry mgr = Core.FilterRegistry; IResource res = mgr.CreateStandardCondition( RSSViewsConstructor.PostIsACommentName, RSSViewsConstructor.PostIsACommentDeep, new string[] {"RSSItem"}, "FeedComment", ConditionOp.HasLink ); mgr.AssociateConditionWithGroup( res, RSSViewsConstructor.RSSConditionsGroup ); } public void RegisterViewsEachRun() { IFilterRegistry fMgr = Core.FilterRegistry; IResource res = fMgr.CreateConditionTemplate( RSSViewsConstructor.FeedInFolderName, RSSViewsConstructor.FeedInFolderDeep, null, ConditionOp.In, Props.RSSFeedGroupResource, "RssItem>Parent" ); fMgr.AssociateConditionWithGroup( res, RSSViewsConstructor.RSSConditionsGroup ); } } #region Rule Conditions/Actions public class PostInSearchFeedCondition : ICustomCondition { public bool MatchResource( IResource res ) { IResource feed = res.GetLinksTo( Props.RSSFeedResource, Props.RSSItem )[ 0 ]; return feed.HasProp( Props.RSSSearchPhrase ); } public IResourceList Filter( string resType ) { IResourceList posts = Core.ResourceStore.EmptyResourceList; // FindResourcesWithProps does not support LongString type for prop, // thus we have to iterate over the whole feeds list. foreach( IResource feed in Core.ResourceStore.GetAllResources( Props.RSSFeedResource ) ) { if( feed.HasProp( Props.RSSSearchPhrase )) { posts = posts.Union( feed.GetLinksOfType( null, Props.RSSItem ), true ); } } return posts; } } public class PostIsAuthorsCommentCondition : ICustomCondition { public bool MatchResource( IResource res ) { IResource parent = res.GetLinkProp( Props.ItemComment ); if( parent != null ) { IResource c1 = parent.GetLinkProp( Core.ContactManager.Props.LinkFrom ); IResource c2 = res.GetLinkProp( Core.ContactManager.Props.LinkFrom ); return ( c1 != null && c2 != null && c1.Id == c2.Id ); } return false; } public IResourceList Filter( string resType ) { int fromId = Core.ContactManager.Props.LinkFrom; IntArrayList list = new IntArrayList(); IResourceList comments = Core.ResourceStore.FindResourcesWithProp( Props.RSSFeedResource, Props.ItemComment ); IResourceList authors = Core.ResourceStore.FindResourcesWithProp( "Contact", Props.Weblog ); foreach( IResource comment in comments ) { IResource contact = comment.GetLinkProp( fromId ); if( contact != null && authors.Contains( contact ) ) { list.Add( comment.Id ); } } return Core.ResourceStore.ListFromIds( list, false ); } } public class EnclosureDownloadRuleAction : IRuleAction { public void Exec( IResource res, IActionParameterStore actionStore ) { Guard.NullArgument( res, "res" ); Guard.NullArgument( actionStore, "actionStore" ); if ( res.Type != "RSSItem" ) { throw new ArgumentException( "EnclosureDownloadRuleAction was registered for RSSItem only but there resource with type = '" + res.Type + "'" ); } Tracer._Trace( "Execute rule: EnclosureDownloadRuleAction" ); if ( res.HasProp( Props.EnclosureURL ) ) { EnclosureDownloadManager.PlanToDownload( res ); } } } public class EnclosureDownloadToDirRuleActionTemplate : IRuleAction { public void Exec( IResource res, IActionParameterStore actionStore ) { Guard.NullArgument( res, "res" ); Guard.NullArgument( actionStore, "actionStore" ); if ( res.Type != "RSSItem" ) { throw new ArgumentException( "EnclosureDownloadRuleAction was registered for RSSItem only but there resource with type = '" + res.Type + "'" ); } Tracer._Trace( "Execute rule: EnclosureDownloadRuleAction" ); if ( res.HasProp( Props.EnclosureURL ) ) { string folder = actionStore.ParameterAsString(); EnclosureDownloadManager.PlanToDownload( res, folder ); } } } #endregion Rule Conditions/Actions }