├── .config └── dotnet-tools.json ├── .editorconfig ├── .gitattributes ├── .github ├── CONTRIBUTING.md ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── ---support-request.md │ ├── --bug.md │ ├── --feature-request.md │ └── --thank-you.md ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml ├── lock.yml ├── stale.yml ├── support.yml └── workflows │ ├── build-and-test.yml │ └── dependabot-auto-merge.yml ├── .gitignore ├── AUTHORS ├── CONTRIBUTING.md ├── CONTRIBUTORS ├── GitReleaseManager.yaml ├── GitVersion.yml ├── LICENSE ├── README.md ├── build.cake ├── build.ps1 ├── cake.config ├── deployment └── cake │ ├── apps-uwp-tasks.cake │ ├── apps-uwp-variables.cake │ ├── apps-wpf-tasks.cake │ ├── apps-wpf-variables.cake │ ├── buildserver-continuaci.cake │ ├── buildserver.cake │ ├── codesigning-tasks.cake │ ├── codesigning-variables.cake │ ├── components-tasks.cake │ ├── components-variables.cake │ ├── dependencies-tasks.cake │ ├── dependencies-variables.cake │ ├── docker-tasks.cake │ ├── docker-variables.cake │ ├── generic-tasks.cake │ ├── generic-variables.cake │ ├── github-pages-tasks.cake │ ├── github-pages-variables.cake │ ├── installers-innosetup.cake │ ├── installers-msix.cake │ ├── installers-squirrel.cake │ ├── installers-velopack.cake │ ├── installers.cake │ ├── issuetrackers-github.cake │ ├── issuetrackers-jira.cake │ ├── issuetrackers.cake │ ├── lib-generic.cake │ ├── lib-logging.cake │ ├── lib-msbuild.cake │ ├── lib-nuget.cake │ ├── lib-signing.cake │ ├── lib-sourcelink.cake │ ├── notifications-msteams.cake │ ├── notifications.cake │ ├── sourcecontrol-github.cake │ ├── sourcecontrol.cake │ ├── tasks.cake │ ├── templates-tasks.cake │ ├── templates-variables.cake │ ├── tests-nunit.cake │ ├── tests-variables.cake │ ├── tests.cake │ ├── tools-tasks.cake │ ├── tools-variables.cake │ ├── vsextensions-tasks.cake │ └── vsextensions-variables.cake ├── design └── Package │ └── Icon.png ├── src ├── .vsconfig ├── Directory.Build.analyzers.props ├── Directory.Build.implicitusings.props ├── Directory.Build.nullable.props ├── Directory.Build.project.props ├── Directory.Build.props ├── Directory.Build.shared.explicit.props ├── Directory.Build.shared.implicit.props ├── Directory.Build.shared.mat.props ├── Directory.Build.shared.tests.props ├── Directory.Build.shared.tools.props ├── Directory.Build.shared.xamltools.props ├── Directory.Build.targets ├── GlobalSuppressions.cs ├── MethodTimeLogger.cs ├── Orc.FilterBuilder.Example │ ├── App.xaml │ ├── App.xaml.cs │ ├── FodyWeavers.xml │ ├── FontAwesome.cs │ ├── Models │ │ ├── Description.cs │ │ ├── MyEnum.cs │ │ └── TestEntity.cs │ ├── ModuleInitializer.cs │ ├── Orc.FilterBuilder.Example.csproj │ ├── Properties │ │ ├── AssemblyInfo.cs │ │ ├── Resources.Designer.cs │ │ └── Resources.resx │ ├── Resources │ │ └── Fonts │ │ │ └── fontawesome-webfont.ttf │ ├── Services │ │ ├── ApplicationInitializationService.cs │ │ ├── ExampleFilterSerializationService.cs │ │ ├── Interfaces │ │ │ └── ITestDataService.cs │ │ ├── RibbonService.cs │ │ └── TestDataService.cs │ ├── Themes │ │ └── Generic.xaml │ ├── ViewModels │ │ ├── MainViewModel.cs │ │ ├── RibbonViewModel.cs │ │ └── StatusBarViewModel.cs │ └── Views │ │ ├── MainView.xaml │ │ ├── MainView.xaml.cs │ │ ├── RibbonView.xaml │ │ ├── RibbonView.xaml.cs │ │ ├── StatusBarView.xaml │ │ └── StatusBarView.xaml.cs ├── Orc.FilterBuilder.Tests │ ├── ConditionsLinqExtensionsFacts.cs │ ├── Converters │ │ └── ObjectToValueConverterFacts.cs │ ├── Expressions │ │ └── EnumExpressionFacts.cs │ ├── Extensions │ │ └── ConditionsLinqExtentionsFacts.cs │ ├── FilterSchemeFacts.cs │ ├── FodyWeavers.xml │ ├── Helpers │ │ ├── AssemblyDirectoryHelper.cs │ │ └── FilterSchemeHelper.cs │ ├── Models │ │ └── TestFilterModel.cs │ ├── ModuleInitializer.cs │ ├── Orc.FilterBuilder.Tests.csproj │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── PublicApiFacts.Orc_FilterBuilder_HasNoBreakingChanges_Async.verified.txt │ ├── PublicApiFacts.Orc_FilterBuilder_Xaml_HasNoBreakingChanges_Async.verified.txt │ ├── PublicApiFacts.cs │ ├── Repros │ │ └── GH210.cs │ ├── Resources │ │ └── Files │ │ │ └── filters.xml │ ├── RuntimeMetadataFacts │ │ ├── AttributeTypeNames.cs │ │ ├── Helpers │ │ │ └── FilterSchemeInitializationHelper.cs │ │ ├── Metadata │ │ │ ├── TestFilterRuntimeModelMetadata.cs │ │ │ └── TestFilterRuntimeModelPropertyCollection.cs │ │ ├── Models │ │ │ ├── TestAttributeType.cs │ │ │ ├── TestAttributeValue.cs │ │ │ └── TestFilterRuntimeModel.cs │ │ ├── Provider │ │ │ ├── TestAttributeTypeProvider.cs │ │ │ └── TestDataProvider.cs │ │ ├── RuntimeMetadataFacts.cs │ │ └── Services │ │ │ └── TestFilterRuntimeModelReflectionService.cs │ ├── TemporaryFilesContext.cs │ └── UI │ │ ├── Asserters │ │ └── EditFilterViewAssert.cs │ │ ├── AutomationMethods │ │ └── InitViewModelMethodRun.cs │ │ ├── Base │ │ └── StyledControlTestFacts.cs │ │ ├── EditFilterViewFacts.cs │ │ ├── FilterBuilderControlFacts.cs │ │ ├── Fluent │ │ └── SplitButton │ │ │ ├── Models │ │ │ └── SplitButtonMap.cs │ │ │ └── SplitButton.cs │ │ ├── Mocks │ │ └── TestFilterSchemeManager.cs │ │ ├── Models │ │ └── TestEntity.cs │ │ └── TestData │ │ └── FilterBuilderControlTestData.cs ├── Orc.FilterBuilder.Xaml │ ├── Automation │ │ ├── Controls │ │ │ ├── EditFilterConditionTree │ │ │ │ ├── EditFilterConditionTree.cs │ │ │ │ ├── Factories │ │ │ │ │ └── EditFilterConditionTreeItemFactory.cs │ │ │ │ ├── Maps │ │ │ │ │ ├── EditFilterConditionGroupTreeItemMap.cs │ │ │ │ │ └── EditFilterPropertyConditionTreeItemMap.cs │ │ │ │ ├── Parts │ │ │ │ │ └── EditFilterPropertyValueEditorPart.cs │ │ │ │ └── TreeItems │ │ │ │ │ ├── Base │ │ │ │ │ └── EditFilterConditionTreeItemBase.cs │ │ │ │ │ ├── EditFilterConditionGroupTreeItem.cs │ │ │ │ │ └── EditFilterPropertyConditionTreeItem.cs │ │ │ ├── EditFilterView │ │ │ │ ├── EditFilterView.cs │ │ │ │ ├── Maps │ │ │ │ │ └── EditFilterViewMap.cs │ │ │ │ ├── Models │ │ │ │ │ └── EditFilterViewModel.cs │ │ │ │ └── Peers │ │ │ │ │ └── EditFilterViewPeer.cs │ │ │ └── FilterBuilderControl │ │ │ │ ├── FilterBuilderControl.cs │ │ │ │ ├── Maps │ │ │ │ └── FilterBuilderControlMap.cs │ │ │ │ ├── Models │ │ │ │ └── FilterBuilderControlModel.cs │ │ │ │ ├── Parts │ │ │ │ ├── EditFilterWindow │ │ │ │ │ ├── EditFilterWindow.cs │ │ │ │ │ └── Maps │ │ │ │ │ │ └── EditFilterWindowMap.cs │ │ │ │ └── FilterBuilderControlListItem │ │ │ │ │ ├── FilterBuilderControlListItem.cs │ │ │ │ │ └── Maps │ │ │ │ │ └── FilterBuilderControlListItemMap.cs │ │ │ │ └── Peers │ │ │ │ └── FilterBuilderControlPeer.cs │ │ ├── Extensions │ │ │ ├── EditFilterConditionGroupTreeItemExtensions.cs │ │ │ └── EditFilterViewExtensions.cs │ │ ├── Helpers │ │ │ └── FilterSchemeBuilder.cs │ │ └── SerializationConverters │ │ │ └── FilterSchemeEditInfoSerializationConverter.cs │ ├── Behaviors │ │ └── DisableSelectionInTreeView.cs │ ├── Converters │ │ ├── ConditionTreeItemConverter.cs │ │ ├── DataTypeExpressionToConditionsConverter.cs │ │ ├── EnsureDateTimeValueConverter.cs │ │ ├── EnsureTimeSpanValueConverter.cs │ │ ├── FilterResultMultiValueConverter.cs │ │ ├── IsCurrentFilterSchemeToCollapsingVisibilityConverter.cs │ │ ├── LeftMarginMultiplierConverter.cs │ │ ├── ObjectToValueConverter.cs │ │ ├── TriggerConverter.cs │ │ └── ValueControlTypeVisibilityConverter.cs │ ├── Extensions │ │ └── TreeViewItemExtensions.cs │ ├── FilterBuilderMode.cs │ ├── FodyWeavers.xml │ ├── Markup │ │ └── EnumBinding.cs │ ├── Models │ │ └── FilterGroup.cs │ ├── ModuleInitializer.cs │ ├── MultilingualResources │ │ ├── Orc.FilterBuilder.Xaml.de.xlf │ │ ├── Orc.FilterBuilder.Xaml.es.xlf │ │ ├── Orc.FilterBuilder.Xaml.fr.xlf │ │ ├── Orc.FilterBuilder.Xaml.nl.xlf │ │ ├── Orc.FilterBuilder.Xaml.ru.xlf │ │ └── Orc.FilterBuilder.Xaml.zh-Hans.xlf │ ├── Orc.FilterBuilder.Xaml.csproj │ ├── Properties │ │ ├── AssemblyInfo.cs │ │ ├── Resources.Designer.cs │ │ ├── Resources.de.resx │ │ ├── Resources.es.resx │ │ ├── Resources.fr.resx │ │ ├── Resources.nl.resx │ │ ├── Resources.resx │ │ ├── Resources.ru.resx │ │ └── Resources.zh-Hans.resx │ ├── Resources │ │ └── Images │ │ │ ├── add_expression.png │ │ │ ├── add_group.png │ │ │ ├── delete.png │ │ │ ├── edit.png │ │ │ ├── remove.png │ │ │ └── selected.png │ ├── Themes │ │ ├── Generic.xaml │ │ └── Geometry.xaml │ ├── ViewModels │ │ ├── EditFilterViewModel.cs │ │ └── FilterBuilderViewModel.cs │ └── Views │ │ ├── EditFilterView.xaml │ │ ├── EditFilterView.xaml.cs │ │ ├── EditFilterWindow.xaml │ │ ├── EditFilterWindow.xaml.cs │ │ ├── FilterBuilderControl.xaml │ │ └── FilterBuilderControl.xaml.cs ├── Orc.FilterBuilder.sln ├── Orc.FilterBuilder │ ├── Conditions │ │ ├── Condition.cs │ │ ├── ConditionGroup.cs │ │ ├── ConditionGroupType.cs │ │ ├── ConditionTreeItem.cs │ │ └── Helpers │ │ │ └── ConditionHelper.cs │ ├── Expressions │ │ ├── BooleanExpression.cs │ │ ├── ByteExpression.cs │ │ ├── DataTypeExpression.cs │ │ ├── DateTimeExpression.cs │ │ ├── DecimalExpression.cs │ │ ├── DoubleExpression.cs │ │ ├── EnumExpression.cs │ │ ├── FloatExpression.cs │ │ ├── IntegerExpression.cs │ │ ├── LongExpression.cs │ │ ├── NullableDataTypeExpression.cs │ │ ├── NumericExpression.cs │ │ ├── NumericExpression.generic.cs │ │ ├── PropertyExpression.cs │ │ ├── SByteExpression.cs │ │ ├── ShortExpression.cs │ │ ├── StringExpression.cs │ │ ├── TimeSpanExpression.cs │ │ ├── TimeSpanValueExpression.cs │ │ ├── UnsignedIntegerExpression.cs │ │ ├── UnsignedLongExpression.cs │ │ ├── UnsignedShortExpression.cs │ │ └── ValueDataTypeExpression.cs │ ├── Extensions │ │ ├── ConditionExtensions.cs │ │ ├── ConditionTreeItemExtensions.cs │ │ ├── ConditionsLinqExtensions.cs │ │ ├── FilterSchemeExtensions.cs │ │ ├── PropertyInfoExtensions.cs │ │ └── TypeExtensions.cs │ ├── FodyWeavers.xml │ ├── Helpers │ │ ├── CollectionHelper.cs │ │ ├── InstancePropertyHelper.cs │ │ └── RegexHelper.cs │ ├── Models │ │ ├── FilterScheme.cs │ │ ├── FilterSchemeEditInfo.cs │ │ ├── FilterSchemes.cs │ │ ├── InstanceProperties.cs │ │ ├── Interfaces │ │ │ ├── IPropertyCollection.cs │ │ │ └── IPropertyMetadata.cs │ │ └── PropertyMetadata.cs │ ├── ModuleInitializer.cs │ ├── MultilingualResources │ │ ├── Orc.FilterBuilder.de.xlf │ │ ├── Orc.FilterBuilder.es.xlf │ │ ├── Orc.FilterBuilder.fr.xlf │ │ ├── Orc.FilterBuilder.nl.xlf │ │ ├── Orc.FilterBuilder.ru.xlf │ │ └── Orc.FilterBuilder.zh-Hans.xlf │ ├── Orc.FilterBuilder.csproj │ ├── Properties │ │ ├── AssemblyInfo.cs │ │ ├── Resources.Designer.cs │ │ ├── Resources.de.resx │ │ ├── Resources.es.resx │ │ ├── Resources.fr.resx │ │ ├── Resources.nl.resx │ │ ├── Resources.resx │ │ ├── Resources.ru.resx │ │ └── Resources.zh-Hans.resx │ ├── Runtime │ │ └── Serialization │ │ │ ├── FilterSchemeSerializerModifier.cs │ │ │ └── PropertyExpressionSerializerModifier.cs │ ├── Services │ │ ├── Extensions │ │ │ └── IFilterServiceExtensions.cs │ │ ├── FilterCustomizationService.cs │ │ ├── FilterSchemeManager.cs │ │ ├── FilterSerializationService.cs │ │ ├── FilterService.cs │ │ ├── Interfaces │ │ │ ├── IFilterCustomizationService.cs │ │ │ ├── IFilterSchemeManager.cs │ │ │ ├── IFilterSerializationService.cs │ │ │ ├── IFilterService.cs │ │ │ └── IReflectionService.cs │ │ └── ReflectionService.cs │ ├── TimeSpanType.cs │ ├── Validators │ │ └── PropertyExpressionValidator.cs │ └── ValueControlType.cs ├── Settings.StyleCop ├── SolutionAssemblyInfo.cs ├── global.json └── nuget.config └── tools ├── TestHost ├── Orc.Automation.Host.deps.json ├── Orc.Automation.Host.dll ├── Orc.Automation.Host.dll.config ├── Orc.Automation.Host.exe ├── Orc.Automation.Host.pdb ├── Orc.Automation.Host.runtimeconfig.json └── Orc.Automation.Host.xml └── nuget.exe /.config/dotnet-tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "isRoot": true, 4 | "tools": { 5 | "cake.tool": { 6 | "version": "5.0.0", 7 | "commands": [ 8 | "dotnet-cake" 9 | ] 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | csharp 2 | *.sln merge=union 3 | *.csproj merge=union 4 | *.vbproj merge=union 5 | *.fsproj merge=union 6 | *.dbproj merge=union 7 | 8 | # Standard to msysgit 9 | *.doc diff=astextplain 10 | *.DOC diff=astextplain 11 | *.docx diff=astextplain 12 | *.DOCX diff=astextplain 13 | *.dot diff=astextplain 14 | *.DOT diff=astextplain 15 | *.pdf diff=astextplain 16 | *.PDF diff=astextplain 17 | *.rtf diff=astextplain 18 | *.RTF diff=astextplain 19 | diff= 20 | # Taken from: https://github.com/Danimoth/gitattributes/blob/master/CSharp.gitattributes 21 | # Auto detect text files and perform LF normalization 22 | # http://davidlaing.com/2012/09/19/customise-your-gitattributes-to-become-a-git-ninja/ 23 | 24 | * text=auto 25 | 26 | # Replace all tabs with spaces 27 | 28 | # Custom for Visual Studio 29 | *.cs 30 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: WildGums-oss # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | custom: # Replace with a single custom sponsorship URL -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/---support-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F62C Support Request" 3 | about: Having Trouble - ONLY contributors to other OSS projects OR people who are 4 | funding this project can submit these! If you aren't one of these, expect the ban 5 | hammer to fall 6 | title: '' 7 | labels: '' 8 | assignees: '' 9 | 10 | --- 11 | 12 | ONLY active OSS contributors OR people who buy us a coffee can ask questions here. If you don't do either of these things - DO NOT FILE HERE :) 13 | 14 | Give as much details as humanly possible if you want any sort of answer! 15 | 16 | Enter Question Below (don't delete this line) -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/--bug.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F99FBug" 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: "s/unverified, t/bug \U0001F47E" 6 | assignees: '' 7 | 8 | --- 9 | 10 | # IF YOU DON'T ANSWER THIS TEMPLATE - THE BOT WILL AUTOMATICALLY CLOSE YOUR ISSUE! 11 | 12 | ## Please check all of the platforms you are having the issue on (if platform is not listed, it is not supported) 13 | 14 | - [ ] WPF 15 | - [ ] Blazor WASM 16 | - [ ] .NET Core 17 | 18 | ## Component 19 | 20 | What component is this issue occurring in? 21 | 22 | ## Version of Library 23 | 24 | 25 | ## Version of OS(s) listed above with issue 26 | 27 | 28 | ## Steps to Reproduce 29 | 1. 30 | 2. 31 | 3. 32 | 33 | ## Expected Behavior 34 | 35 | 36 | ## Actual Behavior -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/--feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F354Feature Request" 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: "s/unverified, t/enhancement \U0001F423" 6 | assignees: '' 7 | 8 | --- 9 | 10 | # IF YOU DON'T ANSWER THIS TEMPLATE - THE BOT WILL AUTOMATICALLY CLOSE YOUR ISSUE! 11 | 12 | ## Summary 13 | Please provide a brief summary of your proposal. Two to three sentences is best here. 14 | 15 | ## API Changes 16 | Include a list of all API changes, additions, subtractions as would be required by your proposal. These APIs should be considered placeholders, so the naming is not as important as getting the concepts correct. If possible you should include some "example" code of usage of your new API. 17 | 18 | ## Intended Use Case 19 | Provide a detailed example of where your proposal would be used and for what purpose. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/--thank-you.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "❤️Thank You" 3 | about: Just want to say thank you, this is the one to do it in 4 | title: Thank You 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | Leave Your Message Below (don't delete this line though) -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Description of Change ### 2 | 3 | 4 | 5 | ### Issues Resolved ### 6 | 7 | 8 | 9 | - fixes # 10 | 11 | ### API Changes ### 12 | 13 | 14 | 15 | None 16 | 17 | ### Behavioral Changes ### 18 | 19 | 20 | 21 | None 22 | 23 | ### Testing Procedure ### 24 | 25 | 26 | 27 | ### PR Checklist ### 28 | 29 | - [ ] I have included examples or tests 30 | - [ ] I have updated the change log or created a GitHub ticket with the change 31 | - [ ] I am listed in the CONTRIBUTORS file (if it exists) 32 | - [ ] Changes adhere to coding standard 33 | - [ ] I checked the licenses of Third Party software and discussed new dependencies with at least 1 other team member -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | registries: 3 | nuget-feed-default: 4 | type: nuget-feed 5 | url: https://api.nuget.org/v3/index.json 6 | 7 | updates: 8 | - package-ecosystem: github-actions 9 | directory: "/" 10 | schedule: 11 | interval: weekly 12 | 13 | - package-ecosystem: nuget 14 | directories: 15 | - "/src" 16 | schedule: 17 | interval: daily 18 | open-pull-requests-limit: 10 19 | ignore: 20 | - dependency-name: "*Analyzers" 21 | versions: 22 | - ">= 0" 23 | registries: 24 | - nuget-feed-default -------------------------------------------------------------------------------- /.github/lock.yml: -------------------------------------------------------------------------------- 1 | # Configuration for Lock Threads - https://github.com/dessant/lock-threads 2 | 3 | # Number of days of inactivity before a closed issue or pull request is locked 4 | daysUntilLock: 4 5 | 6 | # Skip issues and pull requests created before a given timestamp. Timestamp must 7 | # follow ISO 8601 (`YYYY-MM-DD`). Set to `false` to disable 8 | skipCreatedBefore: false 9 | 10 | # Issues and pull requests with these labels will be ignored. Set to `[]` to disable 11 | exemptLabels: ["pinned", "planned"] 12 | 13 | # Label to add before locking, such as `outdated`. Set to `false` to disable 14 | lockLabel: false 15 | 16 | # Comment to post before locking. Set to `false` to disable 17 | lockComment: > 18 | This thread has been automatically locked since there has not been 19 | any recent activity after it was closed. Please open a new issue for 20 | related bugs. 21 | 22 | # Assign `resolved` as the reason for locking. Set to `false` to disable 23 | setLockReason: true 24 | 25 | # Limit to only `issues` or `pulls` 26 | # only: issues 27 | 28 | # Optionally, specify configuration settings just for `issues` or `pulls` 29 | # issues: 30 | # exemptLabels: 31 | # - help-wanted 32 | # lockLabel: outdated 33 | 34 | # pulls: 35 | # daysUntilLock: 30 36 | 37 | # Repository to extend settings from 38 | # _extends: repo -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 60 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 7 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - pinned 8 | - security 9 | - planned 10 | - nostale 11 | # Label to use when marking an issue as stale 12 | staleLabel: wontfix 13 | # Comment to post when marking an issue as stale. Set to `false` to disable 14 | markComment: > 15 | This issue has been automatically marked as stale because it has not had 16 | recent activity. It will be closed if no further activity occurs. Thank you 17 | for your contributions. 18 | # Comment to post when closing a stale issue. Set to `false` to disable 19 | closeComment: false -------------------------------------------------------------------------------- /.github/support.yml: -------------------------------------------------------------------------------- 1 | # Configuration for Support Requests - https://github.com/dessant/support-requests 2 | 3 | # Label used to mark issues as support requests 4 | supportLabel: support 5 | 6 | # Comment to post on issues marked as support requests, `{issue-author}` is an 7 | # optional placeholder. Set to `false` to disable 8 | supportComment: > 9 | :wave: @{issue-author}, we use the issue tracker exclusively for bug reports 10 | and feature requests. However, this issue appears to be a support request. 11 | Please use our support channels to get help with the project. 12 | 13 | # Close issues marked as support requests 14 | close: true 15 | 16 | # Lock issues marked as support requests 17 | lock: false 18 | 19 | # Assign `off-topic` as the reason for locking. Set to `false` to disable 20 | setLockReason: true 21 | 22 | # Repository to extend settings from 23 | # _extends: repo -------------------------------------------------------------------------------- /.github/workflows/build-and-test.yml: -------------------------------------------------------------------------------- 1 | name: Build and test 2 | 3 | on: 4 | push: 5 | branches: 6 | - develop 7 | - master 8 | pull_request: 9 | 10 | #permissions: 11 | #pull-requests: write 12 | #contents: write 13 | 14 | jobs: 15 | build-and-test: 16 | runs-on: windows-latest # Required for some (WPF) projects 17 | 18 | steps: 19 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 20 | id: checkout 21 | with: 22 | fetch-depth: 0 23 | 24 | - name: Setup .NET Core 25 | id: setup-dotnet 26 | uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1 27 | with: 28 | dotnet-version: '9.0.x' 29 | 30 | - name: Cake Action 31 | id: cake-action 32 | uses: cake-build/cake-action@5167c3f6a9e15c76f009de2acdfb9488552bc0b9 #v3.0.0 33 | with: 34 | target: BuildAndTest 35 | arguments: | 36 | IsCiBuild: true -------------------------------------------------------------------------------- /.github/workflows/dependabot-auto-merge.yml: -------------------------------------------------------------------------------- 1 | name: Dependabot auto-merge 2 | on: pull_request_target 3 | permissions: 4 | pull-requests: write 5 | contents: write 6 | jobs: 7 | dependabot: 8 | runs-on: ubuntu-latest 9 | # Checking the actor will prevent your Action run failing on non-Dependabot PRs 10 | if: ${{ github.actor == 'dependabot[bot]' }} 11 | steps: 12 | - name: Dependabot metadata 13 | id: dependabot-metadata 14 | uses: dependabot/fetch-metadata@08eff52bf64351f401fb50d4972fa95b9f2c2d1b #2.4.0 15 | with: 16 | github-token: "${{ secrets.GITHUB_TOKEN }}" 17 | - name: Approve Dependabot PR 18 | run: gh pr review --approve "$PR_URL" 19 | env: 20 | PR_URL: ${{github.event.pull_request.html_url}} 21 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 22 | - name: Enable auto-merge for Dependabot PRs 23 | if: | 24 | (startsWith(steps.dependabot-metadata.outputs.dependency-names, 'catel.') || 25 | startsWith(steps.dependabot-metadata.outputs.dependency-names, 'orc.') || 26 | startsWith(steps.dependabot-metadata.outputs.dependency-names, 'orchestra.')) && 27 | (steps.dependabot-metadata.outputs.update-type == 'version-update:semver-minor' || 28 | steps.dependabot-metadata.outputs.update-type == 'version-update:semver-patch') 29 | run: gh pr merge --auto --merge "$PR_URL" 30 | env: 31 | PR_URL: ${{github.event.pull_request.html_url}} 32 | PR_NUMBER: ${{github.event.pull_request.number}} 33 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | # This is the official list of authors for copyright purposes. 2 | # This file is distinct from the CONTRIBUTORS file. 3 | # See the latter for an explanation. 4 | 5 | # Names should be added to this file as 6 | # Name or Organization 7 | # The email address is not required for organizations. 8 | 9 | # Please keep the list sorted. 10 | # Please notify the first person on the list to be added here. 11 | 12 | WildGums 13 | -------------------------------------------------------------------------------- /CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | # This is the official list of people who have contributed 2 | # to this repository. 3 | # The AUTHORS file lists the copyright holders; this file 4 | # lists people. 5 | 6 | # People submitting code should be listed in this file (by email address). 7 | 8 | # Names should be added to this file like so: 9 | # Name 10 | 11 | # Please keep the list sorted. 12 | 13 | Geert van Horrik 14 | Christian Günther 15 | Maksim Khomutov 16 | Igr Alexánder Fernández Saúco -------------------------------------------------------------------------------- /GitReleaseManager.yaml: -------------------------------------------------------------------------------- 1 | issue-labels-include: 2 | - Breaking change 3 | - Feature 4 | - Bug 5 | - Improvement 6 | - Documentation 7 | - Dependencies 8 | issue-labels-exclude: 9 | - Build 10 | - Won't fix 11 | issue-labels-alias: 12 | - name: Documentation 13 | header: Documentation 14 | plural: Documentation -------------------------------------------------------------------------------- /GitVersion.yml: -------------------------------------------------------------------------------- 1 | mode: ContinuousDeployment 2 | assembly-versioning-scheme: MajorMinorPatch 3 | next-version: 5.0.0 -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2018 WildGums 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | ============================================================================== 24 | 25 | Additional licenses / components 26 | -------------------------------- 27 | 28 | Some parts are based on other open-source components. Each component that is based 29 | on another component has a reference to the original component including the original 30 | license the code was delivered upon. Below is a list of other components / licenses. 31 | 32 | Note: if you feel an item is missing in this list, please let us know! 33 | 34 | * Catel 35 | https://github.com/catel/catel 36 | Original license: MIT 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Orc.FilterBuilder 2 | ================= 3 | 4 | Name|Badge 5 | ---|--- 6 | Chat|[![Join the chat at https://gitter.im/WildGums/Orc.FilterBuilder](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/WildGums/Orc.FilterBuilder?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 7 | Downloads|![NuGet downloads](https://img.shields.io/nuget/dt/orc.filterbuilder.svg) 8 | Stable version|![Version](https://img.shields.io/nuget/v/orc.filterbuilder.svg) 9 | Unstable version|![Pre-release version](https://img.shields.io/nuget/vpre/orc.filterbuilder.svg) 10 | 11 | FilterBuilder is WPF component which can help you extract key insights from your data, by adding complex filtering functionalities to your application. 12 | 13 | For documentation, please visit the [documentation portal](http://opensource.wildgums.com) -------------------------------------------------------------------------------- /build.cake: -------------------------------------------------------------------------------- 1 | //======================================================= 2 | // DEFINE PARAMETERS 3 | //======================================================= 4 | 5 | // Define the required parameters 6 | var Parameters = new Dictionary(); 7 | Parameters["SolutionName"] = "Orc.FilterBuilder"; 8 | Parameters["Company"] = "WildGums"; 9 | Parameters["RepositoryUrl"] = string.Format("https://github.com/{0}/{1}", GetBuildServerVariable("Company"), GetBuildServerVariable("SolutionName")); 10 | Parameters["StartYear"] = "2014"; 11 | Parameters["UseVisualStudioPrerelease"] = "false"; 12 | 13 | // Note: the rest of the variables should be coming from the build server, 14 | // see `/deployment/cake/*-variables.cake` for customization options 15 | // 16 | // If required, more variables can be overridden by specifying them via the 17 | // Parameters dictionary, but the build server variables will always override 18 | // them if defined by the build server. For example, to override the code 19 | // sign wild card, add this to build.cake 20 | // 21 | // Parameters["CodeSignWildcard"] = "Orc.EntityFramework"; 22 | 23 | //======================================================= 24 | // DEFINE COMPONENTS TO BUILD / PACKAGE 25 | //======================================================= 26 | 27 | Components.Add("Orc.FilterBuilder"); 28 | Components.Add("Orc.FilterBuilder.Xaml"); 29 | 30 | TestProjects.Add(string.Format("{0}.Tests", GetBuildServerVariable("SolutionName"))); 31 | 32 | //======================================================= 33 | // REQUIRED INITIALIZATION, DO NOT CHANGE 34 | //======================================================= 35 | 36 | // Now all variables are defined, include the tasks, that 37 | // script will take care of the rest of the magic 38 | 39 | #l "./deployment/cake/tasks.cake" 40 | -------------------------------------------------------------------------------- /build.ps1: -------------------------------------------------------------------------------- 1 | $ErrorActionPreference = 'Stop' 2 | 3 | Set-Location -LiteralPath $PSScriptRoot 4 | 5 | $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE = '1' 6 | $env:DOTNET_CLI_TELEMETRY_OPTOUT = '1' 7 | $env:DOTNET_NOLOGO = '1' 8 | 9 | dotnet tool restore 10 | if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } 11 | 12 | dotnet cake @args 13 | if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } 14 | -------------------------------------------------------------------------------- /cake.config: -------------------------------------------------------------------------------- 1 | ; The configuration file for Cake. 2 | 3 | [Settings] 4 | SkipVerification=true 5 | 6 | [Settings] 7 | EnableScriptCache=true 8 | 9 | [Paths] 10 | ; Cache=%temp%/cake-build/cache/ 11 | ; Note: cache-path is set via environment variables -------------------------------------------------------------------------------- /deployment/cake/apps-uwp-variables.cake: -------------------------------------------------------------------------------- 1 | #l "./buildserver.cake" 2 | 3 | //------------------------------------------------------------- 4 | 5 | public class UwpContext : BuildContextWithItemsBase 6 | { 7 | public UwpContext(IBuildContext parentBuildContext) 8 | : base(parentBuildContext) 9 | { 10 | } 11 | 12 | public string WindowsStoreAppId { get; set; } 13 | public string WindowsStoreClientId { get; set; } 14 | public string WindowsStoreClientSecret { get; set; } 15 | public string WindowsStoreTenantId { get; set; } 16 | 17 | protected override void ValidateContext() 18 | { 19 | } 20 | 21 | protected override void LogStateInfoForContext() 22 | { 23 | CakeContext.Information($"Found '{Items.Count}' uwp projects"); 24 | } 25 | } 26 | 27 | //------------------------------------------------------------- 28 | 29 | private UwpContext InitializeUwpContext(BuildContext buildContext, IBuildContext parentBuildContext) 30 | { 31 | var data = new UwpContext(parentBuildContext) 32 | { 33 | Items = UwpApps ?? new List(), 34 | WindowsStoreAppId = buildContext.BuildServer.GetVariable("WindowsStoreAppId", showValue: true), 35 | WindowsStoreClientId = buildContext.BuildServer.GetVariable("WindowsStoreClientId", showValue: false), 36 | WindowsStoreClientSecret = buildContext.BuildServer.GetVariable("WindowsStoreClientSecret", showValue: false), 37 | WindowsStoreTenantId = buildContext.BuildServer.GetVariable("WindowsStoreTenantId", showValue: false) 38 | }; 39 | 40 | return data; 41 | } 42 | 43 | //------------------------------------------------------------- 44 | 45 | List _uwpApps; 46 | 47 | public List UwpApps 48 | { 49 | get 50 | { 51 | if (_uwpApps is null) 52 | { 53 | _uwpApps = new List(); 54 | } 55 | 56 | return _uwpApps; 57 | } 58 | } -------------------------------------------------------------------------------- /deployment/cake/codesigning-tasks.cake: -------------------------------------------------------------------------------- 1 | #l "codesigning-variables.cake" 2 | 3 | using System.Xml.Linq; 4 | 5 | //------------------------------------------------------------- 6 | 7 | // Empty by design for now 8 | -------------------------------------------------------------------------------- /deployment/cake/codesigning-variables.cake: -------------------------------------------------------------------------------- 1 | #l "buildserver.cake" 2 | 3 | //------------------------------------------------------------- 4 | 5 | public class CodeSigningContext : BuildContextBase 6 | { 7 | public CodeSigningContext(IBuildContext parentBuildContext) 8 | : base(parentBuildContext) 9 | { 10 | } 11 | 12 | public List ProjectsToSignImmediately { get; set; } 13 | 14 | protected override void ValidateContext() 15 | { 16 | 17 | } 18 | 19 | protected override void LogStateInfoForContext() 20 | { 21 | //CakeContext.Information($"Found '{Items.Count}' component projects"); 22 | } 23 | } 24 | 25 | //------------------------------------------------------------- 26 | 27 | private CodeSigningContext InitializeCodeSigningContext(BuildContext buildContext, IBuildContext parentBuildContext) 28 | { 29 | var data = new CodeSigningContext(parentBuildContext) 30 | { 31 | ProjectsToSignImmediately = CodeSignImmediately, 32 | }; 33 | 34 | return data; 35 | } 36 | 37 | //------------------------------------------------------------- 38 | 39 | List _codeSignImmediately; 40 | 41 | public List CodeSignImmediately 42 | { 43 | get 44 | { 45 | if (_codeSignImmediately is null) 46 | { 47 | _codeSignImmediately = new List(); 48 | } 49 | 50 | return _codeSignImmediately; 51 | } 52 | } -------------------------------------------------------------------------------- /deployment/cake/components-variables.cake: -------------------------------------------------------------------------------- 1 | #l "buildserver.cake" 2 | 3 | //------------------------------------------------------------- 4 | 5 | public class ComponentsContext : BuildContextWithItemsBase 6 | { 7 | public ComponentsContext(IBuildContext parentBuildContext) 8 | : base(parentBuildContext) 9 | { 10 | } 11 | 12 | public string NuGetRepositoryUrl { get; set; } 13 | public string NuGetRepositoryApiKey { get; set; } 14 | 15 | protected override void ValidateContext() 16 | { 17 | 18 | } 19 | 20 | protected override void LogStateInfoForContext() 21 | { 22 | CakeContext.Information($"Found '{Items.Count}' component projects"); 23 | } 24 | } 25 | 26 | //------------------------------------------------------------- 27 | 28 | private ComponentsContext InitializeComponentsContext(BuildContext buildContext, IBuildContext parentBuildContext) 29 | { 30 | var data = new ComponentsContext(parentBuildContext) 31 | { 32 | Items = Components ?? new List(), 33 | NuGetRepositoryUrl = buildContext.BuildServer.GetVariable("NuGetRepositoryUrl", showValue: true), 34 | NuGetRepositoryApiKey = buildContext.BuildServer.GetVariable("NuGetRepositoryApiKey", showValue: false) 35 | }; 36 | 37 | return data; 38 | } 39 | 40 | //------------------------------------------------------------- 41 | 42 | List _components; 43 | 44 | public List Components 45 | { 46 | get 47 | { 48 | if (_components is null) 49 | { 50 | _components = new List(); 51 | } 52 | 53 | return _components; 54 | } 55 | } -------------------------------------------------------------------------------- /deployment/cake/docker-variables.cake: -------------------------------------------------------------------------------- 1 | #l "buildserver.cake" 2 | 3 | //------------------------------------------------------------- 4 | 5 | public class DockerImagesContext : BuildContextWithItemsBase 6 | { 7 | public DockerImagesContext(IBuildContext parentBuildContext) 8 | : base(parentBuildContext) 9 | { 10 | } 11 | 12 | public string DockerEngineUrl { get; set; } 13 | public string DockerRegistryUrl { get; set; } 14 | public string DockerRegistryUserName { get; set; } 15 | public string DockerRegistryPassword { get; set; } 16 | 17 | protected override void ValidateContext() 18 | { 19 | } 20 | 21 | protected override void LogStateInfoForContext() 22 | { 23 | CakeContext.Information($"Found '{Items.Count}' docker image projects"); 24 | } 25 | } 26 | 27 | //------------------------------------------------------------- 28 | 29 | private DockerImagesContext InitializeDockerImagesContext(BuildContext buildContext, IBuildContext parentBuildContext) 30 | { 31 | var data = new DockerImagesContext(parentBuildContext) 32 | { 33 | Items = DockerImages ?? new List(), 34 | DockerEngineUrl = buildContext.BuildServer.GetVariable("DockerEngineUrl", showValue: true), 35 | DockerRegistryUrl = buildContext.BuildServer.GetVariable("DockerRegistryUrl", showValue: true), 36 | DockerRegistryUserName = buildContext.BuildServer.GetVariable("DockerRegistryUserName", showValue: false), 37 | DockerRegistryPassword = buildContext.BuildServer.GetVariable("DockerRegistryPassword", showValue: false) 38 | }; 39 | 40 | return data; 41 | } 42 | 43 | //------------------------------------------------------------- 44 | 45 | List _dockerImages; 46 | 47 | public List DockerImages 48 | { 49 | get 50 | { 51 | if (_dockerImages is null) 52 | { 53 | _dockerImages = new List(); 54 | } 55 | 56 | return _dockerImages; 57 | } 58 | } -------------------------------------------------------------------------------- /deployment/cake/issuetrackers.cake: -------------------------------------------------------------------------------- 1 | // Customize this file when using a different issue tracker 2 | #l "issuetrackers-github.cake" 3 | #l "issuetrackers-jira.cake" 4 | 5 | //------------------------------------------------------------- 6 | 7 | public interface IIssueTracker 8 | { 9 | Task CreateAndReleaseVersionAsync(); 10 | } 11 | 12 | //------------------------------------------------------------- 13 | 14 | public class IssueTrackerIntegration : IntegrationBase 15 | { 16 | private readonly List _issueTrackers = new List(); 17 | 18 | public IssueTrackerIntegration(BuildContext buildContext) 19 | : base(buildContext) 20 | { 21 | _issueTrackers.Add(new GitHubIssueTracker(buildContext)); 22 | _issueTrackers.Add(new JiraIssueTracker(buildContext)); 23 | } 24 | 25 | public async Task CreateAndReleaseVersionAsync() 26 | { 27 | BuildContext.CakeContext.LogSeparator("Creating and releasing version"); 28 | 29 | foreach (var issueTracker in _issueTrackers) 30 | { 31 | try 32 | { 33 | await issueTracker.CreateAndReleaseVersionAsync(); 34 | } 35 | catch (Exception ex) 36 | { 37 | BuildContext.CakeContext.Error(ex.Message); 38 | } 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /deployment/cake/lib-logging.cake: -------------------------------------------------------------------------------- 1 | // Note: code originally comes from https://stackoverflow.com/questions/50826394/how-to-print-tool-command-line-in-cake 2 | 3 | /// 4 | /// Temporary sets logging verbosity. 5 | /// 6 | /// 7 | /// 8 | /// // Temporary sets logging verbosity to Diagnostic. 9 | /// using(context.UseVerbosity(Verbosity.Diagnostic)) 10 | /// { 11 | /// context.DotNetBuild(project, settings); 12 | /// } 13 | /// 14 | /// 15 | public static VerbosityChanger UseVerbosity(this ICakeContext context, Verbosity newVerbosity) => 16 | new VerbosityChanger(context.Log, newVerbosity); 17 | 18 | 19 | /// 20 | /// Temporary sets logging verbosity to Diagnostic. 21 | /// 22 | /// 23 | /// 24 | /// // Temporary sets logging verbosity to Diagnostic. 25 | /// using(context.UseDiagnosticVerbosity()) 26 | /// { 27 | /// context.DotNetBuild(project, settings); 28 | /// } 29 | /// 30 | /// 31 | public static VerbosityChanger UseDiagnosticVerbosity(this ICakeContext context) => 32 | context.UseVerbosity(Verbosity.Diagnostic); 33 | 34 | /// 35 | /// Cake log verbosity changer. 36 | /// Restores old verbosity on Dispose. 37 | /// 38 | public class VerbosityChanger : IDisposable 39 | { 40 | ICakeLog _log; 41 | Verbosity _oldVerbosity; 42 | 43 | public VerbosityChanger(ICakeLog log, Verbosity newVerbosity) 44 | { 45 | _log = log; 46 | _oldVerbosity = log.Verbosity; 47 | _log.Verbosity = newVerbosity; 48 | } 49 | 50 | public void Dispose() => _log.Verbosity = _oldVerbosity; 51 | } -------------------------------------------------------------------------------- /deployment/cake/notifications.cake: -------------------------------------------------------------------------------- 1 | #l "notifications-msteams.cake" 2 | //#l "notifications-slack.cake" 3 | 4 | //------------------------------------------------------------- 5 | 6 | public enum NotificationType 7 | { 8 | Info, 9 | 10 | Error 11 | } 12 | 13 | //------------------------------------------------------------- 14 | 15 | public interface INotifier 16 | { 17 | Task NotifyAsync(string project, string message, TargetType targetType = TargetType.Unknown, NotificationType notificationType = NotificationType.Info); 18 | } 19 | 20 | //------------------------------------------------------------- 21 | 22 | public class NotificationsIntegration : IntegrationBase 23 | { 24 | private readonly List _notifiers = new List(); 25 | 26 | public NotificationsIntegration(BuildContext buildContext) 27 | : base(buildContext) 28 | { 29 | _notifiers.Add(new MsTeamsNotifier(buildContext)); 30 | } 31 | 32 | public async Task NotifyDefaultAsync(string project, string message, TargetType targetType = TargetType.Unknown) 33 | { 34 | await NotifyAsync(project, message, targetType, NotificationType.Info); 35 | } 36 | 37 | //------------------------------------------------------------- 38 | 39 | public async Task NotifyErrorAsync(string project, string message, TargetType targetType = TargetType.Unknown) 40 | { 41 | await NotifyAsync(project, string.Format("ERROR: {0}", message), targetType, NotificationType.Error); 42 | } 43 | 44 | //------------------------------------------------------------- 45 | 46 | public async Task NotifyAsync(string project, string message, TargetType targetType = TargetType.Unknown, NotificationType notificationType = NotificationType.Info) 47 | { 48 | foreach (var notifier in _notifiers) 49 | { 50 | await notifier.NotifyAsync(project, message, targetType, notificationType); 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /deployment/cake/templates-variables.cake: -------------------------------------------------------------------------------- 1 | #l "buildserver.cake" 2 | 3 | //------------------------------------------------------------- 4 | 5 | public class TemplatesContext : BuildContextWithItemsBase 6 | { 7 | public TemplatesContext(IBuildContext parentBuildContext) 8 | : base(parentBuildContext) 9 | { 10 | } 11 | 12 | protected override void ValidateContext() 13 | { 14 | 15 | } 16 | 17 | protected override void LogStateInfoForContext() 18 | { 19 | CakeContext.Information($"Found '{Items.Count}' template items"); 20 | } 21 | } 22 | 23 | //------------------------------------------------------------- 24 | 25 | private TemplatesContext InitializeTemplatesContext(BuildContext buildContext, IBuildContext parentBuildContext) 26 | { 27 | var data = new TemplatesContext(parentBuildContext) 28 | { 29 | Items = Templates ?? new List(), 30 | }; 31 | 32 | return data; 33 | } 34 | 35 | //------------------------------------------------------------- 36 | 37 | List _templates; 38 | 39 | public List Templates 40 | { 41 | get 42 | { 43 | if (_templates is null) 44 | { 45 | _templates = new List(); 46 | } 47 | 48 | return _templates; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /deployment/cake/tests-nunit.cake: -------------------------------------------------------------------------------- 1 | #tool "nuget:?package=NUnit.ConsoleRunner&version=3.20.1" 2 | 3 | //------------------------------------------------------------- 4 | 5 | private static void RunTestsUsingNUnit(BuildContext buildContext, string projectName, string testTargetFramework, string testResultsDirectory) 6 | { 7 | var testFile = System.IO.Path.Combine(GetProjectOutputDirectory(buildContext, projectName), 8 | testTargetFramework, $"{projectName}.dll"); 9 | var resultsFile = System.IO.Path.Combine(testResultsDirectory, "testresults.xml"); 10 | 11 | var nunitSettings = new NUnit3Settings 12 | { 13 | Results = new NUnit3Result[] 14 | { 15 | new NUnit3Result 16 | { 17 | FileName = resultsFile, 18 | Format = "nunit3" 19 | } 20 | }, 21 | NoHeader = true, 22 | NoColor = true, 23 | NoResults = false, 24 | X86 = string.Equals(buildContext.Tests.ProcessBit, "X86", StringComparison.OrdinalIgnoreCase), 25 | Timeout = 60 * 1000, // 60 seconds 26 | Workers = 1 27 | //Work = testResultsDirectory 28 | }; 29 | 30 | // Note: although the docs say you can use without array initialization, you can't 31 | buildContext.CakeContext.NUnit3(new string[] { testFile }, nunitSettings); 32 | 33 | buildContext.CakeContext.Information("Verifying whether results file '{0}' exists", resultsFile); 34 | 35 | if (!buildContext.CakeContext.FileExists(resultsFile)) 36 | { 37 | throw new Exception(string.Format("Expected results file '{0}' does not exist", resultsFile)); 38 | } 39 | } -------------------------------------------------------------------------------- /deployment/cake/tests-variables.cake: -------------------------------------------------------------------------------- 1 | #l "buildserver.cake" 2 | 3 | //------------------------------------------------------------- 4 | 5 | public class TestsContext : BuildContextWithItemsBase 6 | { 7 | public TestsContext(IBuildContext parentBuildContext) 8 | : base(parentBuildContext) 9 | { 10 | } 11 | 12 | public string Framework { get; set; } 13 | public string TargetFramework { get; set; } 14 | public string OperatingSystem { get; set; } 15 | public string ProcessBit { get; set; } 16 | 17 | protected override void ValidateContext() 18 | { 19 | if (Items.Count == 0) 20 | { 21 | return; 22 | } 23 | 24 | if (string.IsNullOrWhiteSpace(Framework)) 25 | { 26 | throw new Exception("Framework is required, specify via 'TestFramework'"); 27 | } 28 | 29 | if (string.IsNullOrWhiteSpace(ProcessBit)) 30 | { 31 | throw new Exception("ProcessBit is required, specify via 'TestProcessBit'"); 32 | } 33 | } 34 | 35 | protected override void LogStateInfoForContext() 36 | { 37 | CakeContext.Information($"Found '{Items.Count}' test projects"); 38 | } 39 | } 40 | 41 | //------------------------------------------------------------- 42 | 43 | private TestsContext InitializeTestsContext(BuildContext buildContext, IBuildContext parentBuildContext) 44 | { 45 | var data = new TestsContext(parentBuildContext) 46 | { 47 | Items = TestProjects, 48 | 49 | Framework = buildContext.BuildServer.GetVariable("TestFramework", "nunit", showValue: true), 50 | TargetFramework = buildContext.BuildServer.GetVariable("TestTargetFramework", "", showValue: true), 51 | OperatingSystem = buildContext.BuildServer.GetVariable("TestOperatingSystem", "win", showValue: true), 52 | ProcessBit = buildContext.BuildServer.GetVariable("TestProcessBit", "X64", showValue: true) 53 | }; 54 | 55 | return data; 56 | } 57 | 58 | //------------------------------------------------------------- 59 | 60 | List _testProjects; 61 | 62 | public List TestProjects 63 | { 64 | get 65 | { 66 | if (_testProjects is null) 67 | { 68 | _testProjects = new List(); 69 | } 70 | 71 | return _testProjects; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /deployment/cake/tools-variables.cake: -------------------------------------------------------------------------------- 1 | #l "buildserver.cake" 2 | 3 | //------------------------------------------------------------- 4 | 5 | public class ToolsContext : BuildContextWithItemsBase 6 | { 7 | public ToolsContext(IBuildContext parentBuildContext) 8 | : base(parentBuildContext) 9 | { 10 | } 11 | 12 | public string NuGetRepositoryUrls { get; set; } 13 | public string NuGetRepositoryApiKeys { get; set; } 14 | 15 | protected override void ValidateContext() 16 | { 17 | 18 | } 19 | 20 | protected override void LogStateInfoForContext() 21 | { 22 | CakeContext.Information($"Found '{Items.Count}' tool projects"); 23 | } 24 | } 25 | 26 | //------------------------------------------------------------- 27 | 28 | private ToolsContext InitializeToolsContext(BuildContext buildContext, IBuildContext parentBuildContext) 29 | { 30 | var data = new ToolsContext(parentBuildContext) 31 | { 32 | Items = Tools ?? new List(), 33 | NuGetRepositoryUrls = buildContext.BuildServer.GetVariable("ToolsNuGetRepositoryUrls", showValue: true), 34 | NuGetRepositoryApiKeys = buildContext.BuildServer.GetVariable("ToolsNuGetRepositoryApiKeys", showValue: false) 35 | }; 36 | 37 | return data; 38 | } 39 | 40 | //------------------------------------------------------------- 41 | 42 | List _tools; 43 | 44 | public List Tools 45 | { 46 | get 47 | { 48 | if (_tools is null) 49 | { 50 | _tools = new List(); 51 | } 52 | 53 | return _tools; 54 | } 55 | } -------------------------------------------------------------------------------- /deployment/cake/vsextensions-variables.cake: -------------------------------------------------------------------------------- 1 | #l "buildserver.cake" 2 | 3 | public class VsExtensionsContext : BuildContextWithItemsBase 4 | { 5 | public VsExtensionsContext(IBuildContext parentBuildContext) 6 | : base(parentBuildContext) 7 | { 8 | } 9 | 10 | public string PublisherName { get; set; } 11 | public string PersonalAccessToken { get; set; } 12 | 13 | protected override void ValidateContext() 14 | { 15 | 16 | } 17 | 18 | protected override void LogStateInfoForContext() 19 | { 20 | CakeContext.Information($"Found '{Items.Count}' vs extension projects"); 21 | } 22 | } 23 | 24 | //------------------------------------------------------------- 25 | 26 | private VsExtensionsContext InitializeVsExtensionsContext(BuildContext buildContext, IBuildContext parentBuildContext) 27 | { 28 | var data = new VsExtensionsContext(parentBuildContext) 29 | { 30 | Items = VsExtensions ?? new List(), 31 | PublisherName = buildContext.BuildServer.GetVariable("VsExtensionsPublisherName", showValue: true), 32 | PersonalAccessToken = buildContext.BuildServer.GetVariable("VsExtensionsPersonalAccessToken", showValue: false), 33 | }; 34 | 35 | return data; 36 | } 37 | 38 | //------------------------------------------------------------- 39 | 40 | List _vsExtensions; 41 | 42 | public List VsExtensions 43 | { 44 | get 45 | { 46 | if (_vsExtensions is null) 47 | { 48 | _vsExtensions = new List(); 49 | } 50 | 51 | return _vsExtensions; 52 | } 53 | } -------------------------------------------------------------------------------- /design/Package/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WildGums/Orc.FilterBuilder/b2edabe34c0d74e92c9d0c040d7b073945997e7b/design/Package/Icon.png -------------------------------------------------------------------------------- /src/Directory.Build.implicitusings.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | enable 4 | 5 | -------------------------------------------------------------------------------- /src/Directory.Build.nullable.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | enable 4 | 5 | -------------------------------------------------------------------------------- /src/Directory.Build.project.props: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | wildgums 8 | https://github.com/WildGums/Orc.FilterBuilder 9 | MIT 10 | https://github.com/WildGums/Orc.FilterBuilder 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 9 | 11 | 13 | 14 | 15 | 16 | 18 | 20 | 22 | -------------------------------------------------------------------------------- /src/Directory.Build.shared.mat.props: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 4.0 10 | en-US 11 | true 12 | true 13 | true 14 | 15 | 16 | 17 | <_ResxFiles Remove="Properties\*.resx" /> 18 | 19 | 20 | 21 | 22 | 23 | 24 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/Directory.Build.shared.tests.props: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | false 10 | true 11 | true 12 | 13 | 14 | 15 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/Directory.Build.shared.tools.props: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | $(Description) 10 | $(PackageProjectUrl) 11 | IncludeDefaultProjectBuildOutputInPack 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | $([MSBuild]::MakeRelative('$(OutputPath)\$(TargetFrameworks)\', %(ToolDllFiles.FullPath))) 31 | tools 32 | 33 | 34 | 35 | $([MSBuild]::MakeRelative('$(OutputPath)\$(TargetFrameworks)\', %(ToolExeFiles.FullPath))) 36 | tools 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/GlobalSuppressions.cs: -------------------------------------------------------------------------------- 1 |  2 | // This file is used by Code Analysis to maintain SuppressMessage 3 | // attributes that are applied to this project. 4 | // Project-level suppressions either have no target or are given 5 | // a specific target and scoped to a namespace, type, member, etc. 6 | 7 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("WpfAnalyzers.DependencyProperties", "WPF1010:Property '[property]' must notify when value changes.", Justification = "Don't enforce this")] 8 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("WpfAnalyzers.DependencyProperties", "WPF1011:Implement INotifyPropertyChanged.", Justification = "Don't enforce this")] 9 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("WpfAnalyzers.DependencyProperties", "WPF1013:Use [CallerMemberName].", Justification = "Don't enforce this, base class doesn't neccessarily support this")] 10 | 11 | -------------------------------------------------------------------------------- /src/MethodTimeLogger.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using Catel.Logging; 3 | using System; 4 | using System.Globalization; 5 | 6 | /// 7 | /// Note: do not rename this class or put it inside a namespace. 8 | /// 9 | internal static class MethodTimeLogger 10 | { 11 | public static void Log(MethodBase methodBase, long milliseconds, string message) 12 | { 13 | Log(methodBase.DeclaringType ?? typeof(object), methodBase.Name, milliseconds, message); 14 | } 15 | 16 | public static void Log(Type type, string methodName, long milliseconds, string message) 17 | { 18 | if (type is null) 19 | { 20 | return; 21 | } 22 | 23 | if (milliseconds == 0) 24 | { 25 | // Don't log superfast methods 26 | return; 27 | } 28 | 29 | var finalMessage = $"[METHODTIMER] {type.Name}.{methodName} took '{milliseconds.ToString(CultureInfo.InvariantCulture)}' ms"; 30 | 31 | if (!string.IsNullOrWhiteSpace(message)) 32 | { 33 | finalMessage += $" | {message}"; 34 | } 35 | 36 | var logger = LogManager.GetLogger(type); 37 | logger.Debug(finalMessage); 38 | } 39 | } -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Example/App.xaml: -------------------------------------------------------------------------------- 1 |  4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Example/App.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Orc.FilterBuilder.Example; 2 | 3 | using System.Globalization; 4 | using System.Windows; 5 | using Catel.Logging; 6 | using Catel.IoC; 7 | using Catel.Services; 8 | using Orchestra; 9 | using Orchestra.Services; 10 | using Orchestra.Views; 11 | 12 | /// 13 | /// Interaction logic for App.xaml 14 | /// 15 | public partial class App : Application 16 | { 17 | #pragma warning disable AvoidAsyncVoid 18 | protected override async void OnStartup(StartupEventArgs e) 19 | #pragma warning restore AvoidAsyncVoid 20 | { 21 | #if DEBUG 22 | LogManager.AddDebugListener(); 23 | #endif 24 | 25 | var languageService = ServiceLocator.Default.ResolveRequiredType(); 26 | 27 | // Note: it's best to use .CurrentUICulture in actual apps since it will use the preferred language 28 | // of the user. But in order to demo multilingual features for devs (who mostly have en-US as .CurrentUICulture), 29 | // we use .CurrentCulture for the sake of the demo 30 | languageService.PreferredCulture = CultureInfo.CurrentCulture; 31 | languageService.FallbackCulture = new CultureInfo("en-US"); 32 | 33 | this.ApplyTheme(); 34 | 35 | var serviceLocator = ServiceLocator.Default; 36 | var shellService = serviceLocator.ResolveRequiredType(); 37 | await shellService.CreateAsync(); 38 | 39 | var filterSchemeManager = serviceLocator.ResolveRequiredType(); 40 | await filterSchemeManager.LoadAsync(); 41 | 42 | base.OnStartup(e); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Example/FodyWeavers.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Example/Models/Description.cs: -------------------------------------------------------------------------------- 1 | namespace FilterBuilder.Example.Models; 2 | 3 | public class Description 4 | { 5 | public Description(string value) 6 | { 7 | Value = value; 8 | } 9 | 10 | public string Value { get; } 11 | } -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Example/Models/MyEnum.cs: -------------------------------------------------------------------------------- 1 | namespace FilterBuilder.Example.Models; 2 | 3 | public enum MyEnum 4 | { 5 | EnumValue1, 6 | 7 | EnumValue2, 8 | 9 | SpecialValue 10 | } -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Example/Models/TestEntity.cs: -------------------------------------------------------------------------------- 1 | namespace FilterBuilder.Example.Models; 2 | 3 | using System; 4 | using Catel.Data; 5 | 6 | public class TestEntity : ModelBase 7 | { 8 | public string FirstName { get; set; } 9 | public int Age { get; set; } 10 | public int? Id { get; set; } 11 | public DateTime DateOfBirth { get; set; } 12 | public DateTime? DateOfDeath { get; set; } 13 | public bool IsActive { get; set; } 14 | public TimeSpan Duration { get; set; } 15 | public decimal Price { get; set; } 16 | public decimal? NullablePrice { get; set; } 17 | public MyEnum EnumValue { get; set; } 18 | public MyEnum? NullableEnumValue { get; set; } 19 | public Description Description { get; set; } 20 | } 21 | -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Example/ModuleInitializer.cs: -------------------------------------------------------------------------------- 1 | using Catel.IoC; 2 | using FilterBuilder.Example.Services; 3 | using Orc.FilterBuilder; 4 | using Orc.FilterBuilder.Example.Services; 5 | using Orchestra.Services; 6 | 7 | /// 8 | /// Used by the ModuleInit. All code inside the Initialize method is ran as soon as the assembly is loaded. 9 | /// 10 | public static class ModuleInitializer 11 | { 12 | /// 13 | /// Initializes the module. 14 | /// 15 | public static void Initialize() 16 | { 17 | var serviceLocator = ServiceLocator.Default; 18 | 19 | serviceLocator.RegisterType(); 20 | serviceLocator.RegisterType(); 21 | serviceLocator.RegisterType(); 22 | serviceLocator.RegisterType(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Example/Orc.FilterBuilder.Example.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net8.0-windows 4 | Orc.FilterBuilder.Example 5 | Orc.FilterBuilder.Example 6 | en-US 7 | true 8 | annotations 9 | 10 | 11 | 12 | true 13 | WinExe 14 | 15 | $(NoWarn);SA1652 16 | 17 | 18 | 19 | 20 | 21 | runtime; build; native; contentfiles; analyzers 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Example/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // All other assembly info is defined in SharedAssembly.cs 2 | 3 | using System.Reflection; 4 | using System.Runtime.InteropServices; 5 | using System.Windows; 6 | 7 | [assembly: AssemblyTitle("Orc.FilterBuilder.Example")] 8 | [assembly: AssemblyProduct("Orc.FilterBuilder.Example")] 9 | [assembly: AssemblyDescription("Orc.FilterBuilder.Example library")] 10 | 11 | // Setting ComVisible to false makes the types in this assembly not visible 12 | // to COM components. If you need to access a type in this assembly from 13 | // COM, set the ComVisible attribute to true on that type. 14 | 15 | #if !PCL 16 | [assembly: ComVisible(false)] 17 | #endif 18 | 19 | [assembly: ThemeInfo( 20 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 21 | //(used if a resource is not found in the page, 22 | // or application resource dictionaries) 23 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 24 | //(used if a resource is not found in the page, 25 | // app, or any theme specific resource dictionaries) 26 | )] 27 | -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Example/Resources/Fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WildGums/Orc.FilterBuilder/b2edabe34c0d74e92c9d0c040d7b073945997e7b/src/Orc.FilterBuilder.Example/Resources/Fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Example/Services/ApplicationInitializationService.cs: -------------------------------------------------------------------------------- 1 | namespace Orc.FilterBuilder.Example.Services; 2 | 3 | using System; 4 | using System.Threading.Tasks; 5 | using System.Windows.Media; 6 | using Orchestra.Services; 7 | 8 | public class ApplicationInitializationService : ApplicationInitializationServiceBase 9 | { 10 | public override Task InitializeBeforeCreatingShellAsync() 11 | { 12 | InitializeFonts(); 13 | 14 | return Task.CompletedTask; 15 | } 16 | 17 | private void InitializeFonts() 18 | { 19 | Theming.FontImage.RegisterFont("FontAwesome", new FontFamily(new Uri("pack://application:,,,/Orc.FilterBuilder.Example;component/Resources/Fonts/", UriKind.RelativeOrAbsolute), "./#FontAwesome")); 20 | Theming.FontImage.DefaultBrush = new SolidColorBrush(Color.FromArgb(255, 87, 87, 87)); 21 | Theming.FontImage.DefaultFontFamily = "FontAwesome"; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Example/Services/ExampleFilterSerializationService.cs: -------------------------------------------------------------------------------- 1 | namespace Orc.FilterBuilder.Example.Services; 2 | 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Catel.Collections; 6 | using Catel.Runtime.Serialization.Xml; 7 | using global::FilterBuilder.Example.Models; 8 | using FileSystem; 9 | using FilterBuilder; 10 | 11 | public class ExampleFilterSerializationService : FilterSerializationService 12 | { 13 | public ExampleFilterSerializationService(IFileService fileService, IXmlSerializer xmlSerializer) 14 | : base(fileService, xmlSerializer) 15 | { 16 | } 17 | 18 | public override async Task LoadFiltersAsync(string path) 19 | { 20 | var filterSchemes = await base.LoadFiltersAsync(path); 21 | 22 | filterSchemes.Schemes.Add(new FilterScheme(typeof(TestEntity)) 23 | { 24 | Title = "Demo filter scheme", 25 | FilterGroup = "Group name", 26 | CanEdit = false, 27 | CanDelete = false 28 | }); 29 | 30 | return filterSchemes; 31 | } 32 | 33 | public override async Task SaveFiltersAsync(string path, FilterSchemes filterSchemes) 34 | { 35 | // Create clone with filters we want to serialize 36 | var finalFilterSchemes = new FilterSchemes(); 37 | finalFilterSchemes.Schemes.AddRange(from x in filterSchemes.Schemes 38 | where x.FilterGroup is null 39 | select x); 40 | 41 | await base.SaveFiltersAsync(path, finalFilterSchemes); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Example/Services/Interfaces/ITestDataService.cs: -------------------------------------------------------------------------------- 1 | namespace FilterBuilder.Example.Services; 2 | 3 | using System; 4 | using System.Collections.ObjectModel; 5 | using Models; 6 | 7 | public interface ITestDataService 8 | { 9 | ObservableCollection GetTestItems(); 10 | ObservableCollection GenerateTestItems(); 11 | TestEntity GenerateRandomEntity(); 12 | DateTime GetRandomDateTime(); 13 | string GetRandomString(); 14 | } -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Example/Services/RibbonService.cs: -------------------------------------------------------------------------------- 1 | namespace Orc.FilterBuilder.Example.Services; 2 | 3 | using System.Windows; 4 | using Orchestra.Services; 5 | using Views; 6 | 7 | public class RibbonService : IRibbonService 8 | { 9 | public FrameworkElement GetRibbon() 10 | { 11 | return new RibbonView(); 12 | } 13 | 14 | public FrameworkElement GetMainView() 15 | { 16 | return new MainView(); 17 | } 18 | 19 | public FrameworkElement GetStatusBar() 20 | { 21 | return new StatusBarView(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Example/Services/TestDataService.cs: -------------------------------------------------------------------------------- 1 | namespace FilterBuilder.Example.Services; 2 | 3 | using System; 4 | using System.Collections.ObjectModel; 5 | using System.IO; 6 | using Models; 7 | 8 | public class TestDataService : ITestDataService 9 | { 10 | private readonly Random _random = new(DateTime.Now.Millisecond); 11 | private ObservableCollection? _testItems; 12 | 13 | public ObservableCollection GetTestItems() 14 | { 15 | return _testItems ??= GenerateTestItems(); 16 | } 17 | 18 | public ObservableCollection GenerateTestItems() 19 | { 20 | var items = new ObservableCollection(); 21 | for (var i = 0; i < 10000; i++) 22 | { 23 | items.Add(GenerateRandomEntity()); 24 | } 25 | 26 | return items; 27 | } 28 | 29 | public TestEntity GenerateRandomEntity() 30 | { 31 | var testEntity = new TestEntity 32 | { 33 | FirstName = GetRandomString(), 34 | Age = _random.Next(1, 100), 35 | Id = _random.Next(10) < 1 ? null : _random.Next(10000), 36 | DateOfBirth = GetRandomDateTime(), 37 | DateOfDeath = _random.Next(10) >= 2 ? null : GetRandomDateTime(), 38 | IsActive = _random.Next(2) == 0, 39 | Duration = new TimeSpan(_random.Next(3), _random.Next(24), _random.Next(60), _random.Next(60)), 40 | Price = (decimal)(_random.NextDouble() * 1000 - 500), 41 | NullablePrice = (_random.Next(10) >= 5 ? (decimal?)(_random.NextDouble() * 1000 - 500) : null), 42 | EnumValue = (MyEnum)_random.Next(0, 3) 43 | }; 44 | 45 | var next = _random.Next(0, 4); 46 | testEntity.NullableEnumValue = next == 3 ? null : (MyEnum?)next; 47 | 48 | testEntity.Description = new Description(GetRandomString()); 49 | return testEntity; 50 | } 51 | 52 | public DateTime GetRandomDateTime() 53 | { 54 | return DateTime.Now.AddMinutes((int)(-1 * _random.NextDouble() * 30 * 365 * 24 * 60)); //years*days*hours*minuted 55 | } 56 | 57 | public string GetRandomString() 58 | { 59 | return _random.Next(10) < 1 60 | ? null 61 | : Path.GetRandomFileName().Replace(".", string.Empty); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Example/Themes/Generic.xaml: -------------------------------------------------------------------------------- 1 |  2 | 3 | -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Example/ViewModels/MainViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace Orc.FilterBuilder.Example.ViewModels; 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Collections.ObjectModel; 6 | using Catel.Collections; 7 | using Catel.Logging; 8 | using Catel.MVVM; 9 | using global::FilterBuilder.Example.Models; 10 | using global::FilterBuilder.Example.Services; 11 | 12 | public class MainViewModel : ViewModelBase 13 | { 14 | private static readonly ILog Log = LogManager.GetCurrentClassLogger(); 15 | 16 | private readonly ITestDataService _testDataService; 17 | private readonly IFilterService _filterService; 18 | 19 | public MainViewModel(ITestDataService testDataService, IFilterService filterService) 20 | { 21 | ArgumentNullException.ThrowIfNull(testDataService); 22 | ArgumentNullException.ThrowIfNull(filterService); 23 | 24 | _testDataService = testDataService; 25 | _filterService = filterService; 26 | _filterService.SelectedFilterChanged += OnFilterServiceSelectedFilterChanged; 27 | RawItems = _testDataService.GetTestItems(); 28 | FilteredItems = new FastObservableCollection(); 29 | 30 | FilteredItems.CollectionChanged += (_, _) => Log.Info("Collection updated"); 31 | } 32 | 33 | public override string Title => "Filter Builder Test"; 34 | 35 | #pragma warning disable AvoidAsyncVoid 36 | private async void OnFilterServiceSelectedFilterChanged(object sender, EventArgs e) 37 | #pragma warning restore AvoidAsyncVoid 38 | { 39 | using (FilteredItems.SuspendChangeNotifications()) 40 | { 41 | var filter = _filterService.SelectedFilter; 42 | var items = RawItems; 43 | var result = await _filterService.FilterCollectionAsync(filter, items); 44 | FilteredItems.ReplaceRange(result); 45 | } 46 | } 47 | 48 | public ObservableCollection RawItems { get; } 49 | public FastObservableCollection FilteredItems { get; } 50 | } 51 | -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Example/ViewModels/StatusBarViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace Orc.FilterBuilder.Example.ViewModels; 2 | 3 | using Catel.MVVM; 4 | 5 | public class StatusBarViewModel : ViewModelBase 6 | { 7 | } -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Example/Views/MainView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Orc.FilterBuilder.Example.Views; 2 | 3 | public partial class MainView 4 | { 5 | public MainView() => InitializeComponent(); 6 | } 7 | -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Example/Views/RibbonView.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 12 | 13 | 14 | 19 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Example/Views/RibbonView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Orc.FilterBuilder.Example.Views; 2 | 3 | public partial class RibbonView 4 | { 5 | public RibbonView() => InitializeComponent(); 6 | } 7 | -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Example/Views/StatusBarView.xaml: -------------------------------------------------------------------------------- 1 |  5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Example/Views/StatusBarView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Orc.FilterBuilder.Example.Views; 2 | 3 | public partial class StatusBarView 4 | { 5 | public StatusBarView() => InitializeComponent(); 6 | } 7 | -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Tests/Converters/ObjectToValueConverterFacts.cs: -------------------------------------------------------------------------------- 1 | namespace Orc.FilterBuilder.Tests.Converters; 2 | 3 | using Catel.Data; 4 | using NUnit.Framework; 5 | using Orc.FilterBuilder.Converters; 6 | 7 | [TestFixture] 8 | public class ObjectToValueConverterFacts 9 | { 10 | private class TestModel : ModelBase 11 | { 12 | public string Reference { get => "test"; } 13 | 14 | public int MyIntegerValue { get; set; } 15 | } 16 | 17 | [TestCase] 18 | public void ConvertsGetterPropertiesFromCatelModelBase() 19 | { 20 | var model = new TestModel 21 | { 22 | MyIntegerValue = 42 23 | }; 24 | 25 | var converter = new ObjectToValueConverter(null); 26 | 27 | Assert.That(converter.Convert(model, null, nameof(TestModel.MyIntegerValue), null), Is.EqualTo(42)); 28 | Assert.That(converter.Convert(model, null, nameof(TestModel.Reference), null), Is.EqualTo("test")); 29 | } 30 | } -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Tests/FilterSchemeFacts.cs: -------------------------------------------------------------------------------- 1 | namespace Orc.FilterBuilder.Tests.Models; 2 | 3 | using NUnit.Framework; 4 | 5 | public class FilterSchemeFacts 6 | { 7 | [TestFixture] 8 | public class TheToStringMethod 9 | { 10 | [TestCase] 11 | public void WorksCorrectlyOnEmptyFilterScheme() 12 | { 13 | var filterScheme = new FilterScheme 14 | { 15 | Title = "Default" 16 | }; 17 | 18 | var actual = filterScheme.ToString(); 19 | var expected = @"Default"; 20 | 21 | Assert.That(actual, Is.EqualTo(expected)); 22 | } 23 | 24 | [TestCase] 25 | public void WorksCorrectlyOnLargeFilterScheme() 26 | { 27 | var filterScheme = FilterSchemeHelper.GenerateFilterScheme(); 28 | 29 | var actual = filterScheme.ToString(); 30 | var expected = @"Test filter 31 | (StringProperty contains '123' and BoolProperty is equal to 'True' and IntProperty is greater than or equal to '42') and (StringProperty contains '123' and BoolProperty is equal to 'True' and IntProperty is greater than or equal to '42')"; 32 | 33 | Assert.That(actual, Is.EqualTo(expected)); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Tests/FodyWeavers.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Orc.FilterBuilder 7 | Orc.FilterBuilder.Xaml 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Tests/Helpers/AssemblyDirectoryHelper.cs: -------------------------------------------------------------------------------- 1 | namespace Orc.FilterBuilder.Tests; 2 | 3 | using System; 4 | 5 | internal static class AssemblyDirectoryHelper 6 | { 7 | public static string GetCurrentDirectory() 8 | { 9 | var directory = AppDomain.CurrentDomain.BaseDirectory; 10 | return directory; 11 | } 12 | } -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Tests/Models/TestFilterModel.cs: -------------------------------------------------------------------------------- 1 | namespace Orc.FilterBuilder.Tests.Models; 2 | 3 | using Catel.Data; 4 | 5 | public class TestFilterModel : ModelBase 6 | { 7 | public string StringProperty { get; set; } 8 | 9 | public bool BoolProperty { get; set; } 10 | 11 | public int IntProperty { get; set; } 12 | } -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Tests/ModuleInitializer.cs: -------------------------------------------------------------------------------- 1 | using Catel.IoC; 2 | 3 | /// 4 | /// Used by the ModuleInit. All code inside the Initialize method is ran as soon as the assembly is loaded. 5 | /// 6 | public static class ModuleInitializer 7 | { 8 | /// 9 | /// Initializes the module. 10 | /// 11 | public static void Initialize() 12 | { 13 | var serviceLocator = ServiceLocator.Default; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // All other assembly info is defined in SharedAssembly.cs 2 | 3 | using System.Reflection; 4 | using System.Runtime.InteropServices; 5 | 6 | [assembly: AssemblyTitle("Orc.FilterBuilder.Tests")] 7 | [assembly: AssemblyProduct("Orc.FilterBuilder.Tests")] 8 | [assembly: AssemblyDescription("Orc.FilterBuilder.Tests library")] 9 | 10 | // Setting ComVisible to false makes the types in this assembly not visible 11 | // to COM components. If you need to access a type in this assembly from 12 | // COM, set the ComVisible attribute to true on that type. 13 | 14 | #if !PCL 15 | [assembly: ComVisible(false)] 16 | #endif 17 | -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Tests/PublicApiFacts.cs: -------------------------------------------------------------------------------- 1 | namespace Orc.FilterBuilder.Tests; 2 | 3 | using System.Reflection; 4 | using System.Runtime.CompilerServices; 5 | using System.Threading.Tasks; 6 | using NUnit.Framework; 7 | using PublicApiGenerator; 8 | using VerifyNUnit; 9 | using Views; 10 | 11 | [TestFixture] 12 | public class PublicApiFacts 13 | { 14 | [Test, MethodImpl(MethodImplOptions.NoInlining)] 15 | public async Task Orc_FilterBuilder_HasNoBreakingChanges_Async() 16 | { 17 | var assembly = typeof(FilterScheme).Assembly; 18 | 19 | await PublicApiApprover.ApprovePublicApiAsync(assembly); 20 | } 21 | 22 | [Test, MethodImpl(MethodImplOptions.NoInlining)] 23 | public async Task Orc_FilterBuilder_Xaml_HasNoBreakingChanges_Async() 24 | { 25 | var assembly = typeof(EditFilterView).Assembly; 26 | 27 | await PublicApiApprover.ApprovePublicApiAsync(assembly); 28 | } 29 | 30 | internal static class PublicApiApprover 31 | { 32 | public static async Task ApprovePublicApiAsync(Assembly assembly) 33 | { 34 | var publicApi = ApiGenerator.GeneratePublicApi(assembly, new ApiGeneratorOptions()); 35 | await Verifier.Verify(publicApi); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Tests/Resources/Files/filters.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Orc.FilterBuilder.Tests.TestFilterRuntimeModel 6 | Test 7 | 8 | False 9 | 10 | 11 | And 12 | 13 | 14 | Orc.FilterBuilder.Tests.TestFilterRuntimeModel||StringAttribute 15 | 16 | on 17 | StartsWith 18 | true 19 | Text 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Tests/RuntimeMetadataFacts/AttributeTypeNames.cs: -------------------------------------------------------------------------------- 1 | namespace Orc.FilterBuilder.Tests; 2 | 3 | public static class AttributeTypeNames 4 | { 5 | public const string StringAttribute = "StringAttribute"; 6 | public const string IntAttribute = "IntAttribute"; 7 | public const string DateTimeAttribute = "DateTimeAttribute"; 8 | public const string BoolAttribute = "BoolAttribute"; 9 | } 10 | -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Tests/RuntimeMetadataFacts/Helpers/FilterSchemeInitializationHelper.cs: -------------------------------------------------------------------------------- 1 | namespace Orc.FilterBuilder.Tests; 2 | 3 | using System.IO; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Catel.IoC; 7 | using Services; 8 | 9 | public static class FilterSchemeInitializationHelper 10 | { 11 | public static async Task GetTestFilterSchemeAsync() 12 | { 13 | var serviceLocator = ServiceLocator.Default; 14 | 15 | #pragma warning disable IDISP001 // Dispose created 16 | var typeFactory = serviceLocator.ResolveType(); 17 | #pragma warning restore IDISP001 // Dispose created 18 | var reflectionService = typeFactory.CreateInstanceWithParametersAndAutoCompletion(TestAttributeTypeProvider.AttributeTypes.Values.ToList()); 19 | serviceLocator.RegisterInstance(reflectionService); 20 | 21 | using var tempFileContext = new TemporaryFilesContext("filters"); 22 | var tempFile = tempFileContext.GetFile($"testFilters.xml", true); 23 | var sourceFile = Path.Combine(AssemblyDirectoryHelper.GetCurrentDirectory(), $"Resources\\Files\\filters.xml"); 24 | File.Copy(sourceFile, tempFile, true); 25 | 26 | var filterManager = serviceLocator.ResolveType(); 27 | await filterManager.LoadAsync(tempFile); 28 | 29 | return filterManager.FilterSchemes.Schemes.FirstOrDefault(x => x.Title == "Test"); 30 | } 31 | } -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Tests/RuntimeMetadataFacts/Metadata/TestFilterRuntimeModelMetadata.cs: -------------------------------------------------------------------------------- 1 | namespace Orc.FilterBuilder.Tests; 2 | 3 | using System; 4 | 5 | public class TestFilterRuntimeModelMetadata : IPropertyMetadata 6 | { 7 | private readonly TestAttributeType _attributeType; 8 | 9 | public TestFilterRuntimeModelMetadata(TestAttributeType attributeType) 10 | { 11 | _attributeType = attributeType; 12 | 13 | OwnerType = typeof (TestFilterRuntimeModel); 14 | Type = attributeType.Type; 15 | DisplayName = _attributeType.Name; 16 | } 17 | 18 | public string DisplayName { get; set; } 19 | public string Name => _attributeType.Name; 20 | public Type OwnerType { get; } 21 | public Type Type { get; } 22 | 23 | public object GetValue(object instance) 24 | { 25 | var testData = instance as TestFilterRuntimeModel; 26 | 27 | return GetAttributeValue(testData, _attributeType); 28 | } 29 | 30 | public TValue GetValue(object instance) 31 | { 32 | return (TValue) GetValue(instance); 33 | } 34 | 35 | public void SetValue(object instance, object value) 36 | { 37 | throw new NotImplementedException(); 38 | } 39 | 40 | private object GetAttributeValue(TestFilterRuntimeModel operation, TestAttributeType attributeType) 41 | { 42 | var attributeName = attributeType?.Name; 43 | 44 | return operation.Attributes.TryGetValue(attributeName, out var value) 45 | ? value.Value 46 | : null; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Tests/RuntimeMetadataFacts/Metadata/TestFilterRuntimeModelPropertyCollection.cs: -------------------------------------------------------------------------------- 1 | namespace Orc.FilterBuilder.Tests; 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | public class TestFilterRuntimeModelPropertyCollection : IPropertyCollection 8 | { 9 | public TestFilterRuntimeModelPropertyCollection(IList attributeTypes) 10 | { 11 | ArgumentNullException.ThrowIfNull(attributeTypes); 12 | 13 | Properties = attributeTypes.Select(x => new TestFilterRuntimeModelMetadata(x)) 14 | .Cast() 15 | .ToList(); 16 | } 17 | 18 | public List Properties { get; } 19 | 20 | public IPropertyMetadata GetProperty(string propertyName) 21 | { 22 | return Properties.FirstOrDefault(x => x.Name == propertyName); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Tests/RuntimeMetadataFacts/Models/TestAttributeType.cs: -------------------------------------------------------------------------------- 1 | namespace Orc.FilterBuilder.Tests; 2 | 3 | using System; 4 | 5 | public class TestAttributeType 6 | { 7 | public TestAttributeType(string name, Type type) 8 | { 9 | Name = name; 10 | Type = type; 11 | } 12 | 13 | public string Name { get; } 14 | public Type Type { get; } 15 | } 16 | -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Tests/RuntimeMetadataFacts/Models/TestAttributeValue.cs: -------------------------------------------------------------------------------- 1 | namespace Orc.FilterBuilder.Tests; 2 | 3 | public class TestAttributeValue 4 | { 5 | public TestAttributeValue(object value, TestAttributeType attributeType) 6 | { 7 | Value = value; 8 | AttributeType = attributeType; 9 | } 10 | 11 | public object Value { get; set; } 12 | public TestAttributeType AttributeType { get; set; } 13 | 14 | public override string ToString() 15 | { 16 | return $"{AttributeType.Name}: {Value}"; 17 | } 18 | 19 | public override bool Equals(object obj) 20 | { 21 | if (ReferenceEquals(null, obj)) 22 | { 23 | return false; 24 | } 25 | 26 | if (ReferenceEquals(this, obj)) 27 | { 28 | return true; 29 | } 30 | 31 | if (obj.GetType() != GetType()) 32 | { 33 | return false; 34 | } 35 | 36 | return Equals((TestAttributeValue) obj); 37 | } 38 | 39 | public bool Equals(TestAttributeValue other) 40 | { 41 | if (ReferenceEquals(null, other)) 42 | { 43 | return false; 44 | } 45 | 46 | if (ReferenceEquals(this, other)) 47 | { 48 | return true; 49 | } 50 | 51 | return Equals(AttributeType, other.AttributeType) && Equals(Value, other.Value); 52 | } 53 | 54 | public override int GetHashCode() 55 | { 56 | unchecked 57 | { 58 | return ((AttributeType?.GetHashCode() ?? 0)*397) ^ (Value?.GetHashCode() ?? 0); 59 | } 60 | } 61 | 62 | public static bool operator ==(TestAttributeValue left, TestAttributeValue right) 63 | { 64 | return Equals(left, right); 65 | } 66 | 67 | public static bool operator !=(TestAttributeValue left, TestAttributeValue right) 68 | { 69 | return !Equals(left, right); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Tests/RuntimeMetadataFacts/Models/TestFilterRuntimeModel.cs: -------------------------------------------------------------------------------- 1 | namespace Orc.FilterBuilder.Tests; 2 | 3 | using System.Collections.Generic; 4 | 5 | public class TestFilterRuntimeModel 6 | { 7 | public Dictionary Attributes { get; set; } 8 | } -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Tests/RuntimeMetadataFacts/Provider/TestAttributeTypeProvider.cs: -------------------------------------------------------------------------------- 1 | namespace Orc.FilterBuilder.Tests; 2 | 3 | using System.Collections.Generic; 4 | 5 | public static class TestAttributeTypeProvider 6 | { 7 | public static readonly Dictionary AttributeTypes; 8 | 9 | static TestAttributeTypeProvider() 10 | { 11 | AttributeTypes = new Dictionary() 12 | { 13 | {"StringAttribute", new TestAttributeType("StringAttribute", typeof (string))}, 14 | {"IntAttribute", new TestAttributeType("IntAttribute", typeof (string))}, 15 | {"DateTimeAttribute", new TestAttributeType("DateTimeAttribute", typeof (string))}, 16 | {"BoolAttribute", new TestAttributeType("BoolAttribute", typeof (string))}, 17 | }; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Tests/RuntimeMetadataFacts/Provider/TestDataProvider.cs: -------------------------------------------------------------------------------- 1 | namespace Orc.FilterBuilder.Tests; 2 | 3 | using System.Collections.Generic; 4 | 5 | public static class TestDataProvider 6 | { 7 | public static List GetInitialCollection() 8 | { 9 | var attributeTypes = TestAttributeTypeProvider.AttributeTypes; 10 | 11 | return new List 12 | { 13 | new TestFilterRuntimeModel 14 | { 15 | Attributes = new Dictionary 16 | { 17 | {AttributeTypeNames.StringAttribute,new TestAttributeValue("one", attributeTypes[AttributeTypeNames.StringAttribute])}, 18 | {AttributeTypeNames.IntAttribute, new TestAttributeValue(1, attributeTypes[AttributeTypeNames.IntAttribute])} 19 | } 20 | }, 21 | 22 | new TestFilterRuntimeModel 23 | { 24 | Attributes = new Dictionary 25 | { 26 | {AttributeTypeNames.StringAttribute,new TestAttributeValue("no value", attributeTypes[AttributeTypeNames.StringAttribute])}, 27 | {AttributeTypeNames.IntAttribute, new TestAttributeValue(0, attributeTypes[AttributeTypeNames.IntAttribute])} 28 | } 29 | }, 30 | 31 | new TestFilterRuntimeModel 32 | { 33 | Attributes = new Dictionary 34 | { 35 | {AttributeTypeNames.StringAttribute,new TestAttributeValue("two", attributeTypes[AttributeTypeNames.StringAttribute])}, 36 | {AttributeTypeNames.IntAttribute, new TestAttributeValue(2, attributeTypes[AttributeTypeNames.IntAttribute])} 37 | } 38 | } 39 | }; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Tests/RuntimeMetadataFacts/RuntimeMetadataFacts.cs: -------------------------------------------------------------------------------- 1 | namespace Orc.FilterBuilder.Tests; 2 | 3 | using System.Collections.Generic; 4 | using System.Threading.Tasks; 5 | using Catel.IoC; 6 | using NUnit.Framework; 7 | 8 | [TestFixture] 9 | public class RuntimeMetadataFacts 10 | { 11 | [Test] 12 | public async Task CorrectlyFilterEntitiesWithRuntimeMetadataAsync() 13 | { 14 | var serviceLocator = ServiceLocator.Default; 15 | 16 | #pragma warning disable IDISP001 // Dispose created 17 | var typeFactory = serviceLocator.ResolveType(); 18 | #pragma warning restore IDISP001 // Dispose created 19 | 20 | var filterScheme = await FilterSchemeInitializationHelper.GetTestFilterSchemeAsync(); 21 | var initialCollection = TestDataProvider.GetInitialCollection(); 22 | var resultList = new List(); 23 | 24 | var filterService = typeFactory.CreateInstance(); 25 | await filterService.FilterCollectionAsync(filterScheme, initialCollection, resultList); 26 | 27 | Assert.That(resultList.Count, Is.EqualTo(1)); 28 | Assert.That(resultList[0].Attributes[AttributeTypeNames.StringAttribute].Value, Is.EqualTo("one")); 29 | } 30 | } -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Tests/RuntimeMetadataFacts/Services/TestFilterRuntimeModelReflectionService.cs: -------------------------------------------------------------------------------- 1 | namespace Orc.FilterBuilder.Tests.Services; 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Threading.Tasks; 6 | 7 | public class TestFilterRuntimeModelReflectionService : IReflectionService 8 | { 9 | private readonly IList _attributeTypes; 10 | 11 | private TestFilterRuntimeModelPropertyCollection _propertyCollection; 12 | 13 | public TestFilterRuntimeModelReflectionService(IList attributeTypes) 14 | { 15 | ArgumentNullException.ThrowIfNull(attributeTypes); 16 | 17 | _attributeTypes = attributeTypes; 18 | } 19 | 20 | public IPropertyCollection GetInstanceProperties(Type targetType) 21 | { 22 | return _propertyCollection ??= new TestFilterRuntimeModelPropertyCollection(_attributeTypes); 23 | } 24 | 25 | public Task GetInstancePropertiesAsync(Type targetType) 26 | { 27 | return Task.FromResult(GetInstanceProperties(targetType)); 28 | } 29 | 30 | public void ClearCache() 31 | { 32 | _propertyCollection = null; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Tests/TemporaryFilesContext.cs: -------------------------------------------------------------------------------- 1 | namespace Orc.FilterBuilder.Tests; 2 | 3 | using System; 4 | using System.IO; 5 | using Catel.Logging; 6 | 7 | public sealed class TemporaryFilesContext : IDisposable 8 | { 9 | private static readonly ILog Log = LogManager.GetCurrentClassLogger(); 10 | 11 | private readonly Guid _randomGuid = Guid.NewGuid(); 12 | private readonly string _rootDirectory; 13 | 14 | public TemporaryFilesContext(string name = null) 15 | { 16 | if (string.IsNullOrWhiteSpace(name)) 17 | { 18 | name = _randomGuid.ToString(); 19 | } 20 | 21 | _rootDirectory = Path.Combine(Path.GetTempPath(), "Orc.FilterBuilder.Tests", name); 22 | 23 | Directory.CreateDirectory(_rootDirectory); 24 | } 25 | 26 | /// 27 | /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. 28 | /// 29 | public void Dispose() 30 | { 31 | Log.Info("Deleting temporary files from '{0}'", _rootDirectory); 32 | 33 | try 34 | { 35 | if (Directory.Exists(_rootDirectory)) 36 | { 37 | Directory.Delete(_rootDirectory, true); 38 | } 39 | } 40 | catch (Exception ex) 41 | { 42 | Log.Error(ex, "Failed to delete temporary files"); 43 | } 44 | } 45 | 46 | public string GetDirectory(string relativeDirectoryName) 47 | { 48 | var fullPath = Path.Combine(_rootDirectory, relativeDirectoryName); 49 | 50 | if (!Directory.Exists(fullPath)) 51 | { 52 | Directory.CreateDirectory(fullPath); 53 | } 54 | 55 | return fullPath; 56 | } 57 | 58 | public string GetFile(string relativeFilePath, bool deleteIfExists = false) 59 | { 60 | var fullPath = Path.Combine(_rootDirectory, relativeFilePath); 61 | 62 | var directory = Path.GetDirectoryName(fullPath); 63 | if (!Directory.Exists(directory)) 64 | { 65 | Directory.CreateDirectory(directory); 66 | } 67 | 68 | if (deleteIfExists) 69 | { 70 | if (File.Exists(fullPath)) 71 | { 72 | File.Delete(fullPath); 73 | } 74 | } 75 | 76 | return fullPath; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Tests/UI/AutomationMethods/InitViewModelMethodRun.cs: -------------------------------------------------------------------------------- 1 | namespace Orc.FilterBuilder.Tests; 2 | 3 | using System.Windows; 4 | using Catel.IoC; 5 | using Orc.Automation; 6 | using ViewModels; 7 | using Views; 8 | 9 | public class InitViewModelMethodRun : NamedAutomationMethodRun 10 | { 11 | public override bool TryInvoke(FrameworkElement owner, AutomationMethod method, out AutomationValue result) 12 | { 13 | result = AutomationValue.FromValue(true); 14 | 15 | if (owner is not FilterBuilderControl control) 16 | { 17 | return true; 18 | } 19 | 20 | foreach (var scope in FilterBuilderControlTestData.AvailableScopes) 21 | { 22 | RegisterScope(scope); 23 | } 24 | 25 | #pragma warning disable IDISP004 // Don't ignore created IDisposable 26 | var vm = this.GetTypeFactory().CreateInstanceWithParametersAndAutoCompletion(); 27 | #pragma warning restore IDISP004 // Don't ignore created IDisposable 28 | 29 | control.DataContext = vm; 30 | 31 | return true; 32 | } 33 | 34 | private void RegisterScope(object scope) 35 | { 36 | #pragma warning disable IDISP001 // Dispose created 37 | var serviceLocator = this.GetServiceLocator(); 38 | var typeFactory = this.GetTypeFactory(); 39 | #pragma warning restore IDISP001 // Dispose created 40 | var filterManager = new TestFilterSchemeManager 41 | { 42 | Scope = scope 43 | }; 44 | 45 | var reflectionService = typeFactory.CreateInstanceWithParametersAndAutoCompletion(); 46 | var filterService = typeFactory.CreateInstanceWithParametersAndAutoCompletion(); 47 | 48 | serviceLocator.RegisterInstance(typeof(IReflectionService), reflectionService, scope); 49 | serviceLocator.RegisterInstance(typeof(IFilterService), filterService, scope); 50 | serviceLocator.RegisterInstance(typeof(IFilterSchemeManager), filterManager, scope); 51 | } 52 | } -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Tests/UI/Fluent/SplitButton/Models/SplitButtonMap.cs: -------------------------------------------------------------------------------- 1 | namespace Orc.FilterBuilder.Tests; 2 | 3 | using Orc.Automation; 4 | 5 | [ActiveAutomationModel] 6 | public class SplitButtonModel: AutomationControlModel 7 | { 8 | public SplitButtonModel(AutomationElementAccessor accessor) 9 | : base(accessor) 10 | { 11 | } 12 | } -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Tests/UI/Fluent/SplitButton/SplitButton.cs: -------------------------------------------------------------------------------- 1 | namespace Orc.FilterBuilder.Tests; 2 | 3 | using System.Windows.Automation; 4 | using Orc.Automation; 5 | 6 | public class SplitButton : AutomationControl 7 | { 8 | public SplitButton(AutomationElement element) 9 | : base(element) 10 | { 11 | } 12 | } -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Tests/UI/Mocks/TestFilterSchemeManager.cs: -------------------------------------------------------------------------------- 1 | namespace Orc.FilterBuilder.Tests; 2 | 3 | using System; 4 | using System.Threading.Tasks; 5 | using Catel.Caching; 6 | 7 | public class TestFilterSchemeManager : IFilterSchemeManager 8 | { 9 | private readonly CacheStorage _filterSchemes = new(); 10 | 11 | public TestFilterSchemeManager() 12 | { 13 | var task = Task.Run(async () => await UpdateFiltersAsync()); 14 | Task.WaitAll(task); 15 | } 16 | 17 | public bool AutoSave { get; set; } 18 | 19 | public FilterSchemes FilterSchemes => _filterSchemes.GetFromCacheOrFetch(Scope, () => FilterBuilderControlTestData.GetSchemes(Scope)); 20 | 21 | public object? Scope { get; set; } 22 | 23 | public async Task UpdateFiltersAsync() 24 | { 25 | Updated?.Invoke(this, EventArgs.Empty); 26 | } 27 | 28 | public async Task LoadAsync(string? fileName = null) 29 | { 30 | Loaded?.Invoke(this, EventArgs.Empty); 31 | 32 | return true; 33 | } 34 | 35 | public async Task SaveAsync(string? fileName = null) 36 | { 37 | Saved?.Invoke(this, EventArgs.Empty); 38 | } 39 | 40 | public event EventHandler Updated; 41 | public event EventHandler Loaded; 42 | public event EventHandler Saved; 43 | } -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Tests/UI/TestData/FilterBuilderControlTestData.cs: -------------------------------------------------------------------------------- 1 | namespace Orc.FilterBuilder.Tests; 2 | 3 | using System.Collections.Generic; 4 | 5 | public static class FilterBuilderControlTestData 6 | { 7 | public static List AvailableScopes = new() 8 | { 9 | TestScopeWith0CustomRecords, 10 | TestScopeWith3CustomRecords, 11 | TestScopeWith5CustomRecords 12 | }; 13 | 14 | public const string TestScopeWith0CustomRecords = nameof(TestScopeWith0CustomRecords); 15 | public const string TestScopeWith3CustomRecords = nameof(TestScopeWith3CustomRecords); 16 | public const string TestScopeWith5CustomRecords = nameof(TestScopeWith5CustomRecords); 17 | 18 | public static FilterSchemes GetSchemes(object scope) 19 | { 20 | if (Equals(scope, TestScopeWith3CustomRecords)) 21 | { 22 | var filterSchemes = new FilterSchemes { Scope = scope }; 23 | 24 | var schemes = filterSchemes.Schemes; 25 | 26 | schemes.Add(new FilterScheme(typeof(TestEntity)) { Title = "First" }); 27 | schemes.Add(new FilterScheme(typeof(TestEntity)) { Title = "Second" }); 28 | schemes.Add(new FilterScheme(typeof(TestEntity)) { Title = "Third" }); 29 | 30 | return filterSchemes; 31 | } 32 | 33 | if (Equals(scope, TestScopeWith5CustomRecords)) 34 | { 35 | var filterSchemes = new FilterSchemes { Scope = scope }; 36 | 37 | var schemes = filterSchemes.Schemes; 38 | 39 | schemes.Add(new FilterScheme(typeof(TestEntity)) { Title = "One" }); 40 | schemes.Add(new FilterScheme(typeof(TestEntity)) { Title = "Two" }); 41 | schemes.Add(new FilterScheme(typeof(TestEntity)) { Title = "Three" }); 42 | schemes.Add(new FilterScheme(typeof(TestEntity)) { Title = "Four" }); 43 | schemes.Add(new FilterScheme(typeof(TestEntity)) { Title = "Five" }); 44 | 45 | return filterSchemes; 46 | } 47 | 48 | return new FilterSchemes(); 49 | } 50 | } -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Xaml/Automation/Controls/EditFilterConditionTree/EditFilterConditionTree.cs: -------------------------------------------------------------------------------- 1 | namespace Orc.FilterBuilder.Automation; 2 | 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Windows.Automation; 7 | using Orc.Automation; 8 | using Orc.Automation.Controls; 9 | 10 | [Control(ControlTypeName = nameof(ControlType.Tree))] 11 | public class EditFilterConditionTree : FrameworkElement, IEnumerable 12 | { 13 | protected readonly Tree _tree; 14 | 15 | public EditFilterConditionTree(AutomationElement element) 16 | : base(element) 17 | { 18 | _tree = element.As(); 19 | } 20 | 21 | public IReadOnlyList Children 22 | => _tree.ChildItems.Select(EditFilterConditionTreeItemFactory.Create) 23 | .ToList(); 24 | 25 | public IEnumerator GetEnumerator() 26 | { 27 | return Children.GetEnumerator(); 28 | } 29 | 30 | IEnumerator IEnumerable.GetEnumerator() 31 | { 32 | return GetEnumerator(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Xaml/Automation/Controls/EditFilterConditionTree/Factories/EditFilterConditionTreeItemFactory.cs: -------------------------------------------------------------------------------- 1 | namespace Orc.FilterBuilder.Automation; 2 | 3 | using Orc.Automation; 4 | using Orc.Automation.Controls; 5 | 6 | public static class EditFilterConditionTreeItemFactory 7 | { 8 | public static EditFilterConditionTreeItemBase Create(TreeItem item) 9 | { 10 | //TODO:Vladimir: Take a look 11 | var isGroupItem = item.Find("PART_AddExpressionButton", numberOfWaits: 1) is not null; 12 | if (isGroupItem) 13 | { 14 | return new EditFilterConditionGroupTreeItem(item.Element); 15 | } 16 | 17 | return new EditFilterPropertyConditionTreeItem(item.Element); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Orc.FilterBuilder.Xaml/Automation/Controls/EditFilterConditionTree/Maps/EditFilterConditionGroupTreeItemMap.cs: -------------------------------------------------------------------------------- 1 | namespace Orc.FilterBuilder.Automation; 2 | 3 | using System.Windows.Automation; 4 | using Orc.Automation; 5 | using Orc.Automation.Controls; 6 | 7 | public class EditFilterConditionGroupTreeItemMap : AutomationBase 8 | { 9 | public EditFilterConditionGroupTreeItemMap(AutomationElement element) 10 | : base(element) 11 | { 12 | } 13 | 14 | public ComboBox? GroupTypeComboBox => By.Id("PART_GroupTypeComboBox").One(); 15 | public Button? AddExpressionButton => By.Id("PART_AddExpressionButton").One