More UI updates and cleanup

This commit is contained in:
2023-04-26 21:57:19 -04:00
parent edd01cc052
commit 7638d9c2c7
20 changed files with 225 additions and 273 deletions

View File

@@ -185,10 +185,7 @@ public static class LegacyDatabase
{ {
foreach (var category in categories) foreach (var category in categories)
{ {
if (category.Name == Category.DefaultName) category.IsDefault = category.Name == Category.DefaultName;
category.IsDefault = true;
category.Feeds = feeds.Where(f => f.CategoryId == category.Id).ToList();
} }
foreach (var feed in feeds) foreach (var feed in feeds)

View File

@@ -101,5 +101,6 @@
xcopy /s /y /i "$(PkgMicrosoft_SqlServer_Compact)\NativeBinaries\amd64\*.*" "$(TargetDir)amd64" xcopy /s /y /i "$(PkgMicrosoft_SqlServer_Compact)\NativeBinaries\amd64\*.*" "$(TargetDir)amd64"
</PostBuildEvent> </PostBuildEvent>
<ApplicationIcon>Resources\Application.ico</ApplicationIcon> <ApplicationIcon>Resources\Application.ico</ApplicationIcon>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
</Project> </Project>

View File

@@ -5,34 +5,15 @@ using System.Xml;
namespace FeedCenter.FeedParsers; namespace FeedCenter.FeedParsers;
[Serializable]
internal class InvalidFeedFormatException : ApplicationException
{
internal InvalidFeedFormatException(Exception exception)
: base(string.Empty, exception)
{
}
}
internal abstract class FeedParserBase internal abstract class FeedParserBase
{ {
#region Member variables
protected readonly Feed Feed; protected readonly Feed Feed;
#endregion
#region Constructor
protected FeedParserBase(Feed feed) protected FeedParserBase(Feed feed)
{ {
Feed = feed; Feed = feed;
} }
#endregion
#region Methods
public abstract FeedReadResult ParseFeed(string feedText); public abstract FeedReadResult ParseFeed(string feedText);
protected abstract FeedItem ParseFeedItem(XmlNode node); protected abstract FeedItem ParseFeedItem(XmlNode node);
@@ -57,9 +38,6 @@ internal abstract class FeedParserBase
{ {
Log.Logger.Information("New link: " + newFeedItem.Link); Log.Logger.Information("New link: " + newFeedItem.Link);
// Associate the new item with the right feed
newFeedItem.Feed = Feed;
// Set the item as new // Set the item as new
newFeedItem.New = true; newFeedItem.New = true;
@@ -96,10 +74,6 @@ internal abstract class FeedParserBase
sequence++; sequence++;
} }
#endregion
#region Parser creation and detection
public static FeedParserBase CreateFeedParser(Feed feed, string feedText) public static FeedParserBase CreateFeedParser(Feed feed, string feedText)
{ {
var feedType = DetectFeedType(feedText); var feedType = DetectFeedType(feedText);
@@ -155,6 +129,4 @@ internal abstract class FeedParserBase
throw new FeedParseException(FeedParseError.InvalidXml); throw new FeedParseException(FeedParseError.InvalidXml);
} }
} }
#endregion
} }

View File

@@ -0,0 +1,12 @@
using System;
namespace FeedCenter.FeedParsers;
[Serializable]
internal class InvalidFeedFormatException : ApplicationException
{
internal InvalidFeedFormatException(Exception exception)
: base(string.Empty, exception)
{
}
}

View File

@@ -1,10 +1,9 @@
using System; using JetBrains.Annotations;
using Realms;
using System;
using System.Collections; using System.Collections;
using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Linq; using System.Linq;
using JetBrains.Annotations;
using Realms;
namespace FeedCenter; namespace FeedCenter;
@@ -20,9 +19,6 @@ public class Category : RealmObject, INotifyDataErrorInfo
_dataErrorDictionary.ErrorsChanged += DataErrorDictionaryErrorsChanged; _dataErrorDictionary.ErrorsChanged += DataErrorDictionaryErrorsChanged;
} }
[Ignored]
public ICollection<Feed> Feeds { get; set; }
[PrimaryKey] [PrimaryKey]
public Guid Id { get; set; } = Guid.NewGuid(); public Guid Id { get; set; } = Guid.NewGuid();

View File

@@ -22,42 +22,6 @@ using System.Text.RegularExpressions;
namespace FeedCenter; namespace FeedCenter;
#region Enumerations
public enum MultipleOpenAction
{
IndividualPages,
SinglePage
}
public enum FeedType
{
Unknown,
Rss,
Rdf,
Atom
}
public enum FeedReadResult
{
Success,
NotModified,
NotDue,
UnknownError,
InvalidXml,
NotEnabled,
Unauthorized,
NoResponse,
NotFound,
Timeout,
ConnectionFailed,
ServerError,
Moved,
TemporarilyUnavailable
}
#endregion
public partial class Feed : RealmObject, INotifyDataErrorInfo public partial class Feed : RealmObject, INotifyDataErrorInfo
{ {
private static HttpClient _httpClient; private static HttpClient _httpClient;
@@ -71,9 +35,7 @@ public partial class Feed : RealmObject, INotifyDataErrorInfo
} }
public bool Authenticate { get; set; } public bool Authenticate { get; set; }
public Guid CategoryId { get; set; } public Guid CategoryId { get; set; }
public int CheckInterval { get; set; } = 60; public int CheckInterval { get; set; } = 60;
public string Description { get; set; } public string Description { get; set; }
public bool Enabled { get; set; } = true; public bool Enabled { get; set; } = true;
@@ -225,8 +187,6 @@ public partial class Feed : RealmObject, INotifyDataErrorInfo
_dataErrorDictionary.AddError(propertyName, $"{propertyName} cannot be empty"); _dataErrorDictionary.AddError(propertyName, $"{propertyName} cannot be empty");
} }
#region Reading
public FeedReadResult Read(bool forceRead = false) public FeedReadResult Read(bool forceRead = false)
{ {
Log.Logger.Information("Reading feed: {0}", Source); Log.Logger.Information("Reading feed: {0}", Source);
@@ -494,6 +454,4 @@ public partial class Feed : RealmObject, INotifyDataErrorInfo
[GeneratedRegex("&(?!(?:[a-z]+|#[0-9]+|#x[0-9a-f]+);)")] [GeneratedRegex("&(?!(?:[a-z]+|#[0-9]+|#x[0-9a-f]+);)")]
private static partial Regex UnescapedAmpersandRegex(); private static partial Regex UnescapedAmpersandRegex();
#endregion
} }

View File

@@ -9,9 +9,6 @@ public partial class FeedItem : RealmObject
{ {
public bool BeenRead { get; set; } public bool BeenRead { get; set; }
public string Description { get; set; } public string Description { get; set; }
public Feed Feed { get; set; }
public Guid FeedId { get; set; } public Guid FeedId { get; set; }
public string Guid { get; set; } public string Guid { get; set; }
@@ -22,7 +19,6 @@ public partial class FeedItem : RealmObject
public string Link { get; set; } public string Link { get; set; }
public bool New { get; set; } public bool New { get; set; }
public int Sequence { get; set; } public int Sequence { get; set; }
public string Title { get; set; } public string Title { get; set; }
public static FeedItem Create() public static FeedItem Create()

View File

@@ -0,0 +1,19 @@
namespace FeedCenter;
public enum FeedReadResult
{
Success,
NotModified,
NotDue,
UnknownError,
InvalidXml,
NotEnabled,
Unauthorized,
NoResponse,
NotFound,
Timeout,
ConnectionFailed,
ServerError,
Moved,
TemporarilyUnavailable
}

View File

@@ -0,0 +1,9 @@
namespace FeedCenter;
public enum FeedType
{
Unknown,
Rss,
Rdf,
Atom
}

View File

@@ -0,0 +1,7 @@
namespace FeedCenter;
public enum MultipleOpenAction
{
IndividualPages,
SinglePage
}

View File

@@ -72,7 +72,7 @@ public partial class MainWindow
// If the category changed then reset the current feed to the first in the category // If the category changed then reset the current feed to the first in the category
if (_currentCategory?.Id != category?.Id) if (_currentCategory?.Id != category?.Id)
{ {
_currentFeed = category == null ? _database.Feeds.FirstOrDefault() : category.Feeds.FirstOrDefault(); _currentFeed = category == null ? _database.Feeds.FirstOrDefault() : _database.Feeds.FirstOrDefault(f => f.CategoryId == category.Id);
} }
// Set the current category // Set the current category

View File

@@ -104,8 +104,6 @@ public partial class MainWindow : IDisposable
HandleCommandLine(commandLine); HandleCommandLine(commandLine);
} }
#region Setting events
private void HandlePropertyChanged(object sender, PropertyChangedEventArgs e) private void HandlePropertyChanged(object sender, PropertyChangedEventArgs e)
{ {
// Make sure we're on the right thread // Make sure we're on the right thread
@@ -147,10 +145,6 @@ public partial class MainWindow : IDisposable
} }
} }
#endregion
#region Database helpers
private void ResetDatabase() private void ResetDatabase()
{ {
// Get the ID of the current feed // Get the ID of the current feed
@@ -191,10 +185,6 @@ public partial class MainWindow : IDisposable
: _feedList.OrderBy(feed => feed.Name).AsEnumerable().ElementAt(_feedIndex); : _feedList.OrderBy(feed => feed.Name).AsEnumerable().ElementAt(_feedIndex);
} }
#endregion
#region Feed display
private void UpdateToolbarButtonState() private void UpdateToolbarButtonState()
{ {
// Cache the feed count to save (a little) time // Cache the feed count to save (a little) time
@@ -429,6 +419,4 @@ public partial class MainWindow : IDisposable
// Clear the list // Clear the list
LinkTextList.Items.Clear(); LinkTextList.Items.Clear();
} }
#endregion
} }

View File

@@ -7,34 +7,41 @@
xmlns:my="clr-namespace:FeedCenter.Properties" xmlns:my="clr-namespace:FeedCenter.Properties"
xmlns:feedCenter="clr-namespace:FeedCenter" xmlns:feedCenter="clr-namespace:FeedCenter"
xmlns:controls="clr-namespace:ChrisKaczor.Wpf.Controls;assembly=ChrisKaczor.Wpf.Controls.Link" xmlns:controls="clr-namespace:ChrisKaczor.Wpf.Controls;assembly=ChrisKaczor.Wpf.Controls.Link"
xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
xmlns:options="clr-namespace:FeedCenter.Options"
WindowStartupLocation="CenterOwner" WindowStartupLocation="CenterOwner"
Icon="/FeedCenter;component/Resources/Application.ico" Icon="/FeedCenter;component/Resources/Application.ico"
FocusManager.FocusedElement="{Binding ElementName=FeedLinkFilterText}"> FocusManager.FocusedElement="{Binding ElementName=FeedLinkFilterText}">
<Grid> <Window.Resources>
<Grid.ColumnDefinitions> <ResourceDictionary>
<ColumnDefinition Width="Auto" /> <ResourceDictionary.MergedDictionaries>
<ColumnDefinition Width="*" /> <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
</Grid.ColumnDefinitions> <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.FlatButton.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Themes/light.cobalt.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid Margin="6">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="*" /> <RowDefinition Height="*" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Label Content="{x:Static my:Resources.FeedLinkFilterLabel}" <Grid.ColumnDefinitions>
Margin="6" <ColumnDefinition Width="*" />
Padding="0" </Grid.ColumnDefinitions>
VerticalContentAlignment="Center"
Target="{Binding ElementName=FeedLinkFilterText}" />
<TextBox Grid.Row="0" <TextBox Grid.Row="0"
Grid.Column="1" Grid.Column="0"
mah:TextBoxHelper.UseFloatingWatermark="True"
mah:TextBoxHelper.Watermark="{x:Static my:Resources.FeedLinkFilterLabel}"
mah:TextBoxHelper.SelectAllOnFocus="True"
Name="FeedLinkFilterText" Name="FeedLinkFilterText"
Margin="6"
TextChanged="HandleFilterTextChanged" /> TextChanged="HandleFilterTextChanged" />
<Border Grid.Row="1" <Border Grid.Row="1"
Grid.ColumnSpan="2"
Grid.Column="0" Grid.Column="0"
Margin="6" Margin="0,6"
BorderThickness="1" BorderThickness="1"
BorderBrush="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}"> BorderBrush="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}">
<Grid> <Grid>
@@ -45,9 +52,9 @@
<ScrollViewer VerticalScrollBarVisibility="Auto"> <ScrollViewer VerticalScrollBarVisibility="Auto">
<ItemsControl Name="FilteredFeedsList"> <ItemsControl Name="FilteredFeedsList">
<ItemsControl.ItemTemplate> <ItemsControl.ItemTemplate>
<DataTemplate> <DataTemplate DataType="options:CheckedFeedListItem">
<CheckBox Margin="2" <CheckBox Content="{Binding Item.Name}"
Content="{Binding Item.Name}" Margin="4"
IsChecked="{Binding IsChecked}" /> IsChecked="{Binding IsChecked}" />
</DataTemplate> </DataTemplate>
</ItemsControl.ItemTemplate> </ItemsControl.ItemTemplate>
@@ -58,18 +65,17 @@
BorderBrush="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}"> BorderBrush="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}">
<StackPanel Orientation="Horizontal" <StackPanel Orientation="Horizontal"
Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"> Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}">
<TextBlock Margin="2" <TextBlock Margin="4,2,2,2"
Text="{x:Static my:Resources.SelectLabel}"> Text="{x:Static my:Resources.SelectLabel}" />
</TextBlock> <controls:Link Margin="2,2,4,2"
<controls:Link Margin="2"
Click="HandleSelectAll" Click="HandleSelectAll"
Text="{x:Static my:Resources.SelectAllLabel}"> Text="{x:Static my:Resources.SelectAllLabel}">
</controls:Link> </controls:Link>
<controls:Link Margin="2" <controls:Link Margin="2,2,4,2"
Click="HandleSelectNone" Click="HandleSelectNone"
Text="{x:Static my:Resources.SelectNoneLabel}"> Text="{x:Static my:Resources.SelectNoneLabel}">
</controls:Link> </controls:Link>
<controls:Link Margin="2" <controls:Link Margin="2,2,4,2"
Click="HandleSelectInvert" Click="HandleSelectInvert"
Text="{x:Static my:Resources.SelectInvertLabel}"> Text="{x:Static my:Resources.SelectInvertLabel}">
</controls:Link> </controls:Link>
@@ -77,51 +83,44 @@
</Border> </Border>
</Grid> </Grid>
</Border> </Border>
<Grid Grid.Row="2" <Grid Grid.Column="0"
Grid.Column="0" Grid.Row="2">
MouseRightButtonUp="HandleGridMouseRightButtonUp" <Grid.ColumnDefinitions>
ToolTip="{x:Static my:Resources.EnableHint}"> <ColumnDefinition Width="Auto" />
<Label Content="{x:Static my:Resources.openLabel}" <ColumnDefinition Width="*" />
Name="OpenLabel" </Grid.ColumnDefinitions>
Padding="4,0,0,0" <CheckBox Name="OpenCheckBox"
Margin="6,8,6,6" Grid.Column="0" />
ToolTip="{x:Static my:Resources.DisableHint}"
IsEnabled="False" />
</Grid>
<Grid Grid.Column="1"
Grid.Row="2"
MouseRightButtonUp="HandleGridMouseRightButtonUp"
ToolTip="{x:Static my:Resources.EnableHint}">
<ComboBox Name="OpenComboBox" <ComboBox Name="OpenComboBox"
VerticalContentAlignment="Center" Grid.Column="1"
SelectedIndex="0" SelectedIndex="0"
Margin="6" HorizontalContentAlignment="Stretch"
ToolTip="{x:Static my:Resources.DisableHint}" mah:TextBoxHelper.UseFloatingWatermark="True"
IsEnabled="False"> mah:TextBoxHelper.Watermark="{x:Static my:Resources.openLabel}"
IsEnabled="{Binding ElementName=OpenCheckBox, Path=IsChecked}">
<ComboBoxItem Content="{x:Static my:Resources.openAllMultipleToolbarButton}" <ComboBoxItem Content="{x:Static my:Resources.openAllMultipleToolbarButton}"
Tag="{x:Static feedCenter:MultipleOpenAction.IndividualPages}" /> Tag="{x:Static feedCenter:MultipleOpenAction.IndividualPages}" />
<ComboBoxItem Content="{x:Static my:Resources.openAllSingleToolbarButton}" <ComboBoxItem Content="{x:Static my:Resources.openAllSingleToolbarButton}"
Tag="{x:Static feedCenter:MultipleOpenAction.SinglePage}" /> Tag="{x:Static feedCenter:MultipleOpenAction.SinglePage}" />
</ComboBox> </ComboBox>
</Grid> </Grid>
<Button Content="{x:Static my:Resources.OkayButton}" <StackPanel Grid.Column="0"
Height="23" Grid.Row="3"
HorizontalAlignment="Right" Orientation="Horizontal"
IsDefault="True" Margin="0,5,0,0"
Margin="0,6,87,6" HorizontalAlignment="Right">
VerticalAlignment="Bottom" <Button Content="{x:Static my:Resources.OkayButton}"
Width="75" HorizontalAlignment="Right"
Grid.Column="1" VerticalAlignment="Bottom"
Grid.Row="3" Width="75"
Click="HandleOkButtonClick" /> Margin="0,0,5,0"
<Button Content="{x:Static my:Resources.CancelButton}" IsDefault="True"
Grid.Column="1" Click="HandleOkButtonClick" />
Height="23" <Button Content="{x:Static my:Resources.CancelButton}"
HorizontalAlignment="Right" HorizontalAlignment="Right"
IsCancel="True" VerticalAlignment="Bottom"
Margin="0,6,6,6" Width="75"
VerticalAlignment="Bottom" IsCancel="True" />
Width="75" </StackPanel>
Grid.Row="3" />
</Grid> </Grid>
</Window> </Window>

View File

@@ -1,10 +1,10 @@
using System.Collections.Generic; using FeedCenter.Data;
using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Data; using System.Windows.Data;
using FeedCenter.Data;
namespace FeedCenter.Options; namespace FeedCenter.Options;
@@ -52,11 +52,14 @@ public partial class BulkFeedWindow
private void HandleOkButtonClick(object sender, RoutedEventArgs e) private void HandleOkButtonClick(object sender, RoutedEventArgs e)
{ {
foreach (var item in _checkedListBoxItems.Where(i => i.IsChecked)) Database.Entities.SaveChanges(() =>
{ {
if (OpenComboBox.IsEnabled) foreach (var item in _checkedListBoxItems.Where(i => i.IsChecked))
item.Item.MultipleOpenAction = (MultipleOpenAction) ((ComboBoxItem) OpenComboBox.SelectedItem).Tag; {
} if (OpenComboBox.IsEnabled)
item.Item.MultipleOpenAction = (MultipleOpenAction) ((ComboBoxItem) OpenComboBox.SelectedItem).Tag;
}
});
DialogResult = true; DialogResult = true;
Close(); Close();
@@ -91,10 +94,4 @@ public partial class BulkFeedWindow
checkedListItem.IsChecked = !checkedListItem.IsChecked; checkedListItem.IsChecked = !checkedListItem.IsChecked;
} }
} }
private void HandleGridMouseRightButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
OpenLabel.IsEnabled = !OpenLabel.IsEnabled;
OpenComboBox.IsEnabled = !OpenComboBox.IsEnabled;
}
} }

View File

@@ -0,0 +1,6 @@
namespace FeedCenter.Options
{
public class CheckedFeedListItem : CheckedListItem<Feed>
{
}
}

View File

@@ -10,6 +10,16 @@
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="311" d:DesignHeight="311"
d:DesignWidth="425"> d:DesignWidth="425">
<options:OptionsPanelBase.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.FlatButton.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Themes/light.cobalt.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</options:OptionsPanelBase.Resources>
<Grid> <Grid>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="*" /> <RowDefinition Height="*" />
@@ -20,41 +30,11 @@
<ColumnDefinition Width="5" /> <ColumnDefinition Width="5" />
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<DataGrid Name="FeedListBox" <DataGrid Name="CategoryDataGrid"
SelectionMode="Extended" SelectionChanged="HandleCategoryDataGridSelectionChanged"
Grid.Column="2"
Grid.Row="0"
AutoGenerateColumns="False"
GridLinesVisibility="None"
CanUserResizeRows="False"
IsReadOnly="True"
HeadersVisibility="Column"
BorderThickness="1,1,1,1"
BorderBrush="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}"
Background="{x:Null}"
PreviewMouseLeftButtonDown="HandleFeedListPreviewMouseLeftButtonDown" SelectionChanged="FeedListBox_SelectionChanged">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}"
Header="{x:Static properties:Resources.FeedNameColumnHeader}"
SortDirection="Ascending"
Width="*" />
<DataGridTextColumn Binding="{Binding LastUpdated, StringFormat=d}"
Header="{x:Static properties:Resources.LastUpdatedColumnHeader}"
Width="Auto" />
</DataGrid.Columns>
<DataGrid.ItemContainerStyle>
<Style TargetType="DataGridRow">
<EventSetter Event="MouseDoubleClick"
Handler="HandleListBoxItemMouseDoubleClick" />
<EventSetter Event="PreviewMouseMove"
Handler="HandleListBoxItemPreviewMouseMove" />
</Style>
</DataGrid.ItemContainerStyle>
</DataGrid>
<DataGrid Name="CategoryListBox"
SelectionChanged="HandleCategoryListBoxSelectionChanged"
Grid.Row="0" Grid.Row="0"
SelectionMode="Single" SelectionMode="Single"
SelectionUnit="FullRow"
Grid.Column="0" Grid.Column="0"
AutoGenerateColumns="False" AutoGenerateColumns="False"
GridLinesVisibility="None" GridLinesVisibility="None"
@@ -64,26 +44,61 @@
BorderThickness="1,1,1,1" BorderThickness="1,1,1,1"
BorderBrush="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}" BorderBrush="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}"
AllowDrop="True" AllowDrop="True"
Background="{x:Null}" Background="{x:Null}"
d:DataContext="{d:DesignInstance Type=feedCenter:Category }"> d:DataContext="{d:DesignInstance feedCenter:Category }">
<DataGrid.Columns> <DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}" <DataGridTextColumn Binding="{Binding Name}"
Header="{x:Static properties:Resources.CategoryNameColumnHeader}" Header="{x:Static properties:Resources.CategoryNameColumnHeader}"
SortDirection="Ascending" SortDirection="Ascending"
Width="*" /> Width="*" />
</DataGrid.Columns> </DataGrid.Columns>
<DataGrid.ItemContainerStyle> <DataGrid.RowStyle>
<Style TargetType="DataGridRow"> <Style TargetType="DataGridRow"
BasedOn="{StaticResource MahApps.Styles.DataGridRow}">
<EventSetter Event="Drop" <EventSetter Event="Drop"
Handler="CategoryListBox_Drop" /> Handler="HandleCategoryDataGridRowDrop" />
<EventSetter Event="DragEnter" <EventSetter Event="DragEnter"
Handler="CategoryListBox_DragEnter" /> Handler="HandleCategoryDataGridRowDragEnter" />
<EventSetter Event="DragLeave" <EventSetter Event="DragLeave"
Handler="CategoryListBox_DragLeave" /> Handler="HandleCategoryDataGridRowDragLeave" />
<EventSetter Event="MouseDoubleClick" <EventSetter Event="MouseDoubleClick"
Handler="CategoryListBox_MouseDoubleClick" /> Handler="HandleCategoryDataGridRowMouseDoubleClick" />
</Style> </Style>
</DataGrid.ItemContainerStyle> </DataGrid.RowStyle>
</DataGrid>
<DataGrid Name="FeedDataGrid"
SelectionMode="Extended"
Grid.Column="2"
Grid.Row="0"
AutoGenerateColumns="False"
GridLinesVisibility="None"
CanUserResizeRows="False"
IsReadOnly="True"
SelectionUnit="FullRow"
HeadersVisibility="Column"
BorderThickness="1,1,1,1"
BorderBrush="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}"
Background="{x:Null}"
SelectionChanged="HandleFeedDataGridSelectionChanged"
d:DataContext="{d:DesignInstance feedCenter:Feed }">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}"
Header="{x:Static properties:Resources.FeedNameColumnHeader}"
SortDirection="Ascending"
Width="*" />
<DataGridTextColumn Binding="{Binding LastUpdated, StringFormat=d}"
Header="{x:Static properties:Resources.LastUpdatedColumnHeader}"
Width="Auto" />
</DataGrid.Columns>
<DataGrid.RowStyle>
<Style TargetType="DataGridRow"
BasedOn="{StaticResource MahApps.Styles.DataGridRow}">
<EventSetter Event="MouseDoubleClick"
Handler="HandleFeedDataGridRowMouseDoubleClick" />
<EventSetter Event="PreviewMouseLeftButtonDown"
Handler="HandleFeedDataGridRowPreviewMouseLeftButtonDown" />
</Style>
</DataGrid.RowStyle>
</DataGrid> </DataGrid>
<Border Grid.Column="2" <Border Grid.Column="2"
Grid.Row="1" Grid.Row="1"

View File

@@ -1,4 +1,6 @@
using System.Collections.Generic; using FeedCenter.Data;
using Microsoft.Win32;
using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Windows; using System.Windows;
@@ -6,8 +8,6 @@ using System.Windows.Controls;
using System.Windows.Data; using System.Windows.Data;
using System.Windows.Input; using System.Windows.Input;
using System.Xml; using System.Xml;
using FeedCenter.Data;
using Microsoft.Win32;
namespace FeedCenter.Options; namespace FeedCenter.Options;
@@ -31,22 +31,22 @@ public partial class FeedsOptionsPanel
collectionViewSource.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending)); collectionViewSource.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
collectionViewSource.IsLiveSortingRequested = true; collectionViewSource.IsLiveSortingRequested = true;
CategoryListBox.ItemsSource = collectionViewSource.View; CategoryDataGrid.ItemsSource = collectionViewSource.View;
CategoryListBox.SelectedIndex = 0; CategoryDataGrid.SelectedIndex = 0;
} }
private void SetFeedButtonStates() private void SetFeedButtonStates()
{ {
AddFeedButton.IsEnabled = true; AddFeedButton.IsEnabled = true;
EditFeedButton.IsEnabled = FeedListBox.SelectedItems.Count == 1; EditFeedButton.IsEnabled = FeedDataGrid.SelectedItems.Count == 1;
DeleteFeedButton.IsEnabled = FeedListBox.SelectedItems.Count > 0; DeleteFeedButton.IsEnabled = FeedDataGrid.SelectedItems.Count > 0;
} }
private void AddFeed() private void AddFeed()
{ {
var feed = Feed.Create(); var feed = Feed.Create();
var category = (Category) CategoryListBox.SelectedItem; var category = (Category) CategoryDataGrid.SelectedItem;
feed.CategoryId = category.Id; feed.CategoryId = category.Id;
@@ -59,17 +59,17 @@ public partial class FeedsOptionsPanel
Database.Entities.SaveChanges(() => Database.Entities.Feeds.Add(feed)); Database.Entities.SaveChanges(() => Database.Entities.Feeds.Add(feed));
FeedListBox.SelectedItem = feed; FeedDataGrid.SelectedItem = feed;
SetFeedButtonStates(); SetFeedButtonStates();
} }
private void EditSelectedFeed() private void EditSelectedFeed()
{ {
if (FeedListBox.SelectedItem == null) if (FeedDataGrid.SelectedItem == null)
return; return;
var feed = (Feed) FeedListBox.SelectedItem; var feed = (Feed) FeedDataGrid.SelectedItem;
var feedWindow = new FeedWindow(); var feedWindow = new FeedWindow();
@@ -81,9 +81,9 @@ public partial class FeedsOptionsPanel
if (MessageBox.Show(ParentWindow, Properties.Resources.ConfirmDeleteFeeds, Properties.Resources.ConfirmDeleteTitle, MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No) == MessageBoxResult.No) if (MessageBox.Show(ParentWindow, Properties.Resources.ConfirmDeleteFeeds, Properties.Resources.ConfirmDeleteTitle, MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No) == MessageBoxResult.No)
return; return;
var selectedItems = new Feed[FeedListBox.SelectedItems.Count]; var selectedItems = new Feed[FeedDataGrid.SelectedItems.Count];
FeedListBox.SelectedItems.CopyTo(selectedItems, 0); FeedDataGrid.SelectedItems.CopyTo(selectedItems, 0);
foreach (var feed in selectedItems) foreach (var feed in selectedItems)
Database.Entities.SaveChanges(() => Database.Entities.Feeds.Remove(feed)); Database.Entities.SaveChanges(() => Database.Entities.Feeds.Remove(feed));
@@ -239,11 +239,11 @@ public partial class FeedsOptionsPanel
{ {
AddCategoryButton.IsEnabled = true; AddCategoryButton.IsEnabled = true;
var selectedId = ((Category) CategoryListBox.SelectedItem).Id; var selectedId = ((Category) CategoryDataGrid.SelectedItem).Id;
EditCategoryButton.IsEnabled = CategoryListBox.SelectedItem != null && EditCategoryButton.IsEnabled = CategoryDataGrid.SelectedItem != null &&
selectedId != Database.Entities.DefaultCategory.Id; selectedId != Database.Entities.DefaultCategory.Id;
DeleteCategoryButton.IsEnabled = CategoryListBox.SelectedItem != null && DeleteCategoryButton.IsEnabled = CategoryDataGrid.SelectedItem != null &&
selectedId != Database.Entities.DefaultCategory.Id; selectedId != Database.Entities.DefaultCategory.Id;
} }
@@ -260,17 +260,17 @@ public partial class FeedsOptionsPanel
Database.Entities.SaveChanges(() => Database.Entities.Categories.Add(category)); Database.Entities.SaveChanges(() => Database.Entities.Categories.Add(category));
CategoryListBox.SelectedItem = category; CategoryDataGrid.SelectedItem = category;
SetCategoryButtonStates(); SetCategoryButtonStates();
} }
private void EditSelectedCategory() private void EditSelectedCategory()
{ {
if (CategoryListBox.SelectedItem == null) if (CategoryDataGrid.SelectedItem == null)
return; return;
var category = (Category) CategoryListBox.SelectedItem; var category = (Category) CategoryDataGrid.SelectedItem;
var categoryWindow = new CategoryWindow(); var categoryWindow = new CategoryWindow();
@@ -279,7 +279,7 @@ public partial class FeedsOptionsPanel
private void DeleteSelectedCategory() private void DeleteSelectedCategory()
{ {
var category = (Category) CategoryListBox.SelectedItem; var category = (Category) CategoryDataGrid.SelectedItem;
if (MessageBox.Show(ParentWindow, string.Format(Properties.Resources.ConfirmDeleteCategory, category.Name), Properties.Resources.ConfirmDeleteTitle, MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No) == MessageBoxResult.No) if (MessageBox.Show(ParentWindow, string.Format(Properties.Resources.ConfirmDeleteCategory, category.Name), Properties.Resources.ConfirmDeleteTitle, MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No) == MessageBoxResult.No)
return; return;
@@ -289,12 +289,12 @@ public partial class FeedsOptionsPanel
foreach (var feed in Database.Entities.Feeds.Where(f => f.CategoryId == category.Id)) foreach (var feed in Database.Entities.Feeds.Where(f => f.CategoryId == category.Id))
Database.Entities.SaveChanges(() => feed.CategoryId = defaultCategory.Id); Database.Entities.SaveChanges(() => feed.CategoryId = defaultCategory.Id);
var index = CategoryListBox.SelectedIndex; var index = CategoryDataGrid.SelectedIndex;
if (index == CategoryListBox.Items.Count - 1) if (index == CategoryDataGrid.Items.Count - 1)
CategoryListBox.SelectedIndex = index - 1; CategoryDataGrid.SelectedIndex = index - 1;
else else
CategoryListBox.SelectedIndex = index + 1; CategoryDataGrid.SelectedIndex = index + 1;
Database.Entities.SaveChanges(() => Database.Entities.Categories.Remove(category)); Database.Entities.SaveChanges(() => Database.Entities.Categories.Remove(category));
@@ -316,7 +316,7 @@ public partial class FeedsOptionsPanel
DeleteSelectedCategory(); DeleteSelectedCategory();
} }
private void HandleCategoryListBoxSelectionChanged(object sender, SelectionChangedEventArgs e) private void HandleCategoryDataGridSelectionChanged(object sender, SelectionChangedEventArgs e)
{ {
if (_collectionViewSource == null) if (_collectionViewSource == null)
{ {
@@ -324,13 +324,13 @@ public partial class FeedsOptionsPanel
_collectionViewSource.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending)); _collectionViewSource.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
_collectionViewSource.Filter += HandleCollectionViewSourceFilter; _collectionViewSource.Filter += HandleCollectionViewSourceFilter;
FeedListBox.ItemsSource = _collectionViewSource.View; FeedDataGrid.ItemsSource = _collectionViewSource.View;
} }
_collectionViewSource.View.Refresh(); _collectionViewSource.View.Refresh();
if (FeedListBox.Items.Count > 0) if (FeedDataGrid.Items.Count > 0)
FeedListBox.SelectedIndex = 0; FeedDataGrid.SelectedIndex = 0;
SetFeedButtonStates(); SetFeedButtonStates();
SetCategoryButtonStates(); SetCategoryButtonStates();
@@ -338,14 +338,14 @@ public partial class FeedsOptionsPanel
private void HandleCollectionViewSourceFilter(object sender, FilterEventArgs e) private void HandleCollectionViewSourceFilter(object sender, FilterEventArgs e)
{ {
var selectedCategory = (Category) CategoryListBox.SelectedItem; var selectedCategory = (Category) CategoryDataGrid.SelectedItem;
var feed = (Feed) e.Item; var feed = (Feed) e.Item;
e.Accepted = feed.CategoryId == selectedCategory.Id; e.Accepted = feed.CategoryId == selectedCategory.Id;
} }
private void CategoryListBox_Drop(object sender, DragEventArgs e) private void HandleCategoryDataGridRowDrop(object sender, DragEventArgs e)
{ {
var feedList = (List<Feed>) e.Data.GetData(typeof(List<Feed>)); var feedList = (List<Feed>) e.Data.GetData(typeof(List<Feed>));
@@ -361,31 +361,21 @@ public partial class FeedsOptionsPanel
dataGridRow.FontWeight = FontWeights.Normal; dataGridRow.FontWeight = FontWeights.Normal;
} }
private void HandleListBoxItemPreviewMouseMove(object sender, MouseEventArgs e) private void HandleCategoryDataGridRowDragEnter(object sender, DragEventArgs e)
{
if (e.LeftButton != MouseButtonState.Pressed)
return;
var selectedItems = FeedListBox.SelectedItems.Cast<Feed>().ToList();
DragDrop.DoDragDrop(FeedListBox, selectedItems, DragDropEffects.Move);
}
private void CategoryListBox_DragEnter(object sender, DragEventArgs e)
{ {
var dataGridRow = (DataGridRow) sender; var dataGridRow = (DataGridRow) sender;
dataGridRow.FontWeight = FontWeights.Bold; dataGridRow.FontWeight = FontWeights.Bold;
} }
private void CategoryListBox_DragLeave(object sender, DragEventArgs e) private void HandleCategoryDataGridRowDragLeave(object sender, DragEventArgs e)
{ {
var dataGridRow = (DataGridRow) sender; var dataGridRow = (DataGridRow) sender;
dataGridRow.FontWeight = FontWeights.Normal; dataGridRow.FontWeight = FontWeights.Normal;
} }
private void HandleListBoxItemMouseDoubleClick(object sender, MouseButtonEventArgs e) private void HandleFeedDataGridRowMouseDoubleClick(object sender, MouseButtonEventArgs e)
{ {
EditSelectedFeed(); EditSelectedFeed();
} }
@@ -396,20 +386,14 @@ public partial class FeedsOptionsPanel
bulkFeedWindow.Display(Window.GetWindow(this)); bulkFeedWindow.Display(Window.GetWindow(this));
} }
private void HandleFeedListPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) private void HandleFeedDataGridRowPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{ {
// Get the object that was clicked on var selectedItems = FeedDataGrid.SelectedItems.Cast<Feed>().ToList();
var originalSource = (DependencyObject) e.OriginalSource;
// Look for a row that contains the object DragDrop.DoDragDrop(FeedDataGrid, selectedItems, DragDropEffects.Move);
var dataGridRow = (DataGridRow) FeedListBox.ContainerFromElement(originalSource);
// If the selection already contains this row then ignore it
if (dataGridRow != null && FeedListBox.SelectedItems.Contains(dataGridRow.Item))
e.Handled = true;
} }
private void CategoryListBox_MouseDoubleClick(object sender, MouseButtonEventArgs e) private void HandleCategoryDataGridRowMouseDoubleClick(object sender, MouseButtonEventArgs e)
{ {
if (!EditCategoryButton.IsEnabled) if (!EditCategoryButton.IsEnabled)
return; return;
@@ -417,7 +401,7 @@ public partial class FeedsOptionsPanel
EditSelectedCategory(); EditSelectedCategory();
} }
private void FeedListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) private void HandleFeedDataGridSelectionChanged(object sender, SelectionChangedEventArgs e)
{ {
SetFeedButtonStates(); SetFeedButtonStates();
} }

View File

@@ -733,7 +733,7 @@ namespace FeedCenter.Properties {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to Feed _link contains:. /// Looks up a localized string similar to Feed link contains.
/// </summary> /// </summary>
public static string FeedLinkFilterLabel { public static string FeedLinkFilterLabel {
get { get {

View File

@@ -419,7 +419,7 @@
<value>Edit Multiple Feeds</value> <value>Edit Multiple Feeds</value>
</data> </data>
<data name="FeedLinkFilterLabel" xml:space="preserve"> <data name="FeedLinkFilterLabel" xml:space="preserve">
<value>Feed _link contains:</value> <value>Feed link contains</value>
</data> </data>
<data name="SelectAllLabel" xml:space="preserve"> <data name="SelectAllLabel" xml:space="preserve">
<value>All</value> <value>All</value>

View File

@@ -128,8 +128,6 @@ public class XmlSanitizingStream : StreamReader
return nextCharacter; return nextCharacter;
} // method } // method
#region Read*() method overrides
// The following methods are exact copies of the methods in TextReader, // The following methods are exact copies of the methods in TextReader,
// extracting by disassembling it in Reflector // extracting by disassembling it in Reflector
@@ -219,6 +217,4 @@ public class XmlSanitizingStream : StreamReader
return builder.ToString(); return builder.ToString();
} }
#endregion
} // class } // class