using Common.Debug; using Common.Helpers; using Common.IO; using Common.Wpf.Extensions; using FeedCenter.Options; using FeedCenter.Properties; using System; using System.Collections.Generic; using System.ComponentModel; using System.Deployment.Application; using System.IO; using System.Linq; using System.Threading; using System.Web.UI; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Interop; using System.Windows.Media; namespace FeedCenter { public partial class MainWindow { #region Member variables private int _feedIndex; private Feed _currentFeed; private DateTime _lastFeedDisplay; private DateTime _lastFeedRead; private System.Windows.Forms.Timer _mainTimer; private FeedCenterEntities _database; private InterprocessMessageListener _commandLineListener; private BackgroundWorker _feedReadWorker; #endregion #region Constructor public MainWindow() { InitializeComponent(); } private bool _activated; protected override void OnActivated(EventArgs e) { base.OnActivated(e); if (_activated) return; _activated = true; // Load the lock state HandleWindowLockState(); // Watch for size and location changes SizeChanged += HandleWindowSizeChanged; LocationChanged += HandleWindowLocationChanged; // Watch for setting changes Settings.Default.PropertyChanged += HandlePropertyChanged; } public void Initialize() { // Show the notification icon NotificationIcon.Initialize(this); // Load window settings LoadWindowSettings(); // Set the foreground color to something that can be seen linkTextList.Foreground = (System.Drawing.SystemColors.Desktop.GetBrightness() < 0.5) ? Brushes.White : Brushes.Black; headerLabel.Foreground = linkTextList.Foreground; // Create the background worker that does the actual reading _feedReadWorker = new BackgroundWorker { WorkerReportsProgress = true, WorkerSupportsCancellation = true }; _feedReadWorker.DoWork += HandleFeedReadWorkerStart; _feedReadWorker.ProgressChanged += HandleFeedReadWorkerProgressChanged; _feedReadWorker.RunWorkerCompleted += HandleFeedReadWorkerCompleted; // Setup the database _database = new FeedCenterEntities(); // Initialize the command line listener _commandLineListener = new InterprocessMessageListener(Properties.Resources.ApplicationName); _commandLineListener.MessageReceived += HandleCommandLine; // Handle any command line we were started with HandleCommandLine(null, new InterprocessMessageListener.InterprocessMessageEventArgs(Environment.CommandLine)); // Create a timer to keep track of things we need to do InitializeTimer(); // Initialize the feed display InitializeFeed(); Tracer.WriteLine("MainForm creation finished"); } #endregion #region Window overrides protected override void OnClosing(CancelEventArgs e) { base.OnClosing(e); // Ditch the worker if (_feedReadWorker != null) { _feedReadWorker.CancelAsync(); _feedReadWorker.Dispose(); } // Get rid of the timer TerminateTimer(); // Save current window settings SaveWindowSettings(); // Save settings Settings.Default.Save(); // Save options _database.SaveChanges(); // Get rid of the notification icon NotificationIcon.Dispose(); } #endregion #region Setting events private void HandlePropertyChanged(object sender, PropertyChangedEventArgs e) { // Make sure we're on the right thread if (!Dispatcher.CheckAccess()) { Dispatcher.Invoke(new EventHandler(HandlePropertyChanged), sender, e); return; } if (e.PropertyName == Reflection.GetPropertyName(() => Settings.Default.MultipleLineDisplay)) { // Update the current feed DisplayFeed(); } else if (e.PropertyName == Reflection.GetPropertyName(() => Settings.Default.WindowLocked)) { // Update the window for the new window lock value HandleWindowLockState(); } else if (e.PropertyName == Reflection.GetPropertyName(() => Settings.Default.ToolbarLocation)) { // Update the window for the toolbar location switch (Settings.Default.ToolbarLocation) { case Dock.Top: Grid.SetRow(navigationToolbarTray, mainGrid.GetRowIndex(topToolbarRow)); break; case Dock.Bottom: Grid.SetRow(navigationToolbarTray, mainGrid.GetRowIndex(bottomToolbarRow)); break; } } } #endregion #region Window methods private void LoadWindowSettings() { // Get the last window location var windowLocation = Settings.Default.WindowLocation; // Set the window into position Left = windowLocation.X; Top = windowLocation.Y; // Get the last window size var windowSize = Settings.Default.WindowSize; // Set the window into the previous size if it is valid if (!windowSize.Width.Equals(0) && !windowSize.Height.Equals(0)) { Width = windowSize.Width; Height = windowSize.Height; } // Set the location of the navigation tray switch (Settings.Default.ToolbarLocation) { case Dock.Top: Grid.SetRow(navigationToolbarTray, mainGrid.GetRowIndex(topToolbarRow)); break; case Dock.Bottom: Grid.SetRow(navigationToolbarTray, mainGrid.GetRowIndex(bottomToolbarRow)); break; } // Load the lock state HandleWindowLockState(); } private void SaveWindowSettings() { // Set the last window location Settings.Default.WindowLocation = new Point(Left, Top); // Set the last window size Settings.Default.WindowSize = new Size(Width, Height); // Save the dock on the navigation tray Settings.Default.ToolbarLocation = Grid.GetRow(navigationToolbarTray) == mainGrid.GetRowIndex(topToolbarRow) ? Dock.Top : Dock.Bottom; // Save settings Settings.Default.Save(); } private void HandleWindowLockState() { // Set the resize mode for the window ResizeMode = Settings.Default.WindowLocked ? ResizeMode.NoResize : ResizeMode.CanResize; // Show or hide the border windowBorder.BorderBrush = Settings.Default.WindowLocked ? SystemColors.ActiveBorderBrush : Brushes.Transparent; // Update the borders UpdateBorder(); } #endregion #region Header events private void HandleHeaderLabelMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { // Ignore if the window is locked if (Settings.Default.WindowLocked) return; // Start dragging DragMove(); } private void HandleCloseButtonClick(object sender, RoutedEventArgs e) { // Close the window Close(); } #endregion #region Timer handling private void InitializeTimer() { _mainTimer = new System.Windows.Forms.Timer { Interval = 1000 }; _mainTimer.Tick += HandleMainTimerTick; } private void TerminateTimer() { StopTimer(); _mainTimer.Dispose(); } private void StartTimer() { _mainTimer.Start(); } private void StopTimer() { _mainTimer.Stop(); } private void HandleMainTimerTick(object sender, EventArgs e) { // If the background worker is busy then don't do anything if (_feedReadWorker.IsBusy) return; // Stop the timer for now StopTimer(); // Move to the next feed if the scroll interval has expired and the mouse isn't hovering if (linkTextList.IsMouseOver) _lastFeedDisplay = DateTime.Now; else if (DateTime.Now - _lastFeedDisplay >= Settings.Default.FeedScrollInterval) NextFeed(); // Check to see if we should try to read the feeds if (DateTime.Now - _lastFeedRead >= Settings.Default.FeedCheckInterval) ReadFeeds(); // Get the timer going again StartTimer(); } #endregion #region Feed display private void InitializeFeed() { // Cache the feed count to save (a little) time var feedCount = _database.Feeds.Count(); // Set button states previousToolbarButton.IsEnabled = (feedCount > 1); nextToolbarButton.IsEnabled = (feedCount > 1); refreshToolbarButton.IsEnabled = (feedCount > 0); feedLabel.Visibility = (feedCount == 0 ? Visibility.Hidden : Visibility.Visible); feedButton.Visibility = (feedCount > 1 ? Visibility.Hidden : Visibility.Visible); // Clear the link list linkTextList.Items.Clear(); // Reset the feed index _feedIndex = -1; // Start the timer StartTimer(); // Don't go further if we have no feeds if (feedCount == 0) return; // Get the first feed NextFeed(); } private void NextFeed() { var feedCount = _database.Feeds.Count(); if (feedCount == 0) return; if (Settings.Default.DisplayEmptyFeeds) { // Increment the index and adjust if we've gone around the end _feedIndex = (_feedIndex + 1) % feedCount; // Get the feed _currentFeed = _database.Feeds.OrderBy(feed => feed.Name).AsEnumerable().ElementAt(_feedIndex); } else { // Keep track if we found something var found = false; // Remember our starting position var startIndex = (_feedIndex == -1 ? 0 : _feedIndex); // Increment the index and adjust if we've gone around the end _feedIndex = (_feedIndex + 1) % feedCount; // Loop until we come back to the start index do { // Get the feed _currentFeed = _database.Feeds.OrderBy(feed => feed.Name).AsEnumerable().ElementAt(_feedIndex); // If the current feed has unread items then we can display it if (_currentFeed.Items.Count(item => !item.BeenRead) > 0) { found = true; break; } // Increment the index and adjust if we've gone around the end _feedIndex = (_feedIndex + 1) % feedCount; } while (startIndex != _feedIndex); // If nothing was found then clear the current feed if (!found) { _feedIndex = -1; _currentFeed = null; } } // Update the feed timestamp _lastFeedDisplay = DateTime.Now; // Update the display DisplayFeed(); } private void PreviousFeed() { var feedCount = _database.Feeds.Count(); if (feedCount == 0) return; if (Settings.Default.DisplayEmptyFeeds) { // Decrement the feed index _feedIndex--; // If we've gone below the start of the list then reset to the end if (_feedIndex < 0) _feedIndex = feedCount - 1; // Get the feed _currentFeed = _database.Feeds.OrderBy(feed => feed.Name).AsEnumerable().ElementAt(_feedIndex); } else { // Keep track if we found something var found = false; // Remember our starting position var startIndex = (_feedIndex == -1 ? 0 : _feedIndex); // Decrement the feed index _feedIndex--; // If we've gone below the start of the list then reset to the end if (_feedIndex < 0) _feedIndex = feedCount - 1; // Loop until we come back to the start index do { // Get the feed _currentFeed = _database.Feeds.OrderBy(feed => feed.Name).AsEnumerable().ElementAt(_feedIndex); // If the current feed has unread items then we can display it if (_currentFeed.Items.Count(item => !item.BeenRead) > 0) { found = true; break; } // Decrement the feed index _feedIndex--; // If we've gone below the start of the list then reset to the end if (_feedIndex < 0) _feedIndex = feedCount - 1; } while (startIndex != _feedIndex); // If nothing was found then clear the current feed if (!found) { _feedIndex = -1; _currentFeed = null; } } // Update the feed timestamp _lastFeedDisplay = DateTime.Now; // Update the display DisplayFeed(); } private void UpdateOpenAllButton() { var multipleOpenAction = _currentFeed.MultipleOpenAction; switch (multipleOpenAction) { case MultipleOpenAction.IndividualPages: openAllToolbarButton.ToolTip = Properties.Resources.openAllMultipleToolbarButton; break; case MultipleOpenAction.SinglePage: openAllToolbarButton.ToolTip = Properties.Resources.openAllSingleToolbarButton; break; } } private void DisplayFeed() { // Just clear the display if we have no feed if (_currentFeed == null) { feedLabel.Text = string.Empty; feedButton.Visibility = Visibility.Hidden; linkTextList.Items.Clear(); return; } // Set the header to the feed title feedLabel.Text = (_currentFeed.Name.Length > 0 ? _currentFeed.Name : _currentFeed.Title); feedButton.Visibility = _database.Feeds.Count() > 1 ? Visibility.Visible : Visibility.Hidden; // Clear the current list linkTextList.Items.Clear(); // Sort the items by sequence var sortedItems = _currentFeed.Items.Where(item => !item.BeenRead).OrderBy(item => item.Sequence); // Loop over all items in the current feed foreach (var feedItem in sortedItems) { // Add the list item linkTextList.Items.Add(feedItem); } UpdateOpenAllButton(); } private void MarkAllItemsAsRead() { // Loop over all items and mark them as read foreach (FeedItem feedItem in linkTextList.Items) feedItem.BeenRead = true; // Save the changes _database.SaveChanges(); // Clear the list linkTextList.Items.Clear(); } #endregion #region Feed reading private class FeedReadWorkerInput { public bool ForceRead; public Feed Feed; } private class FeedReadWorkerOutput { public UpdateCheckInfo UpdateResult; } private void SetProgressMode(bool value, int feedCount) { // Reset the progress bar if we need it if (value) { feedReadProgress.Value = 0; feedReadProgress.Maximum = feedCount + 2; feedReadProgress.Visibility = Visibility.Visible; } else { feedReadProgress.Visibility = Visibility.Collapsed; } } private void ReadCurrentFeed(bool forceRead = false) { // Don't read if we're already working if (_feedReadWorker.IsBusy) return; // Don't read if there is nothing to read if (!_database.Feeds.Any()) return; // Switch to progress mode SetProgressMode(true, 1); // Create the input class var workerInput = new FeedReadWorkerInput { ForceRead = forceRead, Feed = _currentFeed }; // Start the worker _feedReadWorker.RunWorkerAsync(workerInput); } private void ReadFeeds(bool forceRead = false) { // Don't read if we're already working if (_feedReadWorker.IsBusy) return; // Don't read if there is nothing to read if (!_database.Feeds.Any()) return; // Switch to progress mode SetProgressMode(true, _database.Feeds.Count()); // Create the input class var workerInput = new FeedReadWorkerInput { ForceRead = forceRead, Feed = null }; // Start the worker _feedReadWorker.RunWorkerAsync(workerInput); } private void HandleFeedReadWorkerProgressChanged(object sender, ProgressChangedEventArgs e) { // Set progress feedReadProgress.Value = e.ProgressPercentage; } private void HandleFeedReadWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { // Get the state info var workerOutput = (FeedReadWorkerOutput) e.Result; // Reset the database to current settings ResetDatabase(); // Save settings Settings.Default.Save(); // Set the read timestamp _lastFeedRead = DateTime.Now; // Update the current feed DisplayFeed(); // Switch to normal mode SetProgressMode(false, 0); // Check for update information var updateCheckInfo = workerOutput.UpdateResult; if (updateCheckInfo != null && updateCheckInfo.UpdateAvailable) newVersionLink.Visibility = Visibility.Visible; UpdateErrorLink(); } private void UpdateErrorLink() { var feedErrorCount = _database.Feeds.Count(f => f.LastReadResult != FeedReadResult.Success); // Set the visibility of the error link feedErrorsLink.Visibility = feedErrorCount == 0 ? Visibility.Collapsed : Visibility.Visible; // Set the text to match the number of errors feedErrorsLink.Text = feedErrorCount == 1 ? Properties.Resources.FeedErrorLink : string.Format(Properties.Resources.FeedErrorsLink, feedErrorCount); } private static void HandleFeedReadWorkerStart(object sender, DoWorkEventArgs e) { // Create a new database instance for just this thread var database = new FeedCenterEntities(); // Get the worker var worker = (BackgroundWorker) sender; // Get the input information var workerInput = (FeedReadWorkerInput) e.Argument; // Create the output var workerOutput = new FeedReadWorkerOutput(); // Setup for progress var currentProgress = 0; // Create the list of feeds to read var feedsToRead = new List(); // If we have a single feed then add it to the list - otherwise add them all if (workerInput.Feed != null) feedsToRead.Add(database.Feeds.First(feed => feed.ID == workerInput.Feed.ID)); else feedsToRead.AddRange(database.Feeds); // Loop over each feed and read it foreach (var feed in feedsToRead) { // Read the feed feed.Read(database, workerInput.ForceRead); // Increment progress currentProgress += 1; // Report progress worker.ReportProgress(currentProgress); } // Save the changes database.SaveChanges(); // Increment progress currentProgress += 1; // Report progress worker.ReportProgress(currentProgress); // See if we're due for a version check if (DateTime.Now - Settings.Default.LastVersionCheck >= Settings.Default.VersionCheckInterval && ApplicationDeployment.IsNetworkDeployed) { UpdateCheckInfo updateCheckInfo = null; try { // Get the update information updateCheckInfo = ApplicationDeployment.CurrentDeployment.CheckForDetailedUpdate(false); } catch (Exception exception) { Tracer.WriteException(exception); } // Store the update information in the output workerOutput.UpdateResult = updateCheckInfo; // Update the last check time Settings.Default.LastVersionCheck = DateTime.Now; } // Increment progress currentProgress += 1; // Report progress worker.ReportProgress(currentProgress); // Save the output e.Result = workerOutput; // Sleep for a little bit so the user can see the update Thread.Sleep(Settings.Default.ProgressSleepInterval * 3); } #endregion #region Remote command line handling private void HandleCommandLine(object sender, InterprocessMessageListener.InterprocessMessageEventArgs e) { // If the command line is blank then ignore it if (e.Message.Length == 0) return; // Pad the command line with a trailing space just to be lazy in parsing var commandLine = e.Message + " "; // Look for the feed URL in the command line var startPosition = commandLine.IndexOf("feed://", StringComparison.Ordinal); // If we found one then we should extract and process it if (startPosition > 0) { // Advance past the protocol startPosition += 7; // Starting at the URL position look for the next space var endPosition = commandLine.IndexOf(" ", startPosition, StringComparison.Ordinal); // Extract the feed URL var feedUrl = commandLine.Substring(startPosition, endPosition - startPosition); // Add the HTTP protocol by default feedUrl = "http://" + feedUrl; // Create a new feed using the URL HandleNewFeed(feedUrl); } } private delegate void NewFeedDelegate(string feedUrl); private void HandleNewFeed(string feedUrl) { // Create and configure the new feed var feed = Feed.Create(); feed.Source = feedUrl; feed.Category = _database.Categories.ToList().First(category => category.IsDefault); // Read the feed for the first time var feedReadResult = feed.Read(_database); // See if we read the feed okay if (feedReadResult == FeedReadResult.Success) { // Update the feed name to be the title feed.Name = feed.Title; // Add the feed to the feed table _database.Feeds.Add(feed); // Save the changes _database.SaveChanges(); // Show a tip NotificationIcon.ShowBalloonTip(string.Format(Properties.Resources.FeedAddedNotification, feed.Name), System.Windows.Forms.ToolTipIcon.Info); // Re-initialize the feed display DisplayFeed(); } else { // Feed read failed - ceate a new feed window var feedForm = new FeedWindow(); var dialogResult = feedForm.Display(_database, feed, this); // Display the new feed form if (dialogResult.HasValue && dialogResult.Value) { // Add the feed to the feed table _database.Feeds.Add(feed); // Save the changes _database.SaveChanges(); // Re-initialize the feed display DisplayFeed(); } } } #endregion #region Database helpers private void ResetDatabase() { // Get the ID of the current feed var currentId = _currentFeed.ID; // Create a new database object _database = new FeedCenterEntities(); // Get a list of feeds ordered by name var feedList = _database.Feeds.OrderBy(f => f.Name).ToList(); // First try to find the current feed by ID to see if it is still there var newIndex = feedList.FindIndex(f => f.ID == currentId); if (newIndex == -1) { // The current feed isn't there anymore so see if we can find a feed at the old index if (feedList.ElementAtOrDefault(_feedIndex) != null) newIndex = _feedIndex; // If there is no feed at the old location then give up and go back to the start if (newIndex == -1 && feedList.Count > 0) newIndex = 0; } // Set the current index to the new index _feedIndex = newIndex; // Re-get the current feed _currentFeed = (_feedIndex == -1 ? null : _database.Feeds.OrderBy(feed => feed.Name).AsEnumerable().ElementAt(_feedIndex)); } #endregion #region Drag and drop private void HandleDragOver(object sender, DragEventArgs e) { // Default to not allowed e.Effects = DragDropEffects.None; e.Handled = true; // If there isn't any text in the data then it is not allowed if (!e.Data.GetDataPresent(DataFormats.Text)) return; // Get the data as a string var data = (string) e.Data.GetData(DataFormats.Text); // If the data doesn't look like a URI then it is not allowed if (!Uri.IsWellFormedUriString(data, UriKind.Absolute)) return; // Allowed e.Effects = DragDropEffects.Copy; } private void HandleDragDrop(object sender, DragEventArgs e) { // Get the data as a string var data = (string) e.Data.GetData(DataFormats.Text); // Handle the new feed but allow the drag/drop to complete Dispatcher.BeginInvoke(new NewFeedDelegate(HandleNewFeed), data); } #endregion #region Link list events private void HandleLinkTextListMouseUp(object sender, MouseButtonEventArgs e) { switch (e.ChangedButton) { case MouseButton.XButton1: PreviousFeed(); break; case MouseButton.XButton2: NextFeed(); break; } } private void HandleLinkTextListListItemMouseUp(object sender, MouseButtonEventArgs e) { // Only handle the middle button if (e.ChangedButton != MouseButton.Middle) return; // Get the feed item var feedItem = (FeedItem) ((ListBoxItem) sender).DataContext; // The feed item has been read and is no longer new feedItem.BeenRead = true; feedItem.New = false; // Remove the item from the list linkTextList.Items.Remove(feedItem); // Save the changes _database.SaveChanges(); } private void HandleLinkTextListListItemMouseDoubleClick(object sender, MouseButtonEventArgs e) { // Get the feed item var feedItem = (FeedItem) ((ListBoxItem) sender).DataContext; // Open the item link if (BrowserCommon.OpenLink(feedItem.Link)) { // The feed item has been read and is no longer new feedItem.BeenRead = true; feedItem.New = false; // Remove the item from the list linkTextList.Items.Remove(feedItem); // Save the changes _database.SaveChanges(); } } #endregion #region Feed list menu private void HandleFeedButtonClick(object sender, RoutedEventArgs e) { // Create a new context menu var contextMenu = new ContextMenu(); // Loop over each feed foreach (var feed in _database.Feeds.OrderBy(feed => feed.Name)) { // Build a string to display the feed name and the unread count var display = string.Format("{0} ({1:d})", feed.Name, feed.Items.Count(item => !item.BeenRead)); // Create a menu item var menuItem = new MenuItem { Header = display, Tag = feed, // Set the current item to bold FontWeight = feed == _currentFeed ? FontWeights.Bold : FontWeights.Normal }; // Handle the click menuItem.Click += HandleFeedMenuItemClick; // Add the item to the list contextMenu.Items.Add(menuItem); } // Set the context menu placement to this button contextMenu.PlacementTarget = this; // Open the context menu contextMenu.IsOpen = true; } private void HandleFeedMenuItemClick(object sender, RoutedEventArgs e) { // Get the menu item clicked var menuItem = (MenuItem) sender; // Get the feed from the menu item tab var feed = (Feed) menuItem.Tag; // Loop over all feeds and look for the index of the new one var feedIndex = 0; foreach (var loopFeed in _database.Feeds.OrderBy(loopFeed => loopFeed.Name)) { if (loopFeed == feed) { _feedIndex = feedIndex; break; } feedIndex++; } // Set the current feed _currentFeed = feed; // Update the feed timestamp _lastFeedDisplay = DateTime.Now; // Update the display DisplayFeed(); } #endregion #region Window border private void UpdateBorder() { var windowInteropHelper = new WindowInteropHelper(this); var screen = System.Windows.Forms.Screen.FromHandle(windowInteropHelper.Handle); var rectangle = new System.Drawing.Rectangle { X = (int) Left, Y = (int) Top, Width = (int) Width, Height = (int) Height }; var borderThickness = new Thickness(); if (rectangle.Right != screen.WorkingArea.Right) borderThickness.Right = 1; if (rectangle.Left != screen.WorkingArea.Left) borderThickness.Left = 1; if (rectangle.Top != screen.WorkingArea.Top) borderThickness.Top = 1; if (rectangle.Bottom != screen.WorkingArea.Bottom) borderThickness.Bottom = 1; windowBorder.BorderThickness = borderThickness; } private DelayedMethod _windowStateDelay; private void HandleWindowSizeChanged(object sender, SizeChangedEventArgs e) { if (_windowStateDelay == null) _windowStateDelay = new DelayedMethod(500, UpdateWindowSettings); _windowStateDelay.Reset(); } private void HandleWindowLocationChanged(object sender, EventArgs e) { if (_windowStateDelay == null) _windowStateDelay = new DelayedMethod(500, UpdateWindowSettings); _windowStateDelay.Reset(); } private void UpdateWindowSettings() { // Save current window settings SaveWindowSettings(); // Update the border UpdateBorder(); } #endregion #region Feed header private void HandleFeedLabelMouseDown(object sender, MouseButtonEventArgs e) { // Open the link for the current feed on a left double click if (e.ClickCount == 2 && e.ChangedButton == MouseButton.Left) BrowserCommon.OpenLink(_currentFeed.Link); } #endregion #region Navigation toolbar private void HandlePreviousToolbarButtonClick(object sender, RoutedEventArgs e) { PreviousFeed(); } private void HandleNextToolbarButtonClick(object sender, RoutedEventArgs e) { NextFeed(); } private void OpenAllFeedItemsIndividually() { // Create a new list of feed items var feedItems = (from FeedItem feedItem in linkTextList.Items select feedItem).ToList(); // Get the browser var browser = BrowserCommon.FindBrowser(Settings.Default.Browser); // Cache the settings object var settings = Settings.Default; // Start with a longer sleep interval to give time for the browser to come up var sleepInterval = settings.OpenAllSleepIntervalFirst; // Loop over all items foreach (var feedItem in feedItems) { // Try to open the link if (BrowserCommon.OpenLink(browser, feedItem.Link)) { // Mark the feed as read feedItem.BeenRead = true; // Remove the item linkTextList.Items.Remove(feedItem); } // Wait a little bit Thread.Sleep(sleepInterval); // Switch to the normal sleep interval sleepInterval = settings.OpenAllSleepInterval; } // Save the changes _database.SaveChanges(); } private void HandleOptionsToolbarButtonClick(object sender, RoutedEventArgs e) { // Create the options form var optionsWindow = new OptionsWindow { Owner = this }; // Show the options form and get the result var result = optionsWindow.ShowDialog(); // If okay was selected if (result.HasValue && result.Value) { // Reset the database to current settings ResetDatabase(); // Re-initialize the feed display DisplayFeed(); } } private void HandleMarkReadToolbarButtonClick(object sender, RoutedEventArgs e) { MarkAllItemsAsRead(); } private void HandleShowErrorsButtonClick(object sender, RoutedEventArgs e) { // Create the feed error window var feedErrorWindow = new FeedErrorWindow(); // Display the window var result = feedErrorWindow.Display(this); // If okay was selected if (result.GetValueOrDefault()) { // Reset the database to current settings ResetDatabase(); // Re-initialize the feed display DisplayFeed(); UpdateErrorLink(); } } private void HandleRefreshMenuItemClick(object sender, RoutedEventArgs e) { var menuItem = (MenuItem) e.Source; if (Equals(menuItem, menuRefresh)) ReadCurrentFeed(true); else if (Equals(menuItem, menuRefreshAll)) ReadFeeds(true); } private void HandleRefreshToolbarButtonClick(object sender, RoutedEventArgs e) { ReadFeeds(true); } private void HandleOpenAllMenuItemClick(object sender, RoutedEventArgs e) { var menuItem = (MenuItem) e.Source; if (Equals(menuItem, menuOpenAllSinglePage)) OpenAllFeedItemsOnSinglePage(); else if (Equals(menuItem, menuOpenAllMultiplePages)) OpenAllFeedItemsIndividually(); } private void HandleOpenAllToolbarButtonClick(object sender, RoutedEventArgs e) { var multipleOpenAction = (MultipleOpenAction) _currentFeed.MultipleOpenAction; switch (multipleOpenAction) { case MultipleOpenAction.IndividualPages: OpenAllFeedItemsIndividually(); break; case MultipleOpenAction.SinglePage: OpenAllFeedItemsOnSinglePage(); break; } } private void HandleEditCurrentFeedMenuItemClick(object sender, RoutedEventArgs e) { // Create a new feed window var feedWindow = new FeedWindow(); // Display the feed window and get the result var result = feedWindow.Display(_database, _currentFeed, this); // If OK was clicked... if (result.HasValue && result.Value) { // Save _database.SaveChanges(); // Update feed DisplayFeed(); } } private void HandleDeleteCurrentFeedMenuItemClick(object sender, RoutedEventArgs e) { // Confirm this delete since it is for real if (MessageBox.Show(this, Properties.Resources.ConfirmDelete, string.Empty, MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No) == MessageBoxResult.No) return; // Get the current feed var feedToDelete = _currentFeed; // Move to the next feed NextFeed(); // Delete all items foreach (var item in feedToDelete.Items.ToList()) _database.FeedItems.Remove(item); // Delete the feed _database.Feeds.Remove(feedToDelete); // Save _database.SaveChanges(); } #endregion #region Single page reading private void OpenAllFeedItemsOnSinglePage() { var fileName = Path.GetTempFileName() + ".html"; TextWriter textWriter = new StreamWriter(fileName); using (var htmlTextWriter = new HtmlTextWriter(textWriter)) { htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.Html); htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.Head); htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.Title); htmlTextWriter.Write(_currentFeed.Title); htmlTextWriter.RenderEndTag(); htmlTextWriter.AddAttribute("http-equiv", "Content-Type"); htmlTextWriter.AddAttribute("content", "text/html; charset=utf-8"); htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.Meta); htmlTextWriter.RenderEndTag(); htmlTextWriter.RenderEndTag(); htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.Body); var sortedItems = from item in _currentFeed.Items where !item.BeenRead orderby item.Sequence ascending select item; var firstItem = true; foreach (var item in sortedItems) { if (!firstItem) { htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.Hr); htmlTextWriter.RenderEndTag(); } htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.Div); htmlTextWriter.AddAttribute(HtmlTextWriterAttribute.Href, item.Link); htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.A); htmlTextWriter.Write(item.Title.Length == 0 ? item.Link : item.Title); htmlTextWriter.RenderEndTag(); htmlTextWriter.RenderBeginTag(HtmlTextWriterTag.Br); htmlTextWriter.RenderEndTag(); htmlTextWriter.Write(item.Description); htmlTextWriter.RenderEndTag(); firstItem = false; } htmlTextWriter.RenderEndTag(); htmlTextWriter.RenderEndTag(); } textWriter.Flush(); textWriter.Close(); BrowserCommon.OpenLink(fileName); MarkAllItemsAsRead(); } #endregion private void HandleNewVersionLinkClick(object sender, RoutedEventArgs e) { // Display update information VersionCheck.DisplayUpdateInformation(true); } } }