" );
RSSPlugin.RSSTreePane.EditResourceLabel( newGroup );
}
public override void Update( IActionContext context, ref ActionPresentation presentation )
{
if( context.SelectedResources.Count != 1 ||
context.SelectedResources[ 0 ].Type != Props.RSSFeedResource )
{
base.Update( context, ref presentation );
}
}
}
public class MoveFeed2FolderAction : IAction
{
public void Execute( IActionContext context )
{
IResourceList list = context.SelectedResources;
SelectFeedFolderForm form = new SelectFeedFolderForm( list );
if( form.ShowDialog( Core.MainWindow ) == DialogResult.OK )
{
IResource folder = form.SelectedFolder;
if( folder != null )
{
foreach( IResource feedOrFolder in list )
{
new ResourceProxy( feedOrFolder ).SetProp( Core.Props.Parent, folder );
}
}
}
}
public void Update( IActionContext context, ref ActionPresentation presentation )
{
presentation.Visible = (context.SelectedResources.Count > 0);
}
}
#endregion Feed Groups
///
/// Action for sending an RSS item by email.
///
public class SendEmailAction : SimpleAction
{
private bool _haveEmailService;
private IEmailService _emailService;
public override void Execute( IActionContext context )
{
if ( context.SelectedResources.Count == 0 )
{
return;
}
InitializeEmailService();
if ( _emailService != null )
{
IResource firstItem = context.SelectedResources[ 0 ];
string subject = firstItem.GetPropText( Core.Props.Subject );
StringBuilder html = StringBuilderPool.Alloc();
try
{
foreach ( IResource selItem in context.SelectedResources )
{
html.Append( selItem.GetPropText( Core.Props.LongBody ) );
if ( selItem.HasProp( Props.Link ) )
{
html.Append( "" +
selItem.GetStringProp( Props.Link ) + "
" );
}
}
if ( context.SelectedResources.Count > 1 )
{
subject += " ( and " + ( context.SelectedResources.Count - 1 ) + " more items ) ";
}
_emailService.CreateEmail( "FW: " + subject, html.ToString(),
EmailBodyFormat.Html, Core.ResourceStore.EmptyResourceList, new string[] {}, false );
}
finally
{
StringBuilderPool.Dispose( html );
}
}
}
public override void Update( IActionContext context, ref ActionPresentation presentation )
{
InitializeEmailService();
base.Update( context, ref presentation );
presentation.Enabled = ( _emailService != null );
}
private void InitializeEmailService()
{
if ( !_haveEmailService )
{
_emailService = (IEmailService)Core.PluginLoader.GetPluginService( typeof (IEmailService) );
_haveEmailService = true;
}
}
}
public class FilterUnreadFeedsAction : IAction
{
public void Execute( IActionContext context )
{
bool val = Core.SettingStore.ReadBool( IniKeys.Section, IniKeys.FilterUnreadFeeds, false );
Core.SettingStore.WriteBool( IniKeys.Section, IniKeys.FilterUnreadFeeds, !val );
RSSPlugin.UpdateUnreadPaneFilter( !val );
}
public void Update( IActionContext context, ref ActionPresentation presentation )
{
presentation.Visible = (context.Kind == ActionContextKind.MainMenu);
presentation.Checked = Core.SettingStore.ReadBool( IniKeys.Section, IniKeys.FilterUnreadFeeds, false );
}
}
public class FilterErrorFeedsAction : IAction
{
public void Execute( IActionContext context )
{
bool val = Core.SettingStore.ReadBool( IniKeys.Section, IniKeys.FilterErrorFeeds, false );
Core.SettingStore.WriteBool( IniKeys.Section, IniKeys.FilterErrorFeeds, !val );
RSSPlugin.UpdateErrorPaneFilter( !val );
}
public void Update( IActionContext context, ref ActionPresentation presentation )
{
presentation.Visible = (context.Kind == ActionContextKind.MainMenu);
presentation.Checked = Core.SettingStore.ReadBool( IniKeys.Section, IniKeys.FilterErrorFeeds, false );
}
}
public class SortByLastPostAction : IAction
{
public void Execute( IActionContext context )
{
bool val = Core.SettingStore.ReadBool( IniKeys.Section, IniKeys.ShowPlaneList, false );
Core.SettingStore.WriteBool( IniKeys.Section, IniKeys.ShowPlaneList, !val );
RSSPlugin.UpdateSortFilter( !val );
}
public void Update( IActionContext context, ref ActionPresentation presentation )
{
presentation.Visible = (context.Kind == ActionContextKind.MainMenu);
presentation.Checked = Core.SettingStore.ReadBool( IniKeys.Section, IniKeys.ShowPlaneList, false );
}
}
///
/// Action for hiding the read messages in an RSS post.
///
public class HideReadRSSAction : IAction
{
public void Execute( IActionContext context )
{
IResource rssFeed = GetFeedFromContext( context );
if ( rssFeed != null )
{
new ResourceProxy( rssFeed ).SetProp( Core.Props.DisplayUnread,
!rssFeed.HasProp( Core.Props.DisplayUnread ) );
RSSPlugin.GetInstance().ResourceNodeSelected( rssFeed );
}
}
public void Update( IActionContext context, ref ActionPresentation presentation )
{
IResource rssFeed = GetFeedFromContext( context );
if ( rssFeed != null )
{
presentation.Checked = rssFeed.HasProp( Core.Props.DisplayUnread );
}
else
{
presentation.Visible = false;
}
}
private static IResource GetFeedFromContext( IActionContext context )
{
IResource rssFeed = null;
if ( context.Kind == ActionContextKind.ContextMenu )
{
if ( context.Instance == RSSPlugin.RSSTreePane &&
context.SelectedResources.Count == 1 &&
( context.SelectedResources[ 0 ].Type == Props.RSSFeedResource ||
context.SelectedResources[ 0 ].Type == Props.RSSFeedGroupResource ) )
{
rssFeed = context.SelectedResources[ 0 ];
}
}
else if ( context.Kind == ActionContextKind.MainMenu )
{
if ( context.ListOwnerResource != null &&
( context.ListOwnerResource.Type == Props.RSSFeedResource || context.ListOwnerResource.Type == Props.RSSFeedGroupResource ) )
{
rssFeed = context.ListOwnerResource;
}
else if ( context.SelectedResources.Count == 1 &&
( context.SelectedResources[ 0 ].Type == Props.RSSFeedResource ||
context.SelectedResources[ 0 ].Type == Props.RSSFeedGroupResource ) )
{
rssFeed = context.SelectedResources[ 0 ];
}
}
return rssFeed;
}
}
public class ReadCommentsAction : ActionOnResource
{
public override void Execute( IActionContext context )
{
foreach ( IResource rssItem in context.SelectedResources )
{
if ( RSSPlugin.HasComments( rssItem ) )
{
DownloadComments( rssItem );
if ( !Core.ResourceBrowser.NewspaperVisible )
{
Core.ResourceBrowser.ExpandConversation( rssItem );
}
else
{
ResourceListDisplayOptions rldo = new ResourceListDisplayOptions();
IResource commentFeed = rssItem.GetLinkProp( -Props.ItemCommentFeed );
IResource parentFeed = rssItem.GetLinkProp( -Props.RSSItem );
rldo.SetTransientContainer( parentFeed, "Feeds" );
rldo.Caption = "Comments to '" + rssItem.DisplayName + "'";
rldo.ShowNewspaper = true;
Core.ResourceBrowser.DisplayResourceList( null,
commentFeed.GetLinksOfType( "RSSItem", Props.RSSItem ), rldo );
}
}
}
}
public override void Update( IActionContext context, ref ActionPresentation presentation )
{
base.Update( context, ref presentation );
if ( Core.ResourceBrowser.NewspaperVisible && context.SelectedResources.Count > 1 )
{
presentation.Enabled = false;
return;
}
if ( presentation.Visible )
{
bool anyComments = false;
foreach ( IResource rssItem in context.SelectedResources )
{
if ( RSSPlugin.HasComments( rssItem ) )
{
anyComments = true;
break;
}
}
if ( !anyComments )
{
if ( context.Kind == ActionContextKind.Toolbar )
{
presentation.Enabled = false;
}
else
{
presentation.Visible = false;
}
}
}
}
internal static void DownloadComments( IResource rssItem )
{
IResource parentFeed = rssItem.GetLinkProp( -Props.RSSItem );
string commentUrl = rssItem.GetStringProp( Props.CommentRSS );
if ( parentFeed != null )
{
try
{
commentUrl = new Uri( new Uri( parentFeed.GetStringProp( Props.URL ) ), commentUrl ).ToString();
}
catch( Exception ex )
{
Trace.WriteLine( "Error building absolute comment feed URI: " + ex.Message );
}
}
IResource commentFeed = rssItem.GetLinkProp( -Props.ItemCommentFeed );
if ( commentFeed == null )
{
ResourceProxy commentFeedProxy = ResourceProxy.BeginNewResource( Props.RSSFeedResource );
commentFeedProxy.AddLink( Props.ItemCommentFeed, rssItem );
if ( parentFeed != null )
{
commentFeedProxy.SetProp( Props.FeedComment2Feed, parentFeed );
}
commentFeedProxy.SetProp( Props.URL, commentUrl );
commentFeedProxy.EndUpdate();
commentFeed = commentFeedProxy.Resource;
}
else if ( !commentFeed.HasProp( Props.URL ) )
{
new ResourceProxy( commentFeed ).SetProp( Props.URL, commentUrl );
}
CreateDownloadingCommentsItem( rssItem );
RSSUnitOfWork uow = new RSSUnitOfWork( commentFeed, true, false );
uow.ParseDone += OnFeedParseDone;
Core.NetworkAP.QueueJob( JobPriority.Immediate, uow );
}
private static void OnFeedParseDone( object sender, EventArgs e )
{
RSSUnitOfWork uow = (RSSUnitOfWork)sender;
if ( uow.Status == RSSWorkStatus.Success )
{
FeedUpdateQueue.CleanupCommentFeed( uow );
}
else if ( uow.Status == RSSWorkStatus.XMLError )
{
IResource rssItem = uow.Feed.GetLinkProp( Props.ItemCommentFeed );
IResource res = FindDownloadingCommentsItem( rssItem );
if ( res != null )
{
res.SetProp( Core.Props.Subject, "Comment download failed: " + uow.LastException.Message );
}
}
}
private static void CreateDownloadingCommentsItem( IResource rssItem )
{
if ( FindDownloadingCommentsItem( rssItem ) != null )
{
return;
}
ResourceProxy transientItem = ResourceProxy.BeginNewResource( "RSSItem" );
transientItem.SetProp( Core.Props.Subject, "Downloading comments..." );
// make sure the stub item is visible when downloading comments is activated from a view
transientItem.SetProp( Core.Props.Date, rssItem.GetDateProp( Core.Props.Date ) );
transientItem.SetProp( Props.ItemComment, rssItem );
transientItem.SetProp( Props.FeedComment, rssItem.GetLinkProp( -Props.RSSItem ) );
transientItem.SetProp( Props.Transient, 1 );
transientItem.EndUpdateAsync();
}
internal static IResource FindDownloadingCommentsItem( IResource rssItem )
{
foreach ( IResource transientRes in Core.ResourceStore.FindResources( "RSSItem", Core.Props.Subject,
"Downloading comments..." ) )
{
if ( transientRes.HasLink( Props.ItemComment, rssItem ) )
{
return transientRes;
}
}
return null;
}
}
public class SetAutoUpdateFeedAction : ActionOnResource
{
public override void Execute( IActionContext context )
{
foreach ( IResource feed in context.SelectedResources )
{
new ResourceProxy( feed ).SetProp( Props.AutoUpdateComments, !feed.HasProp( Props.AutoUpdateComments ) );
}
}
public override void Update( IActionContext context, ref ActionPresentation presentation )
{
base.Update( context, ref presentation );
presentation.Visible = false;
if ( context.SelectedResources.Count != 1 )
{
return;
}
IResource feed = context.SelectedResources[ 0 ];
if ( feed == null || feed.Type != Props.RSSFeedResource )
{
return;
}
presentation.Visible = true;
presentation.Checked = feed.HasProp( Props.AutoUpdateComments );
}
}
public class PostNewComment : ActionOnResource
{
public override void Execute( IActionContext context )
{
foreach ( IResource item in context.SelectedResources )
{
PostCommentForm.CreateNewComment( item );
}
}
public override void Update( IActionContext context, ref ActionPresentation presentation )
{
base.Update( context, ref presentation );
presentation.Visible = false;
if ( context.SelectedResources.Count != 1 )
{
return;
}
IResource item = context.SelectedResources[ 0 ];
if ( item == null || item.Type != "RSSItem" || !item.HasProp( Props.WfwComment ) )
{
return;
}
presentation.Visible = true;
}
}
public class PlanToDownloadAction : IAction
{
public void Execute( IActionContext context )
{
IResourceList selectedResources = context.SelectedResources;
foreach ( IResource resource in selectedResources.ValidResources )
{
int state = resource.GetIntProp( Props.EnclosureDownloadingState );
if ( state == DownloadState.Failed || state == DownloadState.NotDownloaded )
{
EnclosureDownloadManager.PlanToDownload( resource );
}
}
}
public void Update( IActionContext context, ref ActionPresentation presentation )
{
IResourceList selectedResources = context.SelectedResources;
foreach ( IResource resource in selectedResources.ValidResources )
{
if ( resource.HasProp( Props.EnclosureURL ) )
{
int state = resource.GetIntProp( Props.EnclosureDownloadingState );
if ( state == DownloadState.Failed || state == DownloadState.NotDownloaded )
{
presentation.Visible = true;
return;
}
}
}
presentation.Visible = false;
}
}
public class InterruptDownloadAction : IAction
{
public void Execute( IActionContext context )
{
IResourceList selectedResources = context.SelectedResources;
foreach ( IResource resource in selectedResources.ValidResources )
{
if ( resource.HasProp( Props.EnclosureURL ) )
{
int state = resource.GetIntProp( Props.EnclosureDownloadingState );
if ( state == DownloadState.InProgress || state == DownloadState.Planned )
{
EnclosureDownloadManager.CancelDownload( resource );
}
}
}
}
public void Update( IActionContext context, ref ActionPresentation presentation )
{
IResourceList selectedResources = context.SelectedResources;
foreach ( IResource resource in selectedResources.ValidResources )
{
int state = resource.GetIntProp( Props.EnclosureDownloadingState );
if ( state == DownloadState.InProgress || state == DownloadState.Planned )
{
presentation.Visible = true;
return;
}
}
presentation.Visible = false;
}
}
public class LocateOnDiskAction : ActionOnResource
{
public override void Execute( IActionContext context )
{
IResourceList resources = context.SelectedResources;
foreach ( IResource res in resources )
{
try
{
if ( res.Type == "RSSItem" )
{
string path = res.GetPropText( Props.EnclosureTempFile );
if ( path.Length == 0 )
{
IResource feed = res.GetLinkProp( -Props.RSSItem );
path = feed.GetPropText( Props.EnclosurePath );
if ( path.Length == 0 )
{
path = Settings.EnclosurePath;
}
}
if ( path != null && path.Length > 0 )
{
//Process.Start( Path.GetDirectoryName( path ) );
Process.Start( "explorer", "/select, \"" + path + "\"" );
}
}
}
catch ( Exception e )
{
Utils.DisplayException( e, "Error" );
}
}
}
public override void Update( IActionContext context, ref ActionPresentation presentation )
{
IResourceList selectedResources = context.SelectedResources;
foreach ( IResource resource in selectedResources.ValidResources )
{
int state = resource.GetIntProp( Props.EnclosureDownloadingState );
if ( state == DownloadState.Completed )
{
presentation.Visible = true;
return;
}
}
presentation.Visible = false;
}
}
public class RunEnclosureAction : ActionOnSingleResource
{
public override void Execute( IActionContext context )
{
IResource res = context.SelectedResources[ 0 ];
try
{
string path = res.GetPropText( Props.EnclosureTempFile );
if ( path.Length == 0 )
{
IResource feed = res.GetLinkProp( -Props.RSSItem );
path = feed.GetPropText( Props.EnclosurePath );
if ( path.Length == 0 )
{
path = Settings.EnclosurePath;
}
}
if ( path != null && path.Length > 0 )
{
Process.Start( path );
}
}
catch ( Exception e )
{
Utils.DisplayException( e, "Error" );
}
}
public override void Update( IActionContext context, ref ActionPresentation presentation )
{
base.Update( context, ref presentation );
if( presentation.Visible )
{
IResource res = context.SelectedResources[ 0 ];
int state = res.GetIntProp( Props.EnclosureDownloadingState );
presentation.Visible = (res.Type == "RSSItem") && (state == DownloadState.Completed);
}
}
}
public class DeleteEnclosureAction : ActionOnSingleResource
{
public override void Execute( IActionContext context )
{
IResource res = context.SelectedResources[ 0 ];
try
{
string path = res.GetPropText( Props.EnclosureTempFile );
if ( path.Length == 0 )
{
IResource feed = res.GetLinkProp( -Props.RSSItem );
path = feed.GetPropText( Props.EnclosurePath );
if ( path.Length == 0 )
{
path = Settings.EnclosurePath;
}
}
if ( path != null && path.Length > 0 )
{
File.Delete( path );
}
}
catch ( Exception e )
{
Utils.DisplayException( e, "Error" );
}
}
public override void Update( IActionContext context, ref ActionPresentation presentation )
{
base.Update( context, ref presentation );
if( presentation.Visible )
{
IResource res = context.SelectedResources[ 0 ];
int state = res.GetIntProp( Props.EnclosureDownloadingState );
presentation.Visible = (res.Type == "RSSItem") && (state == DownloadState.Completed);
}
}
}
public class SearchInFeed: SimpleAction
{
public override void Execute( IActionContext context )
{
IResource template = Core.ResourceStore.FindUniqueResource( FilterManagerProps.ConditionTemplateResName,
Core.Props.Name, "Post is in %feed%" );
IResource condition = FilterConvertors.InstantiateTemplate( template, context.SelectedResources, new string[]{ "RSSItem" } );
Core.FilteringFormsManager.ShowAdvancedSearchForm( "", new string[]{ "RSSItem" }, new IResource[] { condition }, null );
}
public override void Update( IActionContext context, ref ActionPresentation presentation )
{
presentation.Enabled = presentation.Visible = context.SelectedResources.Count > 0;
if( context.SelectedResources.Count > 1 )
presentation.Text = "Search in these Feeds";
}
}
public class SearchInFeedGroupAction: SimpleAction
{
public override void Execute( IActionContext context )
{
IResourceList feeds = Core.ResourceStore.EmptyResourceList;
foreach( IResource folder in context.SelectedResources )
feeds = feeds.Union( GetFeedsByFolder( folder ) );
IResource template = Core.ResourceStore.FindUniqueResource( FilterManagerProps.ConditionTemplateResName,
Core.Props.Name, "Post is in %feed%" );
IResource condition = FilterConvertors.InstantiateTemplate( template, feeds, new string[]{ "RSSItem" } );
Core.FilteringFormsManager.ShowAdvancedSearchForm( "", new string[]{ "RSSItem" }, new IResource[] { condition }, null );
}
public override void Update( IActionContext context, ref ActionPresentation presentation )
{
IResourceList feeds = Core.ResourceStore.EmptyResourceList;
foreach( IResource folder in context.SelectedResources )
{
if( folder.Type != Props.RSSFeedGroupResource )
throw new ArgumentException( "Search Action -- Action can be applied only to Feed Folder resources." );
feeds = feeds.Union( GetFeedsByFolder( folder ) );
}
presentation.Enabled = feeds.Count > 0;
}
private static IResourceList GetFeedsByFolder( IResource folder )
{
IResourceList feeds = Core.ResourceStore.EmptyResourceList;
IResourceList linked = folder.GetLinksTo( null, Core.Props.Parent );
foreach( IResource res in linked.ValidResources )
{
if( res.Type == Props.RSSFeedResource )
feeds = feeds.Union( res.ToResourceList(), true );
else
if( res.Type == Props.RSSFeedGroupResource )
feeds = feeds.Union( GetFeedsByFolder( res ) );
}
return feeds;
}
}
public class SaveItemAction: ActionOnResource
{
public override void Execute( IActionContext context )
{
IResource rssItem = context.SelectedResources [0];
string fileName = rssItem.GetPropText( Core.Props.Subject ).Trim();
IOTools.MakeValidFileName( ref fileName );
fileName = fileName.TrimEnd( '.' ) + ".html";
SaveFileDialog dlg = new SaveFileDialog();
dlg.Filter = "HTML files (*.html)|*.html|All files|*.*";
using( dlg )
{
dlg.FileName = fileName;
if ( dlg.ShowDialog( Core.MainWindow ) == DialogResult.OK )
{
FileStream fs = new FileStream( dlg.FileName, FileMode.Create );
TextWriter fsWriter = new StreamWriter( fs, Encoding.UTF8 );
try
{
RssNewspaperProvider provider = new RssNewspaperProvider();
fsWriter.Write( "
" );
fsWriter.Write( HttpUtility.HtmlEncode( rssItem.GetStringProp( Core.Props.Subject ) ) );
fsWriter.Write( "" );
foreach( IResource res in context.SelectedResources.ValidResources )
{
provider.GetItemHtml( res, fsWriter );
if ( context.SelectedResources.Count > 1 )
{
fsWriter.Write( "
" );
}
}
fsWriter.Write( "" );
}
finally
{
fsWriter.Close();
}
}
}
}
}
public class StartStopUpdateFeedAction : IAction
{
public void Execute( IActionContext context )
{
bool startAction = true;
IResourceList selectedResources = context.SelectedResources;
foreach( IResource res in selectedResources.ValidResources )
{
bool state = res.HasProp( Props.IsPaused );
startAction = startAction && state;
}
Core.ResourceAP.QueueJob( JobPriority.Immediate,
new UpdateStartStopStatusesDelegate( UpdateStartStopStatuses ), selectedResources, startAction );
}
private delegate void UpdateStartStopStatusesDelegate( IResourceList selectedResources, bool startAction );
private static void UpdateStartStopStatuses( IResourceList selectedResources, bool startAction )
{
IRssService service = (IRssService) Core.PluginLoader.GetPluginService( typeof( IRssService ) );
foreach( IResource res in selectedResources.ValidResources )
{
if( startAction )
{
if( res.Type == Props.RSSFeedResource )
{
service.ScheduleFeedUpdate( res );
}
IResource temp = res;
do
{
temp.DeleteProp( Props.IsPaused );
temp = temp.GetLinkProp( Core.Props.Parent );
}
while( temp != null );
}
else
{
res.SetProp( Props.IsPaused, true );
}
if( res.Type == Props.RSSFeedGroupResource )
{
UpdateStartStopStatuses( res.GetLinksTo( null, Core.Props.Parent ), startAction );
}
}
}
public void Update( IActionContext context, ref ActionPresentation presentation )
{
bool startAction = true, pauseAction = true;
IResourceList selectedResources = context.SelectedResources;
presentation.Visible = false;
if( selectedResources.Count > 0 )
{
bool hasFolders = false;
foreach( IResource res in selectedResources.ValidResources )
{
bool state = res.HasProp( Props.IsPaused );
startAction = startAction && state;
pauseAction = pauseAction && !state;
hasFolders = hasFolders || res.Type == Props.RSSFeedGroupResource;
}
presentation.Visible = true;
presentation.Enabled = startAction || pauseAction;
if( startAction )
{
presentation.Text = "Resume Updating Feed";
if( hasFolders || selectedResources.Count > 1 )
presentation.Text += "(s)";
}
else
if( pauseAction )
{
presentation.Text = "Pause Updating Feed";
if( hasFolders || selectedResources.Count > 1 )
presentation.Text += "(s)";
}
}
}
}
/**
* action for copying feed post URL
*/
public class CopyPostURLAction: ActionOnSingleResource
{
public override void Execute( IActionContext context )
{
IResource post = context.SelectedResources[ 0 ];
try
{
Clipboard.SetDataObject( post.GetPropText( Props.Link ) );
}
catch( ExternalException e )
{
Utils.DisplayException( Core.MainWindow, e, "Error" );
}
}
}
}